Uso de Include em consultas com o Entity Framework Code First

Um tópico muito discutido nos fóruns de acesso a dados (http://social.msdn.microsoft.com/Forums/pt-BR/adoptpt/threads) e LINQ (http://social.msdn.microsoft.com/Forums/pt-BR/linqpt/threads) é o uso de Lazy Load no Entity Framework.

O Lazy Load (ou Lazy Loading) nada mais é do que um mecanismo adotado pelos frameworks de persistência a dados para carregar as informações sobre demanda, isto é, carregar em memória apenas os dados de propriedades que não sejam relacionamentos para outras entidades. Este tipo de recurso minimiza o consumo de memória, o trafego de dados pela rede e os recursos de consulta do banco de dados, além de tornar a consulta mais rápida.

Vamos tomar como exemplo o seguinte cenário: uma construtora possui diversos prédios. Este é um relacionamento bastante simples de um para muitos, onde a construtora (um) possui diversos prédios (muitos) associados. Para esta implementação utilizaremos o Entity Framework Code First versão 5 Beta. Para instalar esta versão rode o comando “Install-Package EntityFramework -Pre” em seu Package Manager Console (http://nuget.org/packages/EntityFramework).

Após instalado, crie em seu projeto as seguintes classes conforme o código abaixo:

public class Construtora {
    public int Id { get; set; }

    public string Nome { get; set; }

    public string RegistroCivil { get; set; }

    public List<Predio> Predios { get; set; }

    public Construtora()
    {
        this.Predios = new List<Predio>();
    }
}

public class Predio {
    public int Id { get; set; }

    public string Nome { get; set; }

    public Endereco Endereco { get; set; }
}

[ComplexType()]
public class Endereco {
    public string Logradouro { get; set; }

    public string Numero { get; set; }

    public string Bairro { get; set; }

    public string Cidade { get; set; }

    public string CEP { get; set; }
}

As classes Construtora, Predio e Endereco são auto-explicativas e representam a abstração da essência do problema discutido.

Como previsto, para utilização do Entity Framework Code First precisamos criar uma classe que seja nosso proxy de comunicação com o banco de dados (contexto de banco de dados). Esta classe pode ser criada como a classe Contexto descrita logo abaixo:

public class Contexto : DbContext
{
    public DbSet<Predio> Predios { get; set; }

    public DbSet<Construtora> Construtoras { get; set; }
}

Veja que em nossa classe de contexto (Data Context) não fizemos nenhuma configuração adicional e apenas registramos as entidades que devem ser persistidas na base de dados.

Para realizar os testes com o uso de Lazy Load fiz a inclusão de alguns registros com o seguinte script:

Construtora construtoraA = new Construtora();
construtoraA.Nome = "Construtora A";
construtoraA.RegistroCivil = "22.22.2222-2";
construtoraA.Predios.Add(new Predio() { Nome = "Prédio 01", 
                                        Endereco = new Endereco() });
construtoraA.Predios.Add(new Predio() { Nome = "Prédio 02", 
                                        Endereco = new Endereco() });
construtoraA.Predios.Add(new Predio() { Nome = "Prédio 03", 
                                        Endereco = new Endereco() });

using (Contexto db = new Contexto())
{
    db.Construtoras.Add(construtoraA);
    db.SaveChanges();
}

Agora que existem alguns registros na base de dados vamos fazer uma consulta e verificar como os nossos dados são retornados, para isso podemos utilizar uma sintaxe Lambda ou uma sintaxe LINQ como a seguir:

// Lambda using (Contexto db = new Contexto()) 
{                
    var x = db.Construtoras
                    .Where(c => c.Id > 0);
}
// LINQ using (Contexto db = new Contexto())
{
    var x = from c in db.Construtoras
            select c;
}

O resultado da consulta foi o seguinte:

lazyLoad01

Podemos perceber que mesmo inserindo dados para a propriedade “Predios”, da classe “Construtora”, não obtivemos nenhum registro como resultado de nossa consulta, tanto que durante o debug da aplicação podemos notar a quantidade de 0 registros associados a instância de construtora. Tudo isso por conta do Lazy Load.

Agora, faremos diferente… Vamos forçar o carregamento dos registros associados com as entidades resultantes de nossa consulta que não foram carregados por conta do Lazy Load do Entity Framework. Neste ponto entra em destaque o método Include, que é o responsável pelo carregamento de registros associados as entidades de nossas consultas. Para que tudo funcione corretamente faça referência ao namespace System.Data.Entity. Nosso script de consulta deve ficar como:

// Lambda using (Contexto db = new Contexto()) 
{                
    var x = db.Construtoras
                    .Include(c => c.Predios)
                    .Where(c => c.Id > 0);
}
// LINQ using (Contexto db = new Contexto())
{
    var x = from c in db.Construtoras.Include(c => c.Predios)
            select c;
}

O resultado da segunda consulta foi este:

lazyLoad02

Podemos notar que por conta do uso do método Include conseguimos fazer o carregamento das demais instâncias de registros associados com nosso escopo de consulta. O recurso de Lazy Load é bastante útil e favorece a construção de consultas mais leves, que consumam menos recursos e sejam mais rápidas.

Fica a dica!

Por
Fernando Henrique Inocêncio Borba Ferreira
Microsoft Most Valuable Professional – Data Platform Development

Publicidade

9 comentários sobre “Uso de Include em consultas com o Entity Framework Code First

  1. Olá, eu senti dificuldade na explicação da arquitetura. Quem está aprendendo isso precisa entender a arquitetura do projeto: Exemplo: Teremos o projeto chamado: DAL onde ficara o edmx, teremos o objeto BE onde ficaram nossas entidades code first.. e assim por diante….

  2. Fernando, muito bacana. Porém surgiu uma duvida. Se uma view fortemente tipada precisa-se de uma coleção de prédios (View(db.Construtoras.Include(“Predio”).Where(c => c.Id > 0))). Mas, caso na view eu precise fazer model.Endereco.Nome por exemplo. Nesse caso o predio tem relacionamento com endereco que não foi incluida. E seu fizesse Construtoras.Include(“Predio”).Include(“Endereco”) daria erro pois Construtora não tem relacionamento com Endereco. Como fazer nesses casos?

    • Olá Anderson,
      Nesse caso vc deve fazer algo como:
      (View(db.Construtoras.Include(“Predio”).Include(“Predio.Endereco”).Where(c => c.Id > 0))).

      Obrigado por postar.
      []s!

  3. Fernando, me ajudou muito mas tive uma dúvida de como adaptar ao que quero fazer.

    public ActionResult Details3(long id)
    {

    var rdm = from c in db.tbRDM.Include(c => c.tbAtividades)
    select c;

    return View(rdm);
    }

    quando coloco pra retornar a view, ele diz que estou passando um IQueryable mas preciso passar um objeto tbRDM, que é minha model. Como eu poderia fazer?

    • Olá Jonatas, tudo beleza?
      Como este é o método Details ele espera apenas um item, ao invés de uma coleção de registros. Acredito que vc deva fazer algo como:

      public ActionResult Details3(long id)
      {

      var rdm = (from c in db.tbRDM.Include(c => c.tbAtividades) where c.Id == id select c).FirstOrDefault();

      return View(rdm);
      }

      Espero que ajude.

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair /  Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair /  Alterar )

Conectando a %s

Este site utiliza o Akismet para reduzir spam. Saiba como seus dados em comentários são processados.