Trying to use navigation properties in a Linq query and not getting any results. Not sure why.
I'm using the standard Simple Membership tables in SQL Server with Entity Framework. So I've pulled the three tables, AspNetUsers, AspNetRoles and AspNetUserRoles into my model (See pic below)
YES, I KNOW I CAN USE THE ROLE/IDENTITY FUNCTIONS, I AM JUST USING THESE TABLES TO TRY OUT THIS LINQ QUERY, THESE TABLES WERE CONVENIENT TO USE
Anyway, my goal was to use the Navigation properties to get the roles for a given user. AspNetUserRoles does not get pulled into my model as an entity since it has no primary key, so this seemed the right way to go. I tried using the suggestion presented here:
Linq to entities navigation properties
The following linq query returns 0 results
var result = (from r in context.AspNetRoles
where r.AspNetUsers.Any(u => u.Id == UserId)
select r).ToList();
return result;
Thought maybe I needed to use the Include extension so I tried this, also returns 0 results
var result = (from r in context.AspNetRoles
where r.AspNetUsers.Any(u => u.Id == UserId)
select r).Include("AspNetUsers").ToList();
return result;
I know I'm doing something wrong with the line:
where r.AspNetUsers.Any(u => u.Id == UserId)
because if I remove it, I get results but not for a specific user, of course.
I'm trying to follow the advice given in one of the answers here:
Any ideas?
Thanks in advance!
If I understand correctly, you want to get all of a User's roles based on their Id.
Unless there is some information I am missing about your User model, then it is impossible to get this without accessing AspNetUserRoles.
If you can access that table, then this becomes really straightforward:
var result = AspNetUserRoles.Where(role => role.UserId == UserId)
.Select(userRole => AspNetRoles.First(role => role.Id == userRole.RoleId));
Or in query syntax:
var result = from userRole in AspNetUserRoles
where userRole.UserId == UserId
from role in AspNetRoles
where role.Id == userRole.RoleId
select role;
Related
I have a model called User and each user has a list of another model called Hobbies. I want to retrieve a User who has a hobby with a certain ID, is there anything better using Entity Framework than just retrieving all users then searching inside each user's hobbies list and match it with the hobby id, a pseudo code would look like the following
UserList = select all users from db
targetUser = null;
for User in UsersList:
for Hobby in User.HobbiesList:
if(Hobby.ID == currentHobby.ID)
{
targetUser = User;
}
First of all, EF won't automatically get all the linked entities, you need to explicitly Include everything you want to see in the end result.
As for the question, yes of course, you can use all the standard LINQ filters when working with EF. In your case
db.Userlist.Where(user => user.HobbiesList.Any(hobby => hobby.ID == currentHobby.ID))
Don't forget to Include(user => user.HobbiesList) if you want to see it in the results.
I have Models named Contest,Problem and Judge
A judge has many Contest and a Contest has many Judge
DataBase Diagram for Models
But when I accessed judges list from database by contest Id it's not working
var existingJudge = this.unitOfWork.JudgeRepository.Get()
.Where(r => r.Contest_Id.Contains(id) && r.Id == User.Identity.GetUserId());
I have tried this too
existingJudge = this.unitOfWork.ContestRepository.GetById(id).JudgeList;
Here id means contest id
Have you tried this :
var existingJudge = this.unitOfWork.JudgeRepository.Get()
.Where(r => r.Contests.Any(t => t.Id == id));
if id contains the right number, this should work.
Several things can be wrong.
Can you please share your class diagram or classes as well. Are you marking the linked object properties (i.e. judges) as virtual? Also Your table is using AspNetUser as name, have you mapped your judge object properly? I would like to see how you mapped your objects to the table name.
I have an app using EF 6 and MVC 5 that works fine for inputting data, but now when I try to display some of it I'm having troubles. The basic layout of my entities can be seen in the following diagram:
The first part where I'm having trouble is in querying and filtering the data. I would like to return a list of premises and related data where a survey and signoff exist, but an approval does not. In straight SQL, the query that works now is:
SELECT *
FROM Premises p LEFT OUTER JOIN Approvals a ON a.Id = p.Id
JOIN Surveys s ON s.PremiseId = p.Id
JOIN SignOffs so ON so.Id = s.Id
WHERE a.ApprovedBy IS NULL
The code that I started with is like this:
var premises = Premises.Include(p => p.Approval)
.Include(p => p.Surveys)
.Include(p => p.Surveys.Select(s => s.SignOff));
This appears* to return all records including the child data, but when I try to filter it so I get only records that have a signoff record but do not have an approval, it doesn't work.
var premises = Premises.Include(p => p.Approval).Where(p => p.Approval.ApprovedBy == null)
.Include(p => p.Surveys)
.Include(p => p.Surveys.Select(s => s.SignOff).Where(s => s.Signature != null));
If I use this code, I get this error:
The Include path expression must refer to a navigation property defined on the type. Use dotted paths for reference navigation properties and the Select operator for collection navigation properties.
Parameter name: path
I've changed this query around a lot to try different things, so I'm not sure what all I have done, but I think the first Where statement might work by itself, but the second one definetly causes the error.
How do I need to structure my query to get it to return the requested data properly filtered?
Also, I put an asterisk above on stating that the query appears to return all the data and child data because I can't actually test it. When I'm trying to write my Razor CSHTML page for this, it's not giving me intellisense for the child and grandchild data, and if I enter what I think it should be I get errors. How do I need to reference this data on the page?
You cannot use Include() like this, it is only good for specifying to load a navigation property, not to specify to load an entity when a navigation property is something (not null, in your case).
To do the filtering, I suggest something like this:
var premises = Premises.Include(p => p.Approval).Include(p => p.Surveys).Include(p => p.Surveys.Select(s => s.SignOff))
.Where(p=>p.Approval.ApprovedBy!=null && p.Surveys.Any(s=>s.SignOff.Signature!=null));
So basically, the includes and the filtering have nothing to do with each other. With the includes, you only specify what to load, you can still use the filter on the original entity set.
You're confusing what the Include LINQ method does. It only tells EF to eagerly load that relationship, which is actually unnecessary if your query itself utilizes that relationship; EF will include the relationship by default in that case.
What it doesn't do is allow you filter those relationships. For example, in this portion of your code:
.Include(p => p.Surveys.Select(s => s.SignOff).Where(s => s.Signature != null));
The where clause is applied to Premises, not SignOff as you seem to think. In other words, Where filters the main table being queried, not the table you're including.
There's two paths forward here. You can simply filter Premises by the important parts, i.e.:
var premises = Premises.Where(p => p.Approval.ApprovedBy == null && p => p.Surveys.Any(s => s.SignOff.Signature != null));
That will return only premises where these conditions are true, but the included Surveys collection will contain all surveys related to each premise, not just the ones with null signoff signatures.
If you need to filter the related items as well, then you must explicitly load them:
foreach (premise in premises)
{
context.Entry(premise)
.Collection(p => p.Surveys)
.Query()
.Where(s => s.SignOff.Signature != null)
.Load();
}
Two things of note:
Because of the nature of how this query must be applied, there's no way to do it once for all premises. You'll have to iterate over the premises and explicitly load the Surveys collection for each.
Since this will issue a new query, you want to avoid loading the Surveys collection either lazily or eagerly before this explict load. Otherwise, you're querying the same information twice, which is very inefficient. The easiest way to ensure that is to remove the virtual keyword from the collection property. However, if you do that, then you will have to eager or explicitly load the collection or it will be null. For more information, see: https://msdn.microsoft.com/en-us/library/jj574232(v=vs.113).aspx
I am trying to fetch a collection of entities from a one-to-many relationship as an IQueryable so I can filter the data down before fetching this from the database.
To make it clear, consider the following example:
I currently have an entity "User" which has a collection of Pictures:
public virtual ICollection<Picture> Pictures{ get; set; }
The Picture entity may or may not belong to a User, and hence, doesnt have the User property in its definition.
A user may have thousands of pictures, but I would like to select the first 10 for example, ordered by Picture.Id. Is there a way to do this?
Maybe something along the lines like:
IQueryable<ICollection<Picture>> pictures = context.Users.Where(u=>u.UserId == userId).Select(c => c.Pictures)
Thanks!
The basic idea is to use the OrderBy and Take methods on the Pictures collection of the user. However, since you want to make sure that you only perform a single EntityFramework SQL query without loading the entire Pictures collection of a user, this needs to be expressed in a slightly more specific way.
Query syntax
var result = (from u in users
where u.Id == userId
from p in u.Pictures
orderby p.Id
select p).Take(10);
Method syntax
var result = context.Users
.Where(u => u.Id == 2)
.SelectMany(u => u.Pictures)
.OrderBy(p => p.Id)
.Take(10);
Note the call to SelectMany. It's important. Basically this adds up all the Pictures collections of all the selected users into one list and continues the query on this flattened meta-list. In theory this sounds like a pretty big operation, but in this case there should only be one user with a specific ID, so it really just continues with the selected user's Pictures collection. The generated SQL is a single, fast query:
Resulting SQL query (for both of the above)
SELECT TOP (10)
[Extent1].[User_Id] AS [User_Id],
[Extent1].[Id] AS [Id],
[Extent1].[Name] AS [Name]
FROM [dbo].[Pictures] AS [Extent1]
WHERE ([Extent1].[User_Id] IS NOT NULL) AND (2 = [Extent1].[User_Id])
ORDER BY [Extent1].[Id] ASC
This is my first question in stackoverflow but really not the first time to get solution here. I am struggling with multiple join in entity framework 4. I have three tables (Accounts, Users and AccountUsers) that am finding difficult to query.
What I want is to get all the users for the provided accountId including the account creator. I can get all the account users with no problem but the hard side for me is getting the account creator since it's not added to AccountUsers table. below is a quick preview how the tables are related.
Accounts
AccountId
UserId (account creator)
...other columns
Users
UserId
...other columns
AccountUsers
AccountId
UserId
I would prefer the query to be esql, but Linq to Entities will do.
I trust you guys on stackoverflow, so I know this won't take long to get the 'Answer' mark.
Thanks for even reading.
If I'm reading your question right, you're not looking for a join so much as a union? I'm not sure about esql, but I'd think the following Linq query should work. Maybe it will get you going in the right direction (or I could be completely off-base or missing something):
var users = (from accountUser in db.AccountUsers
where accountUser.AccountId == myAccountId
select accountUser.UserId)
.ToList()
.Add((from account in db.Accounts
where account.AccountId == myAccountId
select account.UserId)
.Single());
To make it lazy loading, you could always make a method that makes use of foreach and yield return:
IEnumerable<int> GetAccountUsers(int AccountId)
{
//return the users
foreach(var userId in (from accountUser in db.AccountUsers
where accountUser.AccountId == myAccountId
select accountUser.UserId))
yield return userId;
//return the owner too
yield return (from account in db.Accounts
where account.AccountId == myAccountId
select account.UserId)
.Single();
}
Out of curiosity, though, why is the owner not also added to the AccountUsers table?