2017-02-20 5 views
1

Ich arbeite mit einem DB-Schema, in dem Datensätze bei der Aktualisierung nicht überschrieben werden. Stattdessen wird eine neue Kopie des Datensatzes hinzugefügt und als "aktuell" markiert.Entity Framework - Eager Laden mit Filter?

Zum Beispiel:

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

In meinem Modell Ich habe eine Blog Einheit, die viele Post s im Zusammenhang mit ihm hat. Jeder Post hat viele Comment s mit sich bringen:

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

Ich möchte eifrig seine eine Blog mit allen Post s laden und alle ihre Comment s ähnlich wie in this example from 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(); }

Allerdings möchte ich nur DB-Datensätze enthalten, wo Current == true. Wie kann ich dies mit LINQ-to-EF tun? Im Idealfall würde die Bedingung in die ON Klausel gehen - ist das möglich?

+1

Frage ist nicht sehr klar, was ist mit .Include (b => b.Posts.Select (p => p.Comments.Where (comment => comment.Current))) ?? –

+0

@ a-t Danke. Was ist nicht klar? Ihr Vorschlag erstreckt sich nicht auf Blogs und Posts und gibt mir Folgendes: "Der Include-Pfadausdruck muss auf eine für diesen Typ definierte Navigationseigenschaft verweisen. Verwenden Sie gepunktete Pfade für Referenznavigationseigenschaften und den Navigationsoperator Select für die Sammlung." – urig

Antwort

1

Haftungsausschluss: Ich bin der Besitzer des Projekts Entity Framework Plus

Das EF + Abfrage IncludeFilter erlauben leicht enthalten Entitäten filtern.

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

Hinweis: Jeder Pfad muss aufgrund einiger Einschränkungen der Bibliothek mit Navigationseigenschaften enthalten sein.

Wiki: EF+ Query Include Filter


Antwort Unterfrage

Eine Sorge: Die SQL emittiert wird, sehr groß.

Die SQL wird von Entity Framework generiert. Das SQL ist sehr groß, da es die Beziehung in der Projektion und der Include-Methode behandelt. Unsere Bibliothek generiert dieses SQL nicht.

Sie können die große SQL mithilfe von EF+ Query IncludeOptimized generiert ändern, anstatt mehrere Anweisung auszuführen. Die Verwendung mehrerer Anweisungen verbessert häufig die Leistung.

Beispiel:

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

Hinweis: Jeder Pfad muss aufgrund einiger Einschränkungen der Bibliothek mit Navigationseigenschaften enthalten sein.

Wiki: EF+ Query IncludeOptimized

+0

Vielen Dank für diese Antwort. Aufgrund der Einschränkung in meiner eigenen Antwort habe ich mich für die Verwendung von EF + Include Filter entschieden. Die zurückgegebenen Ergebnisse sind genau wie erwartet. Ein Problem: Die ausgegebene SQL ist sehr groß. Enthält mehrere UNION-Klauseln, wenn es aussieht, als ob nur die letzte wirklich notwendig ist ...? (Das ist der, wo alle Tabellen zusammengefügt sind.) – urig

0

Filtern, wenn eifrig Laden mit .Include() wird derzeit nicht "out of the box" mit Entity Framework unterstützt. Sie können vote in favor of this feature here und hoffentlich macht es den Schnitt in EF7.

Ich habe eine Teilantwort auf meine Frage in einer Open-Source-Bibliothek namens EntityFramework.Include gefunden, die einige Filterfunktionen zum Zeitpunkt des eifrigen Ladens bietet.

Leider habe ich nur in der Lage gewesen, es für die Verwendung von zwei (von drei) Ebenen meiner Hierarchie wie so:

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

noch zu versuchen, herauszufinden, wie man in Comment s eine Ebene tiefer zu gehen.

+0

Es gibt auch [EntityFramework.Filters] (https://github.com/jbogard/EntityFramework.Filters/), aber leider werden seine Filter nicht auf '.Include()' angewendet. – urig

1

eine Lösung gefunden "out of the box" Entity Framework basiert auf this StackOverflow answer verwenden.

Das Schlüsselkonzept ist eine übergeordnete Eigenschaft zu jeder Einheit hinzuzufügen und dann gehen „rückwärts“ aus der untersten Ebene der Hierarchie nach oben:

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

Eine wichtige Einschränkung, die in einem erwähnt wird Kommentar zu dieser SO-Antwort:

... Wenn Eltern vorhanden sind, die keine Kinder haben, die den Filtern entsprechen, werden diese Eltern nicht in der Ergebnismenge enthalten sein.

Verwandte Themen