This question already has answers here:
Entity Framework Include with condition
(4 answers)
Closed 5 years ago.
I am aware of the other similar question at the link below, but those answers do not work as I am db first and the entity framework plus solution is very slow and appears to just get every record and filter it out afterwards.
EF: Include with where clause
drivers and passengers are navigational properties on busses. preferredBrands is a List<String>. So basically what I want is all busses where typeid = 2, all drivers where their preferredbrand is listed in the preferredbrand list, and all passengers. The query below throws exception:
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
Query:
var result = db.busses.Where(h => h.bussesTypeId.Equals(2))
.Include(h => h.drivers.Where(p => preferredBrands.Contains(p.PreferredBrand)))
.Include(h => h.passengers).ToList();
'Include' only accepts string parameter and not delegate. You have to place the Relational property in quote (string). Do this instead
var result = db.busses
.Include("drivers.preferredBrands")
.Include("passengers")
.Where(h => h.bussesTypeId.Equals(2));
To access drivers, use
result.drivers.where(p => preferredBrands.Contains(p.PrefferedBrand));
However, if you must use delegate in your include, then
1. Reference Z.EntityFramework from Nuget
2. Then you can use 'IncludeFilter' instead as follows;
using Z.EntityFramework.Plus;
var result = db.busses
.IncludeFilter(h => h.drivers.Where(p => preferredBrands.Contains(p.PrefferedBrand)))
.IncludeFilter(h => h.passengers)
.Where(h => h.bussesTypeId.Equals(2)).ToList();
Note: You must use the Include or IncludeFilter before the where clause. It must be used directly on the EF Entity and not just on any IEnumerable
Related
This is more of a syntax question than an actual bug or error, as I finally got what I wanted working. But I want to understand and perhaps improve upon my current solution.
Schema
Let's assume I have a Users table, with a one-to-many relationship to a table Posts, and a further one-to-one relationship table of Authors - one for each Post.
I want to write a custom repository function to get all Users, with all Posts, with each Author per Post.
Attempt #1 (Doesn't Work)
I thought I could do something like:
public IQueryable<User> GetUsersWithPostsAndAuthors()
{
var query = GetAll();
// include all details on user object
return query
.Include(user => user.Posts.Select(x => x.Author));
}
it doesn't seem to include the Author entity. Actually, I was getting the following error:
Lambda expression used inside Include is not valid.
Attempt #2 (Also Doesn't Work)
Then I thought that maybe those Posts need to be in the query first, so I tried this:
public IQueryable<User> GetUsersWithPostsAndAuthors()
{
var query = GetAll();
// include all details on user object
return query
.Include(user => user.Posts)
.Include(user => user.Posts.Select(x => x.Author)
}
Unfortunately, I got the same error:
Lambda expression used inside Include is not valid.
Attempt #3 (Works!)
However, if I use the version of Include where you can provide a string navigationPropertyPath (which actually I don't like since it's just a hardcoded string), with something like this:
public IQueryable<User> GetUsersWithPostsAndAuthors()
{
var query = GetAll();
// include all details on user object
return query
.Include(user => user.Posts)
.Include("Posts.Author");
}
The query works as expected!
What is going on here? I thought the Select projection would do the same as Include. (And there seem to be some answers on Stackoverflow suggesting that.)
More importantly, is there a way to accomplish what I want without hardcoding the Posts.Author in the Include call? I'd like to have static type checks here.
What is going on here?
No offense, but nothing more than not quite understanding what Include is for. It's only for including navigation properties, not for projections.
The syntax is quite clear:
Include for navigation properties off of the root of the query:
.Include(user => user.Posts)
ThenInclude for navigation properties off of included navigation properties:
.Include(user => user.Posts).ThenInclude(p => p.Author)
The latter example is equivalent to .Include("Posts.Author"), but the lambda syntax is preferred because of compile-time checking. In the old EF6 version there was no ThenInclude and the syntax for including more levels was as you wrote: .Include(user => user.Posts.Select(x => x.Author)).
A projection is a Select in the LINQ query, not inside an Include statement. For example:
return query.Select(u => new { u.Id, u.Name });
Projections and Includes exclude one another. In the projection there's nothing in which a navigation property can be included. A query like:
return query
.Include(u => u.Posts)
.Select(u => new
{
u.Id,
u.Name,
Posts = u.Posts.Select(p => p.Title)
});
will completely ignore the Include. There's no trace of it in the generated SQL: only Post.Title will be queried, not all Post fields, as an Include would do.
This question already has answers here:
EF: Include with where clause [duplicate]
(5 answers)
Closed 6 years ago.
I need to get products with cover picture. But when i add pic => pic.IsCover it's throw exception.Otherwise there is no problem. How can i fixed it?
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.
Parametre adı: path
Thanks to all
_db.ProdSmartSorts
.Where(x => catIds.Contains((int)x.Product.CategoryId))
.OrderBy(x => x.ProdSmartId)
.Select(x => x.Product)
.Include(p => p.Pictures.Where(pic => pic.IsCover))
.Skip(prodCount * (pageNumber - 1))
.Take(prodCount)
.ToList();
Entity Framework does not support filtering with the Include method. You can vote for it here, though: https://entityframework.codeplex.com/workitem/47
Does placing the .Include() method call directly after the DbSet work? i.e.
_db.ProdSmartSorts
.Include(p => p.Pictures)
.Where(x => catIds.Contains((int)x.Product.CategoryId))
.OrderBy(x => x.ProdSmartId)
.Select(x => x.Product)
.Skip(prodCount * (pageNumber - 1))
.Take(prodCount)
.ToList();
I think the Include method is only available on the DbSet objects within the dbContext. If you try and put it further down the chain you only have methods that are available to IQueryable or IEnumerable objects dependant on the circumstances.
Also, to my knowledge you can't use the Include function to filter, as you attempted. So you will have to load all images related Picture entities.
EDIT: Sorry - just realised that this question is specifically asking for filtering on the Include() method. Please disregard.
This question already has answers here:
EF: Include with where clause [duplicate]
(5 answers)
Closed 5 years ago.
Here is my expression:
Course course = db.Courses
.Include(
i => i.Modules.Where(m => m.IsDeleted == false)
.Select(s => s.Chapters.Where(c => c.IsDeleted == false))
).Include(i => i.Lab).Single(x => x.Id == id);
I know the cause is Where(m => m.IsDeleted == false) in the Modules portion, but why does it cause the error? More importantly, how do I fix it?
If I remove the where clause it works fine but I want to filter out deleted modules.
.Include is used to eagerly load related entities from the db. I.e. in your case make sure the data for modules and labs is loaded with the course.
The lamba expression inside the .Include should be telling Entity Framework which related table to include.
In your case you are also trying to perform a condition inside of the include, which is why you are receiving an error.
It looks like your query is this:
Find the course matching a given id, with the related module and lab. As long as the matching module and chapter are not deleted.
If that is right, then this should work:
Course course = db.Courses.Include(c => c.Modules)
.Include(c => c.Lab)
.Single(c => c.Id == id &&
!c.Module.IsDeleted &&
!c.Chapter.IsDeleted);
but why does it cause the error?
I can imagine that sometimes the EF team regrets the day they introduces this Include syntax. The lambda expressions suggest that any valid linq expression can be used to subtly manipulate the eager loading. But too bad, not so. As I explained here the lambdas only serve as a disguised string argument to the underlying "real" Include method.
how do I fix it?
Best would be to project to another class (say, a DTO)
db.Courses.Select(x => new CourseDto {
Id = x.Id,
Lab = x.Lab,
Modules = x.Modules.Where(m => !m.IsDeleted).Select( m => new ModuleDto {
Moudle = m,
Chapters = x.Chapters.Where(c => c.IsDeleted)
}
}).Single(x => x.Id == id);
but that may be a major modification for you.
Another option is to disable lazy loading and pre-load the non-deleted Modules and Chapters of the course in the context by the Load command. Relationship fixup will fill the right navigation properties. The Include for Lab will work normally.
By the way, there is a change request for this feature.
This question already has answers here:
EF: Include with where clause [duplicate]
(5 answers)
Closed 5 years ago.
Here is my expression:
Course course = db.Courses
.Include(
i => i.Modules.Where(m => m.IsDeleted == false)
.Select(s => s.Chapters.Where(c => c.IsDeleted == false))
).Include(i => i.Lab).Single(x => x.Id == id);
I know the cause is Where(m => m.IsDeleted == false) in the Modules portion, but why does it cause the error? More importantly, how do I fix it?
If I remove the where clause it works fine but I want to filter out deleted modules.
.Include is used to eagerly load related entities from the db. I.e. in your case make sure the data for modules and labs is loaded with the course.
The lamba expression inside the .Include should be telling Entity Framework which related table to include.
In your case you are also trying to perform a condition inside of the include, which is why you are receiving an error.
It looks like your query is this:
Find the course matching a given id, with the related module and lab. As long as the matching module and chapter are not deleted.
If that is right, then this should work:
Course course = db.Courses.Include(c => c.Modules)
.Include(c => c.Lab)
.Single(c => c.Id == id &&
!c.Module.IsDeleted &&
!c.Chapter.IsDeleted);
but why does it cause the error?
I can imagine that sometimes the EF team regrets the day they introduces this Include syntax. The lambda expressions suggest that any valid linq expression can be used to subtly manipulate the eager loading. But too bad, not so. As I explained here the lambdas only serve as a disguised string argument to the underlying "real" Include method.
how do I fix it?
Best would be to project to another class (say, a DTO)
db.Courses.Select(x => new CourseDto {
Id = x.Id,
Lab = x.Lab,
Modules = x.Modules.Where(m => !m.IsDeleted).Select( m => new ModuleDto {
Moudle = m,
Chapters = x.Chapters.Where(c => c.IsDeleted)
}
}).Single(x => x.Id == id);
but that may be a major modification for you.
Another option is to disable lazy loading and pre-load the non-deleted Modules and Chapters of the course in the context by the Load command. Relationship fixup will fill the right navigation properties. The Include for Lab will work normally.
By the way, there is a change request for this feature.
What's wrong with this Lambda query? I want to be able to only include ProjectDocs of a certain type, there could be many types of ProjectDocs
ICollection<Project> projects = db.Projects
.Include(i => i.ProjectDoc.OfType<Cover>().Where(s => s.Status == "Active"))
.Include(i => i.ProjectDoc.OfType<Summary>().Where(s => s.Status == "Active"))
.Include(i => i.User)
.Include(i => i.ProjectTag.Select(t => t.Tag)).ToList();
I have a model ProjectDoc with the derived classes Cover, Segment and Summary. Should I just include ProjectDoc and use the discriminator column in a condition later? Some of the types could have a large number of results, others just a few.
The Error I get...
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
The Navigation Property on "Project" is ProjectDoc. There is no navigation property for the derived classes. When I tried that I got tons of extra keys.
This scenario is not supported - you can only load or not load a set of related entities but you can not apply filter expressions to load only a subset of the entities.
The API documentation for Include() lists the different expressions that are supported and states that the method just delegates the work to an underlying Include() method taking a string as argument, for example ObjectQuery.Include(). The documentation of this method and the linked page Shaping Query Results make it more or less obvious that this is not supported.