Laden zugehöriger Entitäten

Entity Framework unterstützt drei Möglichkeiten zum Laden zugehöriger Daten – Eager Loading, Lazy Loading und explizites Laden. Die in diesem Thema dargestellten Techniken gelten jeweils für Modelle, die mit Code First und dem EF-Designer erstellt wurden.

Eager Loading

Beim Eager Loading handelt es sich um den Prozess, bei dem eine Abfrage für einen Entitätstyp auch zugehörige Entitäten als Teil der Abfrage lädt. Eager Loading erfolgt mithilfe der Include-Methode. Die folgenden Abfragen laden beispielsweise Blogs und alle Beiträge, die sich auf jeden Blog beziehen.

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

    // Load one blog and its related posts.
    var blog1 = context.Blogs
                       .Where(b => b.Name == "ADO.NET Blog")
                       .Include(b => b.Posts)
                       .FirstOrDefault();

    // Load all blogs and related posts
    // using a string to specify the relationship.
    var blogs2 = context.Blogs
                        .Include("Posts")
                        .ToList();

    // Load one blog and its related posts
    // using a string to specify the relationship.
    var blog2 = context.Blogs
                       .Where(b => b.Name == "ADO.NET Blog")
                       .Include("Posts")
                       .FirstOrDefault();
}

Hinweis

Include ist eine Erweiterungsmethode im System.Data.Entity-Namespace. Stellen Sie daher sicher, dass Sie diesen Namespace verwenden.

Eager Loading von mehreren Ebenen

Es ist auch möglich, mehrere Ebenen zugehöriger Entitäten über Eager Loading zu laden. In den folgenden Abfragen finden Sie Beispiele dafür, wie Sie dies sowohl für Sammlungs- als auch für Referenznavigationseigenschaften tun.

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

    // Load all users, their related profiles, and related avatar.
    var users1 = context.Users
                        .Include(u => u.Profile.Avatar)
                        .ToList();

    // Load all blogs, all related posts, and all related comments  
    // using a string to specify the relationships.
    var blogs2 = context.Blogs
                        .Include("Posts.Comments")
                        .ToList();

    // Load all users, their related profiles, and related avatar  
    // using a string to specify the relationships.
    var users2 = context.Users
                        .Include("Profile.Avatar")
                        .ToList();
}

Hinweis

Es ist derzeit nicht möglich, zu filtern, welche zugehörigen Entitäten geladen werden. Include führt immer alle zugehörigen Entitäten ein.

Verzögertes Laden

Lazy Loading ist der Prozess, bei dem eine Entität oder eine Sammlung von Entitäten automatisch aus der Datenbank geladen wird, wenn das erste Mal auf eine Eigenschaft zugegriffen wird, die sich auf die Entität(en) bezieht. Bei der Verwendung von POCO-Entitätstypen wird Lazy Loading erreicht, indem Instanzen abgeleiteter Proxytypen erstellt und dann virtuelle Eigenschaften überschrieben werden, um den Ladehook hinzuzufügen. Wenn Sie beispielsweise die unten definierte Blog-Entitätsklasse verwenden, werden die zugehörigen Beiträge beim ersten Zugriff auf die Navigationseigenschaft „Beiträge“ geladen:

public class Blog
{
    public int BlogId { get; set; }
    public string Name { get; set; }
    public string Url { get; set; }
    public string Tags { get; set; }

    public virtual ICollection<Post> Posts { get; set; }
}

Lazy Loading für die Serialisierung deaktivieren

Lazy Loading und Serialisierung funktionieren nicht gut zusammen, und wenn Sie nicht aufpassen, können Sie am Ende Ihre gesamte Datenbank abfragen, nur weil Lazy Loading aktiviert ist. Die meisten Serialisierer funktionieren, indem sie auf jede Eigenschaft einer Instanz eines Typs zugreifen. Der Eigenschaftenzugriff löst Lazy Loading aus, sodass mehr Entitäten serialisiert werden. Auf diese Entitätseigenschaften wird zugegriffen, und noch mehr Entitäten werden geladen. Es empfiehlt sich, Lazy Loading zu deaktivieren, bevor Sie eine Entität serialisieren. Dies wird in den folgenden Abschnitte gezeigt.

Deaktivieren von Lazy Loading für bestimmte Navigationseigenschaften

Lazy Loading der für die Beitragssammlung kann ausgeschaltet werden, indem die Beitragseigenschaften nicht-virtuell gemacht werden:

