O que Include () faz no LINQ?

93

Eu tentei fazer muitas pesquisas, mas sou mais um cara de banco de dados - então mesmo a explicação no MSDN não faz nenhum sentido para mim. Alguém pode explicar e fornecer alguns exemplos sobre o que a Include()afirmação faz no termo de SQLconsulta?

CJ
fonte
Muito básico, eu só conheço simples Selecionar, Onde, Ordem por, alguns operadores agregados. Não tentei JOIN no LINQ, nem Incluir. Meu objetivo final era poder reescrever essas consultas LINQ em SQL
CJ

Respostas:

165

Digamos, por exemplo, que você deseja obter uma lista de todos os seus clientes:

var customers = context.Customers.ToList();

E vamos supor que cada Customerobjeto tenha uma referência ao seu conjunto de Orders, e que cada um Ordertenha referências às LineItemsquais também podem fazer referência a a Product.

Como você pode ver, selecionar um objeto de nível superior com muitas entidades relacionadas pode resultar em uma consulta que precisa obter dados de várias fontes. Como medida de desempenho, Include()permite que você indique quais entidades relacionadas devem ser lidas do banco de dados como parte da mesma consulta.

Usando o mesmo exemplo, isso pode trazer todos os cabeçalhos de pedidos relacionados, mas nenhum dos outros registros:

var customersWithOrderDetail = context.Customers.Include("Orders").ToList();

Como ponto final, já que você solicitou o SQL, a primeira instrução sem Include()poderia gerar uma instrução simples:

SELECT * FROM Customers;

A declaração final que chama Include("Orders")pode ser assim:

SELECT *
FROM Customers JOIN Orders ON Customers.Id = Orders.CustomerId;
que nojo
fonte
1
Obrigado. Usando seu exemplo, posso dizer se também desejo incluir LineItemse Products, a consulta LINQ deve ser semelhante a esta var customersWithOrderDetail = context.Customers.Include("Orders").Include("LineItems").Include("Products").ToList();:?
CJ
2
Sim, você pode encadear várias chamadas Include()para capturar objetos ao longo de "caminhos" diferentes. Se você deseja objetos no mesmo caminho, você só precisa fazer uma chamada que especifica o caminho inteiro. Como LineItemse Productsnão compartilha nenhum componente de caminho, você precisa de chamadas separadas.
Yuck
É obrigatório usar Incluir? Tenho certeza de que trabalhei em soluções nas quais poderia obter objetos relacionados sem usá-los.
Jepzen
@Jepzen Depende se você está usando entidades com carregamento lento ou não.
Yuck
@Yuck, acredito que isso funciona quando você está usando o carregamento lento, no caso de carregamento antecipado, você não precisa usar a instrução "include", mas isso definitivamente resultará em problemas de desempenho. Por favor, me corrija nisso.
sam
26

Só queria acrescentar que "Incluir" faz parte do carregamento antecipado. Ele é descrito no tutorial do Entity Framework 6 da Microsoft. Aqui está o link: https://docs.microsoft.com/en-us/aspnet/mvc/overview/getting-started/getting-started-with-ef-using-mvc/reading-related-data-with-the -entity-framework-in-an-asp-net-mvc-application


Trecho da página vinculada:

Aqui estão várias maneiras que o Entity Framework pode carregar dados relacionados nas propriedades de navegação de uma entidade:

Carregamento lento.Quando a entidade é lida pela primeira vez, os dados relacionados não são recuperados. No entanto, na primeira vez que você tenta acessar uma propriedade de navegação, os dados necessários para essa propriedade de navegação são recuperados automaticamente. Isso resulta em várias consultas enviadas ao banco de dados - uma para a própria entidade e uma cada vez que os dados relacionados para a entidade devem ser recuperados. A classe DbContext permite o carregamento lento por padrão.

Carregamento ansioso. Quando a entidade é lida, os dados relacionados são recuperados junto com ela. Isso normalmente resulta em uma única consulta de junção que recupera todos os dados necessários. Você especifica o carregamento antecipado usando oInclude método.

Carregamento explícito.Isso é semelhante ao carregamento lento, exceto que você recupera explicitamente os dados relacionados no código; isso não acontece automaticamente quando você acessa uma propriedade de navegação. Você carrega dados relacionados manualmente obtendo a entrada do gerenciador de estado do objeto para uma entidade e chamando o método Collection.Load para coleções ou o método Reference.Load para propriedades que contêm uma única entidade. (No exemplo a seguir, se você quiser carregar a propriedade de navegação do Administrador, substitua Collection(x => x.Courses)por Reference(x => x.Administrator).) Normalmente, você usará o carregamento explícito apenas quando tiver desativado o carregamento lento.

Como eles não recuperam imediatamente os valores da propriedade, o carregamento lento e o carregamento explícito também são conhecidos como carregamento adiado.

Minoosha
fonte
2
Bem-vindo ao SO =) Apenas uma sugestão, mas quando você estiver respondendo algo assim, se puder, inclua um trecho de código. Links podem morrer, infelizmente.
The_Cthulhu_Kid
2

Pense nisso como uma aplicação do Eager-Loading em um cenário em que seus subitens seriam de carregamento lento.

O Query EF está enviando para o banco de dados irá render um resultado maior a princípio, mas no acesso nenhuma consulta de acompanhamento será feita ao acessar os itens incluídos.

Por outro lado, sem ele, o EF executaria consultas separadas mais tarde, quando você acessasse os subitens pela primeira vez.

robkrueger
fonte