2017-02-20 72 views
1

我正在使用数据库模式,其中记录在更新时不会被覆盖。而是添加记录的新副本并将其标记为“当前”。实体框架 - 急于使用过滤器加载?

例如:

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

在我的模型我有有许多与此相关的PostBlog实体。每个Post有许多与之相关的Comment S:

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}; 
} 

我想在this example from MSDN热切加载Blog与所有Post S和所有的Comment小号很像:

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。我如何用LINQ到EF来做到这一点?理想情况下,条件将进入JOINON条款 - 这可能吗?

+1

问题不是很清楚,大约.INCLUDE(B => b.Posts.Select(P => p.Comments.Where(注释=> comment.Current)))什么?? –

+0

@ a-t谢谢。什么不清楚?您的建议不会扩展到博客和帖子,并给我:“包含路径表达式必须引用该类型上定义的导航属性。对引用导航属性使用虚线路径,对集合导航属性使用选择运算符。 – urig

回答

1

免责声明:我的项目Entity Framework Plus

的EF +查询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(); 
} 

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

百科:EF+ Query Include Filter


答子问题

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

SQL由实体框架生成。由于他们如何处理投影和包含方法中的关系,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(); 
} 

注:必须包括每个路径由于与导航性能库的一些限制。

百科:EF+ Query IncludeOptimized

+0

谢谢你的回答。由于下面我自己的回答中的警告,我选择使用EF +包含过滤器。返回的结果与预期完全相同。一个担心:发射的SQL非常大。包含多个UNION子句时,看起来只有最后一个实际上是必要的......? (这是所有表连接在一起的那个)。 – urig

0

当使用实体框架“开箱即用”时,现在不支持使用.Include()进行急切加载时进行过滤。你可以vote in favor of this feature here,并希望它切入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秒。

+0

还有[EntityFramework.Filters](https://github.com/jbogard/EntityFramework.Filters/),但不幸的是它的过滤器不适用于'.Include()'。 – urig

1

发现使用“开箱即用”实体框架基于this StackOverflow answer的解决方案。

的关键概念是到父属性添加到每个实体,然后去“倒退”从层次到顶部的最低水平:

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

的一个重要警告是在提到过的对此的评论回答:

...如果父母的父母不存在与过滤器匹配的子女,那些父母将不会在结果集中。