2017-02-20 57 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(); 

的一個重要警告是在提到過的對此的評論回答:

...如果父母的父母不存在與過濾器匹配的子女,那些父母將不會在結果集中。