Sdílet prostřednictvím


Načítání souvisejících entit

Entity Framework podporuje tři způsoby načtení souvisejících dat – dychtivé načítání, opožděné načítání a explicitní načítání. Techniky uvedené v tomto tématu jsou rovnocenné pro modely vytvořené pomocí Code First a EF Designeru.

Dychtivá načítání

Načítání dychtivosti je proces, kdy dotaz na jeden typ entity také načte související entity jako součást dotazu. Načítání dychtivosti se dosahuje pomocí metody Include. Níže uvedené dotazy například načtou blogy a všechny příspěvky související s jednotlivými blogy.

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

Poznámka

Include je metoda rozšíření v oboru názvů System.Data.Entity, takže se ujistěte, že používáte tento obor názvů.

Dychtivá načítání více úrovní

Je také možné dychtivě načíst více úrovní souvisejících entit. Níže uvedené dotazy ukazují příklady, jak to udělat pro vlastnosti kolekce i referenční navigace.

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

Poznámka

V současné době není možné filtrovat, které související entity se načtou. Zahrnutí bude vždy obsahovat všechny související entity.

Opožděné načítání

Opožděné načítání je proces, kdy se entita nebo kolekce entit automaticky načte z databáze při prvním přístupu k vlastnosti odkazující na entitu nebo entity. Při použití typů entit POCO se opožděné načítání dosahuje vytvořením instancí odvozených typů proxy a následným přepsáním virtuálních vlastností, aby se přidalo načítání háku. Pokud například použijete třídu entity blogu definovanou níže, související příspěvky se načtou při prvním přístupu k navigační vlastnosti Příspěvky:

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

Vypnout opožděné načítání pro serializaci

Opožděné načítání a serializace se nesměšují dobře, a pokud nejste opatrní, můžete skončit dotazování na celou databázi jen proto, že je povolené opožděné načítání. Většina serializátorů funguje tak, že přistupuje k jednotlivým vlastnostem v instanci typu. Přístup k vlastnostem aktivuje opožděné načítání, takže se serializuje více entit. K těmto vlastnostem entit se přistupuje a ještě více entit se načte. Před serializací entity je vhodné vypnout opožděné načítání. Následující části ukazují, jak to udělat.

Vypnutí opožděné načítání pro konkrétní navigační vlastnosti

Opožděné načítání kolekce Příspěvky je možné vypnout tak, že vlastnost Příspěvky není virtuální:

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

Načítání kolekce Příspěvky je stále možné dosáhnout pomocí dychtivého načítání (viz Dychtivé načítání výše) nebo Load metoda (viz Explicitní načítání níže).

Vypnutí opožděné načítání pro všechny entity

Opožděné načítání lze vypnout pro všechny entity v kontextu nastavením příznaku vlastnosti Konfigurace. Příklad:

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

Načítání souvisejících entit je stále možné dosáhnout pomocí dychtivého načítání (viz Dychtivé načítání výše) nebo metody Load (viz explicitní načítání níže).

Explicitní načítání

I s opožděným načítáním je stále možné opožděně načíst související entity, ale musí být provedeno explicitním voláním. K tomu použijete metodu Load u položky související entity. Příklad:

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

Poznámka

Metoda Reference by se měla použít, pokud má entita navigační vlastnost na jinou entitu. Na druhou stranu by se měla použít metoda Collection, pokud má entita navigační vlastnost kolekce jiných entit.

Metoda Query poskytuje přístup k podkladovému dotazu, který Entity Framework použije při načítání souvisejících entit. Potom můžete pomocí LINQ použít filtry na dotaz předtím, než ho spustíte pomocí volání metody rozšíření LINQ, jako je ToList, Load atd. Metodu Query lze použít s referenčními i kolekcemi navigačních vlastností, ale je nejužitečnější pro kolekce, kde lze použít k načtení pouze části kolekce. Příklad:

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

Při použití metody Query je obvykle nejlepší vypnout opožděné načítání pro navigační vlastnost. Důvodem je to, že jinak se celá kolekce může automaticky načíst opožděným mechanismem načítání buď před nebo po provedení filtrovaného dotazu.

Poznámka

I když je možné relaci zadat jako řetězec místo výrazu lambda, vrácený IQueryable není obecný, pokud je použit řetězec, a proto je metoda Cast obvykle potřebná před tím, než se s ním dá něco užitečného udělat.

Někdy je užitečné vědět, kolik entit souvisí s jinou entitou v databázi, aniž by se skutečně zabíjely náklady na načtení všech těchto entit. K tomu je možné použít metodu Query s metodou LINQ Count. Příklad:

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