Utilizando Include e ThenInclude no Entity Framework

Quando estamos lidando com consultas que envolvem relações entre entidades, o EF oferece métodos eficientes para incluir dados relacionados, como “Include”, “ThenInclude”. Este artigo irá explorar esses métodos, explicando suas funcionalidades e apresentando exemplos práticos de uso.

Lazy Loading

No Entity Framework (EF), o Lazy Loading, ou carregamento tardio, é um comportamento padrão em que as entidades relacionadas não são carregadas automaticamente junto com a entidade principal.

Esse comportamento é vantajoso, pois nem sempre precisamos de todos os dados relacionados à entidade, evitando assim o carregamento de informações desnecessárias, melhorando o desempenho em algumas situações ao reduzir a quantidade de dados inicialmente buscados.

Eager Loading

No entanto, há casos em que é necessário carregar as entidades relacionadas junto com a entidade principal. Isso é especialmente importante quando sabemos antecipadamente que precisaremos dessas informações.

Nesses cenários, o Eager Loading, ou carregamento antecipado se torna uma abordagem mais apropriada. Usando os métodos “Include” e “ThenInclude”, o EF permite carregarmos as entidades relacionadas de uma só vez, em uma única consulta, garantindo que todas as informações necessárias estejam disponíveis imediatamente.

Consulta sem Include

Para ilustrar o funcionamento dessas técnicas no Entity Framework, vamos tomar como exemplo um cenário em que temos a entidade “Pedido”, a qual contém um “Cliente” que, por sua vez, contém um “Endereco”. Ou seja, temos dois níveis de relacionamento entre as entidades:

Ao realizarmos uma consulta no banco de dados, apenas os dados da entidade principal, “Pedido”, são carregados. Os dados relacionados, como o “Cliente” e seu “Endereco”, não são carregados imediatamente. Por exemplo:

				
					var pedidos = _context.Pedidos.ToList();
				
			

No resultado da consulta acima teríamos apenas os dados da entidade principal, “Pedido”, enquanto a propriedade de navegação “Cliente” viria nula, pois ela não foi explicitamente requisitada.

Nesse caso os dados retornados seriam os seguintes:

				
					[
  {
    "pedidoId": 1,
    "descricao": "Pedido 001",
    "clienteId": 101,
    "cliente": null
  },
  {
    "pedidoId": 2,
    "descricao": "Pedido 002",
    "clienteId": 102,
    "cliente": null
  }
]
				
			

Utilizando Include

Conforme foi comentado anteriormente, o Lazy Loading pode ser bastante útil para evitar o carregamento antecipado de dados que não serão necessários no primeiro momento. Porém, desta vez desejamos carregar também os dados do cliente vinculado ao pedido, para isso utilizaremos o método “Include”, da seguinte forma:

				
					var pedidos = _context.Pedidos
                      .Include(p => p.Cliente)
                      .ToList();

				
			

Neste exemplo estamos passando como parâmetro para o método “Include” uma expressão lambda que define qual propriedade de navegação desejamos carregar. Ao fazer isso, o Entity Framework irá resolver o relacionamento que foi configurado e realizar a consulta adequada para trazer os dados dependentes.

Dessa vez os dados retornados seriam os seguintes:

				
					[
  {
    "pedidoId": 1,
    "descricao": "Pedido 001",
    "clienteId": 101,
    "cliente": {
      "clienteId": 101,
      "nome": "João Silva",
      "endereco": null
    }
  },
  {
    "pedidoId": 2,
    "descricao": "Pedido 002",
    "clienteId": 102,
    "cliente": {
      "clienteId": 102,
      "nome": "Maria Souza",
      "endereco": null
    }
  }
]

				
			

Utilizando ThenInclude

No exemplo anterior, carregamos uma propriedade de navegação a partir da entidade principal da consulta. Porém, note que a classe “Cliente” possui uma propriedade “Endereco” que veio nula na consulta acima.

