Partilhar via


Carregar entidades relacionadas

O Entity Framework dá suporte a três maneiras de carregar dados relacionados: carregamento adiantado, carregamento adiado e carregamento explícito. As técnicas mostradas neste tópico se aplicam igualmente a modelos criados com o Code First e com o EF Designer.

Carregamento adiantado

O Carregamento adiantado é o processo pelo qual uma consulta para um tipo de entidade também carrega entidades relacionadas como parte da consulta. O Carregamento adiantado é obtido com o uso do método Include. Por exemplo, as consultas abaixo carregarão blogs e todas as postagens relacionadas a cada blog.

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

Observação

Include é um método de extensão no namespace System.Data.Entity, portanto, verifique se você está usando esse namespace.

Como fazer carregamento adiantado em vários níveis

Também é possível fazer carregamento adiantado em vários níveis de entidades relacionadas. As consultas abaixo mostram exemplos de como fazer isso para propriedades de navegação de referência e coleção.

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

Observação

No momento, não é possível filtrar quais entidades relacionadas são carregadas. A inclusão sempre trará todas as entidades relacionadas.

Carregamento lento

O carregamento adiado é o processo pelo qual uma entidade ou conjunto de entidades é automaticamente carregada do banco de dados na primeira vez que uma propriedade referente à entidade/entidades é acessada. Ao usar tipos de entidade POCO, o carregamento adiado é obtido criando instâncias de tipos de proxy derivados e substituindo as propriedades virtuais para adicionar o gancho de carregamento. Por exemplo, ao usar a classe de entidade blog definida abaixo, as Postagens relacionadas serão carregadas na primeira vez que a propriedade de navegação Postagens for acessada:

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

Como desativar o carregamento adiado para serialização

O carregamento adiado e a serialização não se combinam bem e, se você não tiver cuidado, poderá acabar consultando todo o banco de dados apenas porque o carregamento adiado está habilitado. A maioria dos serializadores funciona acessando cada propriedade em uma instância de um tipo. O acesso à propriedade dispara o carregamento adiado, de modo que mais entidades são serializadas. Nessas propriedades de entidades são acessadas e ainda mais entidades são carregadas. É uma boa prática desativar o carregamento adiado antes de serializar uma entidade. As seções a seguir mostram como fazer isso.

Como desativar o carregamento adiado para propriedades de navegação específicas

O carregamento adiado da coleção de Postagens pode ser desativado tornando a propriedade Posts não virtual:

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

O carregamento da coleção de Postagens ainda pode ser feito usando o Carregamento adiantado (consulte Carregamento adiantado acima) ou o método Load (consulte Carregamento explícito abaixo).

Como desativar o carregamento adiado para todas as entidades

O carregamento adiado pode ser desativado para todas as entidades no contexto definindo um sinalizador na propriedade Configuração. Por exemplo:

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

O carregamento de entidades relacionadas ainda pode ser obtido usando o Carregamento adiantado (consulte Carregamento adiantado acima) ou o método Load (consulte Carregamento explícito abaixo).

Carregamento explícito

Mesmo com o carregamento adiado desabilitado, ainda é possível fazer carregamento adiado para entidades relacionadas, mas isso deve ser feito com uma chamada explícita. Para fazer isso, use o método Load na entrada da entidade relacionada. Por exemplo:

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

Observação

O método Reference deve ser usado quando uma entidade tem uma propriedade de navegação para outra única entidade. Por outro lado, o método Collection deve ser usado quando uma entidade tem uma propriedade de navegação para uma coleção de outras entidades.

O método de consulta fornece acesso à consulta subjacente que o Entity Framework usará ao carregar entidades relacionadas. Em seguida, você pode usar LINQ para aplicar filtros à consulta antes de executá-la com uma chamada para um método de extensão LINQ, como ToList, Load etc. O método Query pode ser usado com propriedades de navegação de referência e coleção, mas é mais útil para coleções em que pode ser usado para carregar apenas parte da coleção. Por exemplo:

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

Ao usar o método Query, geralmente é melhor desativar o carregamento adiado para a propriedade de navegação. Isso ocorre porque, caso contrário, toda a coleção poderá ser carregada automaticamente pelo mecanismo de carregamento adiado antes ou depois da execução da consulta filtrada.

Observação

Embora a relação possa ser especificada como uma cadeia de caracteres em vez de uma expressão lambda, o IQueryable retornado não é genérico quando uma cadeia de caracteres é usada e, portanto, o método Cast geralmente é necessário antes que qualquer coisa útil possa ser feita com ela.

Às vezes, é útil saber quantas entidades estão relacionadas à outra entidade no banco de dados sem, na verdade, incorrer no custo de carregar todas essas entidades. O método de consulta com o método LINQ Count pode ser usado para fazer isso. Por exemplo:

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