Filtering on Include in EF Core

空扰寡人 提交于 2020-08-20 11:23:12

问题


I'm trying to filter on the initial query. I have nested include leafs off a model. I'm trying to filter based on a property on one of the includes. For example:

using (var context = new BloggingContext())
{
    var blogs = context.Blogs
        .Include(blog => blog.Posts)
            .ThenInclude(post => post.Author)
        .ToList();
}

How can I also say .Where(w => w.post.Author == "me")?


回答1:


Finally, this feature has been implemented starting with EF Core preview version 5.0.0-preview.3.20181.2 and will be GA in EF Core version 5.0.0. See EF-core's documentation.

Supported operations:

  • Where
  • OrderBy(Descending)/ThenBy(Descending)
  • Skip
  • Take

Some usage examples (from the original feature request):

Only one filter allowed per navigation, so for cases where the same navigation needs to be included multiple times (e.g. multiple ThenInclude on the same navigation) apply the filter only once, or apply exactly the same filter for that navigation.

customers
    .Include(c => c.Orders.Where(o => o.Name != "Foo")).ThenInclude(o => o.OrderDetails)
    .Include(c => c.Orders).ThenInclude(o => o.Customer)

or

customers
    .Include(c => c.Orders.Where(o => o.Name != "Foo")).ThenInclude(o => o.OrderDetails)
    .Include(c => c.Orders.Where(o => o.Name != "Foo")).ThenInclude(o => o.Customer)

Another important note:

Collections included using new filter operations are considered to be loaded.

That means that if lazy loading is enabled, addressing customers.Orders from the last example won't trigger a reload of the entire Orders collection.

On the other hand, if other Orders are loaded into the same context, more of them may get added to a customers.Orders collection because of relationship fixup. This is inevitable because of how EF's change tracker works.

Also, two subsequent filtered Includes in the same context will accumulate the results. For example...

customers.Include(c => c.Orders.Where(o => !o.IsDeleted))

...followed by...

customers.Include(c => c.Orders.Where(o => o.IsDeleted))

...will result in customers with Orders collections containing all orders.




回答2:


Not doable.

There is an on-going discussion about this topic: https://github.com/aspnet/EntityFramework/issues/1833

I'd suggest to look around for any of the 3rd party libraries listed there, ex.: https://github.com/jbogard/EntityFramework.Filters




回答3:


You can also reverse the search.

{
    var blogs = context.Author
    .Include(author => author.posts)
        .ThenInclude(posts => posts.blogs)
    .Where(author => author == "me")
    .Select(author => author.posts.blogs)
    .ToList();
}



回答4:


Not sure about Include() AND ThenInclude(), but it's simple to do that with a single include:

var filteredArticles = 
    context.NewsArticles.Include(x => x.NewsArticleRevisions)
    .Where(article => article.NewsArticleRevisions
        .Any(revision => revision.Title.Contains(filter)));

Hope this helps!




回答5:


Although it's (still in discussion) not doable with EF Core, I've managed to do it using Linq to Entities over EF Core DbSet. In your case instead of:

var blogs = context.Blogs
        .Include(blog => blog.Posts)
            .ThenInclude(post => post.Author)
        .ToList()

.. you'll have:

await (from blog in this.DbContext.Blogs
           from bPost in blog.Posts
           from bpAuthor in bPost.Author
           where bpAuthor = "me"
           select blog)
.ToListAsync();



回答6:


The easiest inline solution to this I have used would be something like:

using (var context = new BloggingContext())
{
    var blogs = context.Blogs
        .Include(blog => blog.Posts)
            .ThenInclude(post => post.Author)
        .FromSql("Select b.* from Blogs b inner join Posts p on b.BlogId = p.BlogId where p.Author = 'me'")
        .ToList();
}


来源:https://stackoverflow.com/questions/63103021/ef-core-problem-in-filtering-related-entities

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!