Carregamento de dados relacionadosLoading Related Data

Entity Framework Core permite que você use as propriedades de navegação em seu modelo para carregar as entidades relacionadas.Entity Framework Core allows you to use the navigation properties in your model to load related entities. Há três padrões de S/RM comuns usados para carregar os dados relacionados.There are three common O/RM patterns used to load related data.

  • Carregamento adiantado significa que os dados relacionados são carregados do banco de dados como parte da consulta inicial.Eager loading means that the related data is loaded from the database as part of the initial query.
  • Carregamento explícito significa que os dados relacionados explicitamente carregados do banco de dados em um momento posterior.Explicit loading means that the related data is explicitly loaded from the database at a later time.
  • Carregamento preguiçoso significa que os dados relacionados são carregados transparente do banco de dados quando a propriedade de navegação é acessada.Lazy loading means that the related data is transparently loaded from the database when the navigation property is accessed. Carregamento preguiçoso ainda não é possível com o EF Core.Lazy loading is not yet possible with EF Core.

Dica

Você pode exibir este artigo exemplo no GitHub.You can view this article's sample on GitHub.

Carregamento adiantadoEager loading

Você pode usar o Include método para especificar dados relacionados a serem incluídos nos resultados da consulta.You can use the Include method to specify related data to be included in query results. No exemplo a seguir, os blogs que são retornados nos resultados terão seus Posts propriedade preenchida com as postagens relacionadas.In the following example, the blogs that are returned in the results will have their Posts property populated with the related posts.

using (var context = new BloggingContext())
{
    var blogs = context.Blogs
        .Include(blog => blog.Posts)
        .ToList();
}

Dica

Entity Framework Core será corrigir automaticamente o propriedades de navegação para outras entidades que foram previamente carregadas para a instância de contexto.Entity Framework Core will automatically fix-up navigation properties to any other entities that were previously loaded into the context instance. Dessa forma, mesmo se você não incluir explicitamente os dados para uma propriedade de navegação, a propriedade ainda pode ser populada se algumas ou todas as entidades relacionadas foram carregadas anteriormente.So even if you don't explicitly include the data for a navigation property, the property may still be populated if some or all of the related entities were previously loaded.

Você pode incluir dados relacionados de várias relações em uma única consulta.You can include related data from multiple relationships in a single query.

using (var context = new BloggingContext())
{
    var blogs = context.Blogs
        .Include(blog => blog.Posts)
        .Include(blog => blog.Owner)
        .ToList();
}

Incluindo vários níveisIncluding multiple levels

Você pode fazer uma busca detalhada por meio de relações para incluir vários níveis de dados relacionados usando o ThenInclude método.You can drill down thru relationships to include multiple levels of related data using the ThenInclude method. O exemplo a seguir carrega todos os blogs, suas postagens relacionadas e autor de cada postagem.The following example loads all blogs, their related posts, and the author of each post.

using (var context = new BloggingContext())
{
    var blogs = context.Blogs
        .Include(blog => blog.Posts)
            .ThenInclude(post => post.Author)
        .ToList();
}

É possível encadear chamadas múltiplas para ThenInclude para continuar incluindo mais níveis de dados relacionados.You can chain multiple calls to ThenInclude to continue including further levels of related data.

using (var context = new BloggingContext())
{
    var blogs = context.Blogs
        .Include(blog => blog.Posts)
            .ThenInclude(post => post.Author)
                .ThenInclude(author => author.Photo)
        .ToList();
}

Você pode combinar tudo isso para incluir dados relacionados de vários níveis e várias raízes na mesma consulta.You can combine all of this to include related data from multiple levels and multiple roots in the same query.

using (var context = new BloggingContext())
{
    var blogs = context.Blogs
        .Include(blog => blog.Posts)
            .ThenInclude(post => post.Author)
            .ThenInclude(author => author.Photo)
        .Include(blog => blog.Owner)
            .ThenInclude(owner => owner.Photo)
        .ToList();
}

Você talvez queira incluir várias entidades relacionadas para uma das entidades que está sendo incluída.You may want to include multiple related entities for one of the entities that is being included. Por exemplo, ao consultar Blogs, que você incluir Posts e deseja incluir o Author e Tags do Posts.For example, when querying Blogs, you include Posts and then want to include both the Author and Tags of the Posts. Para fazer isso, você precisa especificar cada incluem a partir da raiz do caminho.To do this, you need to specify each include path starting at the root. Por exemplo, Blog -> Posts -> Author e Blog -> Posts -> Tags.For example, Blog -> Posts -> Author and Blog -> Posts -> Tags. Isso não significa que você obterá junções redundantes, na maioria dos casos que EF serão consolidados associações durante a geração de SQL.This does not mean you will get redundant joins, in most cases EF will consolidate the joins when generating SQL.

using (var context = new BloggingContext())
{
    var blogs = context.Blogs
        .Include(blog => blog.Posts)
            .ThenInclude(post => post.Author)
        .Include(blog => blog.Posts)
            .ThenInclude(post => post.Tags)
        .ToList();
}

Ignorado incluiIgnored includes

Se você alterar a consulta para que ele não retorna instâncias do tipo de entidade que a consulta foi iniciada com o, os operadores de inclusão são ignorados.If you change the query so that it no longer returns instances of the entity type that the query began with, then the include operators are ignored.

No exemplo a seguir, os operadores de inclusão se baseiam o Blog, mas, em seguida, o Select operador é usado para alterar a consulta para retornar um tipo anônimo.In the following example, the include operators are based on the Blog, but then the Select operator is used to change the query to return an anonymous type. Nesse caso, os operadores de inclusão não têm efeito.In this case, the include operators have no effect.