Isso ocorre porque como temos mais um relacionamento, é preciso carregá-lo explicitamente, assim como foi feito com o primeiro. Porém, dessa vez, como desejamos incluir uma entidade que está relacionada a uma outra que já foi incluída, precisamos utilizar o método “ThenInclude”, realizando um tipo de carregamento “em cascata”:

				
					var pedidos = _context.Pedidos
                      .Include(p => p.Cliente)
                          .ThenInclude(c => c.Endereco)
                      .ToList();

				
			

Agora, os resultados retornados incluem também os dados da entidade “Endereco”, relacionada ao cliente de cada pedido:

				
					[
  {
    "pedidoId": 1,
    "descricao": "Pedido 001",
    "clienteId": 101,
    "cliente": {
      "clienteId": 101,
      "nome": "João Silva",
      "endereco": {
        "enderecoId": 501,
        "rua": "Rua das Flores",
        "cidade": "São Paulo"
      }
    }
  },
  {
    "pedidoId": 2,
    "descricao": "Pedido 002",
    "clienteId": 102,
    "cliente": {
      "clienteId": 102,
      "nome": "Maria Souza",
      "endereco": {
        "enderecoId": 502,
        "rua": "Avenida Paulista",
        "cidade": "São Paulo"
      }
    }
  }
]

				
			

Utilizando múltiplos Include e ThenInclude

Caso você precise carregar múltiplas entidade relacionadas, também é possível. Por exemplo, o código abaixo inclui as propriedades “Pagamento” e “Itens” do pedido:

				
					var pedidos = _context.Pedidos
                      .Include(p => p.Cliente)
                          .ThenInclude(c => c.Endereco)
                      .Include(p => p.Pagamento)
                      .Include(p => p.Itens)
                      .ToList();

				
			

Da mesma forma, se cada uma dessas propriedades de navegação possuir entidades relacionadas, basta utilizar o “ThenInclude” novamente:

				
					var pedidos = _context.Pedidos
                      .Include(p => p.Cliente)
                          .ThenInclude(c => c.Endereco)
                      .Include(p => p.Pagamento)
                          .ThenInclude(p => p.Parcelas)
                      .Include(p => p.Itens)
                           .ThenInclude(p => p.Produto)
                      .ToList();

				
			

Para incluir vários subníveis de relacionamento, basta usar o “ThenInclude” em cascata. Por exemplo, supondo que a classe “Endereco” possua uma propriedade “Pais”, ela pode ser incluída na consulta da seguinte forma:

				
					var pedidos = _context.Pedidos
                      .Include(p => p.Cliente)
                          .ThenInclude(c => c.Endereco)
                              .ThenInclude(e => e.Pais)
                      .ToList();

				
			

Já para o caso de uma mesma propriedade de navegação possuir mais de uma entidade relacionada, é necessário usar a sequência “Include+ThenInclude” repetidas vezes. Por exemplo, se o cliente possui uma propriedade “Contatos”, representando seus e-mails e telefones, ela pode ser incluída na consulta assim:

				
					var pedidos = _context.Pedidos
                      .Include(p => p.Cliente)
                          .ThenInclude(c => c.Endereco)
                      .Include(p => p.Cliente)
                          .ThenInclude(c => c.Contatos)
                      .ToList();

				
			

Acelere a sua carreira conosco!

Se você é Desenvolvedor .NET Júnior e quer acelerar sua carreira até nível Pleno com salário de R$7k+, ou mesmo busca a primeira vaga, conheça a Mentoria .NET StartClique aqui Se é Desenvolvedor .NET Pleno ou Sênior e quer virar referência técnica em sua equipe e mercado, com salário de R$10k+, conheça a Mentoria .NET ExpertClique aqui

Conclusão

Conhecer o funcionamento dos métodos “Include” e “ThenInclude” é fundamental para a manipulação eficaz de dados relacionados no Entity Framework. Partindo dos exemplos ilustrados neste artigo você pode aplicar essa técnica em seus projetos e construir consultas completas.