public class Blog
{
    public int BlogId { get; set; }
    public string Name { get; set; }
    public string Url { get; set; }
    public string Tags { get; set; }

    public ICollection<Post> Posts { get; set; }
}

Das Laden der Beitragssammlung kann weiterhin mit Eager Loading erreicht werden (siehe Eager Loading oben) oder die Lademethode (siehe Explizites Laden unten).

Deaktivieren von Lazy Loading für alle Entitäten

Lazy Loading kann für alle Entitäten im Kontext ausgeschaltet werden, indem ein Flag in der Eigenschaft „Konfiguration“ gesetzt wird. Beispiel:

public class BloggingContext : DbContext
{
    public BloggingContext()
    {
        this.Configuration.LazyLoadingEnabled = false;
    }
}

Das Laden der zugehörigen Entitäten kann weiterhin mit Eager Loading erreicht werden (siehe Eager Loading oben) oder die Load-Methode (siehe Explizites Laden unten).

Explizites Laden

Auch wenn Lazy Loading deaktiviert ist, ist es immer noch möglich, verwandte Entitäten über Lazy Loading zu laden, doch das muss mit einem expliziten Aufruf erfolgen. Verwenden Sie dazu die Load-Methode für den Eintrag der zugehörigen Entität. Beispiel:

using (var context = new BloggingContext())
{
    var post = context.Posts.Find(2);

    // Load the blog related to a given post.
    context.Entry(post).Reference(p => p.Blog).Load();

    // Load the blog related to a given post using a string.
    context.Entry(post).Reference("Blog").Load();

    var blog = context.Blogs.Find(1);

    // Load the posts related to a given blog.
    context.Entry(blog).Collection(p => p.Posts).Load();

    // Load the posts related to a given blog
    // using a string to specify the relationship.
    context.Entry(blog).Collection("Posts").Load();
}

Hinweis

Die Reference-Methode sollte verwendet werden, wenn eine Entität über eine Navigationseigenschaft zu einer anderen einzelnen Entität verfügt. Andererseits sollte die Collection-Methode verwendet werden, wenn eine Entität über eine Navigationseigenschaft für eine Sammlung anderer Entitäten verfügt.

Die Query-Methode bietet Zugriff auf die zugrunde liegende Abfrage, die Entity Framework beim Laden verwandter Entitäten verwendet. Anschließend können Sie LINQ verwenden, um Filter auf die Abfrage anzuwenden, bevor Sie sie mit einem Aufruf einer LINQ-Erweiterungsmethode wie ToList, Load usw. ausführen. Die Query-Methode kann mit Navigationseigenschaften sowohl für Verweise als auch für Sammlungen verwendet werden, ist jedoch am nützlichsten für Sammlungen, in denen sie nur zum Laden eines Teils der Auflistung verwendet werden kann. Beispiel:

using (var context = new BloggingContext())
{
    var blog = context.Blogs.Find(1);

    // Load the posts with the 'entity-framework' tag related to a given blog.
    context.Entry(blog)
           .Collection(b => b.Posts)
           .Query()
           .Where(p => p.Tags.Contains("entity-framework"))
           .Load();

    // Load the posts with the 'entity-framework' tag related to a given blog
    // using a string to specify the relationship.
    context.Entry(blog)
           .Collection("Posts")
           .Query()
           .Where(p => p.Tags.Contains("entity-framework"))
           .Load();
}

Bei Verwendung der Query-Methode ist es in der Regel am besten, Lazy Loading für die Navigationseigenschaft zu deaktivieren. Dies liegt daran, dass andernfalls die gesamte Sammlung entweder vor oder nach der Ausführung der gefilterten Abfrage automatisch vom faulen Lademechanismus geladen wird.

Hinweis

Während die Beziehung als Zeichenfolge anstelle eines Lambda-Ausdrucks angegeben werden kann, ist die zurückgegebene IQueryable nicht generisch, wenn eine Zeichenfolge verwendet wird und daher die Cast-Methode in der Regel benötigt wird, bevor sie nützlich sein kann.

Manchmal ist es hilfreich, zu wissen, wie viele Entitäten mit einer anderen Entität in der Datenbank verbunden sind, ohne dass tatsächlich die Kosten für das Laden aller diese Entitäten entstehen. Dazu kann die Query-Methode mit der LINQ Count-Methode verwendet werden. Beispiel:

using (var context = new BloggingContext())
{
    var blog = context.Blogs.Find(1);

    // Count how many posts the blog has.
    var postCount = context.Entry(blog)
                           .Collection(b => b.Posts)
                           .Query()
                           .Count();
}