using (var context = new BloggingContext())
{
    var blogs = context.Blogs
        .Include(blog => blog.Posts)
        .Select(blog => new
        {
            Id = blog.BlogId,
            Url = blog.Url
        })
        .ToList();
}

Por padrão, o núcleo de EF registrará um aviso quando inclui operadores são ignorados.By default, EF Core will log a warning when include operators are ignored. Consulte log para obter mais informações sobre como exibir a saída de log.See Logging for more information on viewing logging output. Você pode alterar o comportamento quando um operador include é ignorado para gerar ou não faça nada.You can change the behavior when an include operator is ignored to either throw or do nothing. Isso é feito ao configurar as opções para o contexto - normalmente em DbContext.OnConfiguring, ou em Startup.cs se você estiver usando o ASP.NET Core.This is done when setting up the options for your context - typically in DbContext.OnConfiguring, or in Startup.cs if you are using ASP.NET Core.

protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
{
    optionsBuilder
        .UseSqlServer(@"Server=(localdb)\mssqllocaldb;Database=EFQuerying;Trusted_Connection=True;ConnectRetryCount=0")
        .ConfigureWarnings(warnings => warnings.Throw(CoreEventId.IncludeIgnoredWarning));
}

Carregamento explícitoExplicit loading

Observação

Esse recurso foi introduzido no EF Core 1.1.This feature was introduced in EF Core 1.1.

Você pode carregar explicitamente uma propriedade de navegação por meio de DbContext.Entry(...) API.You can explicitly load a navigation property via the DbContext.Entry(...) API.

using (var context = new BloggingContext())
{
    var blog = context.Blogs
        .Single(b => b.BlogId == 1);

    context.Entry(blog)
        .Collection(b => b.Posts)
        .Load();

    context.Entry(blog)
        .Reference(b => b.Owner)
        .Load();
}

Você pode carregar também explicitamente uma propriedade de navegação executando uma consulta separada que retorna as entidades relacionadas.You can also explicitly load a navigation property by executing a seperate query that returns the related entities. Se o controle de alterações está habilitada, ao carregar uma entidade, Core EF automaticamente definir as propriedades de navegação da entidade para se referir a qualquer entidade que já carregada recentemente carregado e definir as propriedades de navegação das entidades já carregado para referir-se a entidade carregado recentemente.If change tracking is enabled, then when loading an entity, EF Core will automatically set the navigation properties of the newly-loaded entitiy to refer to any entities already loaded, and set the navigation properties of the already-loaded entities to refer to the newly-loaded entity.

Você também pode obter uma consulta LINQ que representa o conteúdo de uma propriedade de navegação.You can also get a LINQ query that represents the contents of a navigation property.

Isso permite que você faça coisas como a execução de um operador de agregação sobre as entidades relacionadas sem carregá-los na memória.This allows you to do things such as running an aggregate operator over the related entities without loading them into memory.

using (var context = new BloggingContext())
{
    var blog = context.Blogs
        .Single(b => b.BlogId == 1);

    var postCount = context.Entry(blog)
        .Collection(b => b.Posts)
        .Query()
        .Count();
}

Você também pode filtrar quais entidades relacionadas são carregadas na memória.You can also filter which related entities are loaded into memory.

using (var context = new BloggingContext())
{
    var blog = context.Blogs
        .Single(b => b.BlogId == 1);

    var goodPosts = context.Entry(blog)
        .Collection(b => b.Posts)
        .Query()
        .Where(p => p.Rating > 3)
        .ToList();
}

Carregamento preguiçosoLazy loading

Carregamento preguiçoso ainda não é suportado por núcleo EF.Lazy loading is not yet supported by EF Core. Você pode exibir o item de carregamento lento em nossa lista de pendências para controlar esse recurso.You can view the lazy loading item on our backlog to track this feature.

Como propriedades de navegação de automaticamente a correção do EF principal será você pode acabar com ciclos em seu gráfico de objeto.Because EF Core will automatically fix-up navigation properties, you can end up with cycles in your object graph. Por exemplo, o carregamento de um blog e está relacionado postagens resultará em um objeto de blog que referencia uma coleção de postagens.For example, Loading a blog and it's related posts will result in a blog object that references a collection of posts. Cada essas postagens terá uma referência de volta para o blog.Each of those posts will have a reference back to the blog.

Algumas estruturas de serialização não permitir que esses ciclos.Some serialization frameworks do not allow such cycles. Por exemplo, Json.NET lançará a exceção a seguir se encontrou um ciclo.For example, Json.NET will throw the following exception if a cycle is encoutered.

Newtonsoft.Json.JsonSerializationException: Self referenciando loop detectado para a propriedade 'Blog' com tipo 'MyApplication.Models.Blog'.Newtonsoft.Json.JsonSerializationException: Self referencing loop detected for property 'Blog' with type 'MyApplication.Models.Blog'.

Se você estiver usando o ASP.NET Core, você pode configurar Json.NET para ignorar ciclos que encontrar no gráfico de objeto.If you are using ASP.NET Core, you can configure Json.NET to ignore cycles that it finds in the object graph. Isso é feito o ConfigureServices(...) método Startup.cs.This is done in the ConfigureServices(...) method in Startup.cs.

public void ConfigureServices(IServiceCollection services)
{
    ...

    services.AddMvc()
        .AddJsonOptions(
            options => options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore
        );

    ...
}