I have 3 tables in my SQL Server database Role, Permission and RolePermission.
RolePermission consists of two columns qRole and qPermission which are the foreign keys for the other two tables.
Therefore when Entity Framework creates the model for it, it just create two classes and add virtual property for RolePermission into each role and permission classes.
Now I need to select columns from RolePermission so what I did I wrote this piece of code:
var rolePermission = PREntitiy.Roles.Where(r => r.qRole == TxtRole.Text)
.Select(p => p.Permissions);
Doing this I can access rolePermission table however I need to retrieve some column from role table and some column from rolePermission in a single query like what we do in a join statement in SQL.
In other words, I need a linq query to access some column from role table and some from rolePermission but I need to do it in just one linq query like a join statement in SQL.
Thanks
You are looking for the .Include() statement
http://msdn.microsoft.com/en-us/data/jj574232.aspx
var role = PREntitiy.Roles.Include(r=>r.Permission).Where(r => r.qRole == TxtRole.Text)
I don't have all your classes, so that Permission property may be incorrect.
You would access the properties from each class using dot notation like normal:
var x = role.name;
var y = role.Permission.Name;
etc.
#BlackICE helped me a lot with his suggestion. This isn't exactly the same but I had a similar problem. I have three tables, Users (Username, Password), Roles (RoleId, RoleName), and UserRoles (Username, RoleId). The last was made up of keys from the other two. To get the role, given the username I had to do the following. I don't know if this is proper/improper but it worked for me :).
IQueryable<User> IQUsers = _dbContext.Users.Include(u => u.Roles).Where(u => u.Username == username);
User _user = IQUsers.FirstOrDefault<User>();
Role _role = _user.Roles.FirstOrDefault<Role>();
roleName = _role.RoleName;
Related
I have an entity framework setup which has been generated using the database first approach. In it I have a User table and a profile table.
User
- UserId
- ProfileId
Profile
- ProfileId
- {unimportant profile details}
- ModifiedOn
- CreatedOn
In each of these tables the Ids are their primary keys. The issue is that there are 3 Foreign Key relationships between the two tables.
A User Has A Profile (User.FK_User_Profile User.ProfileId == Profile.ProfileId)
A Profile was Created by a User (Profile.FK_UserCreatedBy Profile.CreatedBy == User.UserId)
A Profile was Modified by a User (Profile.FK_UserModifiedBy Profile.ModifiedBy == User.UserId)
This all works fine in the database. Unfortunately, when I try to access the edmx generated from this with the following Linq query:
databaseContext.User.Where(u => u.UserID == SOMEGUID)
.Select(p => p.Profile.FirstOrDefault())
the generated sql is this:
SELECT projected details
FROM ( SELECT
[Extent1].UserId as UserId,
[Extent2].ProfileId as ProfileId,
[Other fields],
FROM [dbo].[User] AS [Extent1]
LEFT OUTER JOIN [dbo].[Profile] AS [Extent2] ON *[Extent1].[UserID] = [Extent2].[ModifiedBy]*
WHERE [Extent1].[ProfileID] = efGeneratedId
) AS [Project1]
The problem is that Left Outer Join criteria. Instead of joining on
Extent1.UserId = Extent2.UserId
it's joining on
Extent1.UserId = Extent2.ModifiedBy
This results in the Linq retrieving all users which modified the profile, rather than the profile that the user has.
How do I instruct EF to map this query, or more likely these relationships, correctly?
As you didn't include any info about edmx generated, I will try to guess..:
The model for those tables should produce something like this on User class:
int ProfileId {get; set;}
Profile Profile {get; set;} //->An user has A profile
ICollection<Profile> ProfileX {get; set;} //CreatedBy
ICollection<Profile> ProfileY {get; set;} //ModifiedBy
According to the Sql you posted, the "Profile.FirstOrDefault" of your linq is the "ProfileY" collection of my example.
You should adjust edmx properties naming and use the one representing the User has A profile relation, which shouldn't be a collection
I'm developing a WCF RESTful web service with Entity Framework Code First.
I have a table Users with a lot of columns. I do this to get an specific user:
context.Configuration.ProxyCreationEnabled = false;
var users = from u in context.Users
where u.UserId == userId
select u;
On this table, there is a password column, and I don't want return this column.
How can I exclude password column from that select?
Its sad to say but NO
You do not have option to directly exclude any particular column. You may go with lazy loading of columns.
The easiest and non-liking method would be to include columns which you want.
Specify each column that you do want in your select statement:
var users = from u in context.Users
where u.UserId == userId
select u.UserId, u.Watever, etc... ;
another way like this,
var users = from u in context.Users
where u.UserId == userId
select new
{
col1 = u.UserId,
col2 = u.Watever
}.ToList();
You can create more than one LINQ object per table. I'd create one with the field you need and one without. It makes CRUD operations more difficult though.
Yes, you can run LINQ with certain columns excluded:
Store list of all columns in an array of string. E.g.
var arrayOfColNames = dbContext.Model.FindEntityType(typeof(TableName))
.GetProperties().Select(x => x.Relational().ColumnName).ToArray() )
Remove the unwanted columns from the above array of string. E.g.
arrayOfColNames = arrayOfColNames .Where(w => !w.Equals("password")).ToArray();
Run your LINQ select using the above filtered array of strings : https://stackoverflow.com/a/45205267/19386398
I have a table called Students and a table called Majors, Students and Majors are joined by MajorId I have set this relationship already and have set the foreign key in the schema. When I access my Student object how can I return the MajorName column (this comes from the Majors table)? The only options I have in intellisense is Major_1, Major_1Reference, MajorId .
Major_1 should be a navigation property leading to the appropriate Major entry, so you should be able to access the Major's properties like this:
from s in ctx.Students
select s.Major_1.MajorName
You can use linq join statement like this to make query on the two tables...
var q = from s in Students
join m in Majors on s.MajorId equals m.MajorId
select new { m.MajorName };
I have three tables
Employee (ID numeric, Name varchar)
Login (ID numeric, UserName varchar, Password varchar)
EmployeeLogin (ID numeric, EmployeeID, LoginID)
Relation is one employee can have multiple login. How will I get all the Login Name of a particular Employee.
I am able to fetch single record using the code given below but how will I get multiple records
using (var context = new AllEntities())
{
var query = from c in context.Employees
where c.ID == 9
select c;
}
The EmployeeLogin table seems redundant if you only have a one-to-many relationship between Employee and Login. You could just place a column EmployeeId in the Login table. The setup you have right now supports many-to-many between Employee and Login.
If you change your model according to my suggestion you could then get all Logins for a EmployeeId like this:
var query = from c in context.Logins
where c.EmployeeID == 9
select c;
If you keep your current model you could get all logins for an employee id like this:
var query = from l in context.Logins
join el in context.EmployeeLogins
on l.LoginId equals el.LoginId
where el.EmployeeID == 9
select l;
You should have all of the Logins in a navigation property on the Employee entity. See this tutorial:
http://www.asp.net/web-forms/tutorials/getting-started-with-ef/the-entity-framework-and-aspnet-getting-started-part-1
You can let the Entity Framework get the related data automatically or you can do it manually; for descriptions of lazy vs. eager loading see these tutorials:
http://www.asp.net/web-forms/tutorials/getting-started-with-ef/the-entity-framework-and-aspnet-getting-started-part-2
http://www.asp.net/mvc/tutorials/getting-started-with-ef-using-mvc/reading-related-data-with-the-entity-framework-in-an-asp-net-mvc-application
I have 3 tables: the User table, the Records table and the UserRecords table.
The columns are so:
UserTable
UserID | OtherUserDataFields
RecordsTable
RecordID | OtherRecordDataFields
UserRecords
UserID | RecordID
The UserRecords table tells me which users have authorization on which record. I have a function that updates the RecordsTable by receiving 2 paramaters: a record TheRecord (which contains a RecordID field) and a UserID.
I'm writing a query in the data context MyDC to fetch the record with the RecordID supplied in the parameter and test if the user is authorized on that record like this:
var RecordToUpdate = (
from r in MyDC.RecordsTable
from u in MyDC.UserRecords
where r.RecordID == TheRecord.RecordID && TheRecord.RecordID == u.RecordID
where u.UserID == TheUserID
select r).SingleOrDefault();
Will this ensure me that only records the user is authorized will be fetched? I want to avoid cases where users maliciously send a record they're not authorized on and make changes to these unauthorized records.
Thanks for your advice.
I agree with Anand, you will need a linq query:
var filterUserRecord = from u in MyDC.UserRecords
where u.UserID == TheUserID
select u;
var q1 = from r in MyDC.RecordsTable
where r.RecordID = TheRecordID
where filterUserRecord.Any(f => f.RecordID == r.RecordID)
select r;
This will be converted to the SQL query like the following:
SELECT * FROM RecordsTable rt WHERE rt.RecordID = TheRecordID AND EXISTS
(SELECT recordId FROM UserRecords ur WHERE ur.userId = TheUserID AND ur.recordID = rt.recordID)
Note that those are IQueryable<T>s and linq queries on it will produce another IQueryable<T> which will contain expressions to be wholly translated to SQL (or whatever the backend is) instead of naively evaluating it at client side.
Well I think your problem could be solved by subquery
sql:
select * from RecordsTable where recordId in
(select recordId from UserRecords where userId = #someUserId)
It could be represented in Linq as following
var filterUserRecord = from u in MyDC.UserRecords
where u.UserID == TheUserID
select u
var q1 = from r in MyDC.RecordsTable
where filterUserRecord.Any(f => f.RecordID == r.RecordID)
Details for subquery in Linq - Read from here
Perhaps read the article here which discusses how SQL Injection (which I assume should be the main security concern here) is handled in LINQ scenarios.
There is also a nice article here regarding Microsoft's security considerations for EF. It's worth a read for anyone developing with these tools!
[Edit] With regards to your last comment, you can use queries similar to those already on this page. To condense a little: If your database is normalised, to the extent that the RecordId is a unique primary key, you can bypass joins to make a query which reads a little better:
var targetRecords =
from userRecords in MyDC.UserRecords
where userRecords.UserTable.UserID == TheUserID
&& userRecords.RecordsTable.RecordID == TheRecord.RecordID
select userRecords;
var targetRecordsResult = targetRecords.SingleOrDefault();
I have separated the query from it's result 'var' here to point out that 'targetRecords' does NOT get evaluated until you call SingleOrDefault on it in order to assign to targetRecordsResult. You can of course wrap this into one statement if you wish.
If, as mentioned, your RecordID is a Unique Primary Key, you will either get the matching Record back, or null. Note that if this isn't the case, i.e. more than on Record could have the same ID, then the SingleOrDefault call can fail. If your database is designed like that, you would have to use a query more like the one which Anand has specified. That is slightly more verbose, but will return you ANY Record with a matching id for that specific user.
In terms of security, note that your SQL statement will get compiled containing the UserID, making it very difficult to tamper with. Hence my point that in this case, the scope and exposure of UserID is your main concern. If, like you have stated, the user (and any potential malitious user) has no access to the variable (via property exposure etc) then this should be more than suitable for your needs.
Try this:
var RecordToUpdate = (from u in MyDC.UserRecords
where u.UserTable.UserID == TheUserID
and u.RecordsTable.RecordID == TheRecord.RecordID).SingleOrDefault();
This will return the result for query which has specified UserID and RecordID.