繁体   English   中英

实体框架 - 急切加载过滤器?

[英]Entity Framework - Eager loading with filter?

我正在使用数据库架构,在更新时不会覆盖记录。 而是添加记录的新副本并标记为“当前”。

例如:

Id | Current | Name | Owner
1  | false   | Foo  | Bar
1  | false   | Foo  | Bazz
1  | true    | Foo  | Buzz

在我的模型中,我有一个Blog实体,其中包含许多与之相关的Post 每个Post都有很多与之相关的Comment

public class Blog
{
    public int Id {get; set};
    public bool Current {get; set};
    public ICollection<Post> Posts {get; set;}
}

public class Post
{
    public int Id {get; set};
    public bool Current {get; set};
    public ICollection<Comment> Comments {get; set;}
}

public class Comment
{
    public int Id {get; set};
    public bool Current {get; set};
}

我想热切地加载一个Blog及其所有Post和所有Comment ,就像在MSDN的这个例子中一样:

using (var context = new BloggingContext()) { // Load all blogs, all related posts, and all related comments var blogs1 = context.Blogs .Include(b => b.Posts.Select(p => p.Comments)) .ToList(); }

但是,我想只包含其中Current == true DB记录。 如何使用LINQ-to-EF执行此操作? 理想情况下,条件会进入JOINON子句 - 这可能吗?

免责声明 :我是项目Entity Framework Plus的所有者

EF + Query IncludeFilter允许轻松过滤包含的实体。

using (var context = new BloggingContext()) 
{ 
  // Load all blogs, all related posts, and all related comments 
  var blogs1 = context.Blogs 
                     .IncludeFilter(b => b.Posts.Where(x => x.Current))
                     .IncludeFilter(b => b.Posts.Where(x => x.Current).Select(p => p.Comments.Where(x => x.Current)) 
                     .ToList(); 
}

注意:由于具有导航属性的库的某些限制,必须包含每个路径。

Wiki: EF + Query包含过滤器


回答子问题

一个问题:发出的SQL非常大。

SQL由Entity Framework生成。 由于它们如何处理投影和包含方法中的关系,SQL非常大。 我们的库不生成这个SQL。

您可以使用EF + Query IncludeOptimized来更改生成的大SQL以执行多个语句。 使用多个语句通常可以提高性能。

例:

using (var context = new BloggingContext()) 
{ 
  // Load all blogs, all related posts, and all related comments 
  var blogs1 = context.Blogs 
                     .IncludeOptimized(b => b.Posts.Where(x => x.Current))
                     .IncludeOptimized(b => b.Posts.Where(x => x.Current).Select(p => p.Comments.Where(x => x.Current)) 
                     .ToList(); 
}

注意:由于具有导航属性的库的某些限制,必须包含每个路径。

Wiki: EF + Query IncludeOptimized

使用基于此StackOverflow答案的 “开箱即用”实体框架找到了解决方案。

关键概念是向每个实体添加父属性,然后从层次结构的最低级别“向后”向上移动到顶部:

var query = context.Comments
    .Include("Post.Blog")
    .Where(comment =>
        comment.Current &&
        comment.Post.Current &&
        comment.Post.Blog.Current )
    .Select(comment => comment.Post.Blog)
    .ToList();

在对SO答案的评论中提到的一个重要警告

...如果父母存在没有任何与过滤器匹配的子项,那么这些父母将不在结果集中。

当使用实体框架“开箱即用”时,目前不支持使用.Include()进行预先加载时进行过滤。 你可以在这里投票赞成这个功能 ,希望它可以切入EF7。

我在一个名为EntityFramework.Include的开源库中找到了我的问题的部分答案,它在急切加载时提供了一些过滤功能。

不幸的是,我只能将它用于我的层次结构中的两个(三个)级别,如下所示:

using (var context = new BloggingContext()) 
{ 
    // Load all blogs and all related posts that are "Current"
    var query = context.Blogs
        .Where(b => b.Current)
        .Include(b => b.Posts, b => b.Posts.Where(p => p.Current).ToList());
    var list = query.ToListWithInclude();
}

仍然试图弄清楚如何更深入到Comment s。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM