Entity Framework 4.0 - Opções de Carga de dados (Lazy/Eager Loading)


A nova versão do Visual Studio, o Visual Studio 2010, lançado no final de abril trouxe dentre muitas novidades a tão esperada versão do Entity Framework, que passou a ser identificada como Entity Framework 4.0.

Segue abaixo um resumo das principais novidades desta versão do Entity Framework:

  • Persistence Ignorance - A Persistence Ignorance significa que podemos definir uma camada de domínio que contém entidades que são independentes do mecanismo de persistência usado. O EF4 agora permite que definimos nossos próprios POCO (Plain Old CLR Object), que são desacoplados de qualquer persistência específica. (O NHibernate já oferecia este recurso.)
  • T4 Code Generation - (Text Template Transformation ToolKit) é um modelo para gerar código que você pode usar para gerar código no EF4. Foram incluídos diversos modelos T4 para POCO (estão disponíveis junto a opção Add Code Generation item...)
  • Lazy Loading - Lazy Loading é o mecanismo utilizado pelos frameworks de persistência para carregar informações sobre demanda. Agora o EF4 da suporte a este recurso. Na versão anterior você tinha que usar o include explicitamente para realizar o lazy loading.
  • Model-First development - O Model-First permite a geração do banco de dados a partir do modelo de entidades no próprio Visual Studio.
  • Essas novidades tornaram a utilização do EF4 mais fácil e aproximando-o mais do seu concorrente mais famoso o NHibernate.

    Neste artigo vou mostrar algumas opções que temos para acessar e carregados.

    Nosso ponto de partida será mostrar como gerar o modelo de entidades usando o Entity Data Model (EDM) e a seguir usar o modelo gerado para realizar as operações com a fonte de dados.

    Criando o modelo de entidades - Entity Data Model (EDM)

    O objetivo da ADO .NET Entity Framework é mais ambicioso; o serviço OR/M seria apenas mais um serviço e outros serviços como relatórios, sincronização, backup, etc. também seriam oferecidos; para cobrir todos estes serviços foi criado um modelo de dados que é similar ao usado no paradigma orientado a objetos que o desenvolvedor utiliza, e também é independente de qualquer linguagem ou plataforma.

    Este modelo de dados é conhecido como Entity Data Model (EDM) ou modelo de entidades de dados e pode ser considerado o coração da do Entity Framework.

    O EDM é um modelo entidades-relacionamentos onde :
    • Entidades - são instâncias de tipos de entidades como Clientes, Produtos os quais estão estruturados em registros e chaves;
    • Relacionamentos - são instâncias de tipos de relacionamentos que são associações entre duas ou mais tipos de entidades;

    É a partir do modelo de entidades que podemos escrever código usando as diferentes APIs , como o provedor EntityClient ou o Object Services com LINQ to Entities.

    O Visual Studio oferece um assistente para a criação do EDM a partir do seu banco de dados ou do seu modelo de entidades.

    Para criar um EDM a partir de um banco de dados relacional podemos usar o Visual Studio 2010, o VB 2010 Express Edition ou o Visual C# 2010 Express Edition.

    Após criar um projeto Windows Forms, Web Application, WPF Application, etc. e a seguir clique com o botão direito sobre o nome do projeto e selecione Add -> New Item e na janela Add New Item selecione Data -> ADO .NET Entity Data Model e informe o nome Northwind.edmx pois vamos gerar o modelo de entidades a partir do banco de dados Northwind.mdf;

    O assistente irá apresentar a tela do Entity Data Model Wizard onde temos as opções de gerar o modelo a partir do banco de dados ou de um modelo vazio;

    Vamos gerar o modelo a partir do banco de dados Northwind.mdf portanto selecione o item Generate from database e clique em Next>;

    O assistente irá apresenta a janela para você escolher a conexão. Definindo a conexão para o Northwind.mdf vemos a string de conexão da entidade e nome com a qual ela será salva no arquivo App.Config;

    Na próxima janela vamos escolher quais tabelas do banco de dados irão fazer parte do modelo de entidades e para as quais será gerado o mapeamento objeto relacional;

    Eu vou selecionar apenas as tabelas Categories e Products para fica mais fácil visualizar o modelo;

    Ao final será gerado o arquivo Northwind.edmx que representa o modelo de entidades. No descritor podemos ver as entidades, o mapeamento gerado pelo EF4;

     

    Com isso estamos prontos para usar o modelo de entidades gerado.

    Trabalhando com o EDM gerado

    Agora que o temos o EDM gerado podemos acessar os dados de forma bem simples pois o EF gerou as entidades e todo o mapeamento com as tabelas do banco de dados criando um contexto a partir do qual temos os métodos para acessar, editar e excluir as informações das entidades persistindo-as no banco de dados.

    Com isso você não vai precisar mais usar os objetos ADO .NET para abrir e fechar conexões nem acessar os dados nem com comandos SQL para realizar as tarefas básicas de manutenção de dados.

    A partir deste momento você tem acesso ao modelo de entidades e pode realizar consultas usando o LINQ to Entities obtendo listas de objetos e objetos e usando uma sintaxe bem mais próxima da linguagem de alto nível que estamos usando.

    EF - Carregando dados com Lazy/Eager Loading

    Se estamos trabalhando com uma fonte de dados relacional usando Entity Framework 4 mais cedo ou mais tarde teremos que carregar os dados para exibição e/ou manutenção.

    Veremos algumas opções que temos usando o EF4 para carregar dados baseado no EDM que geramos no início do artigo.

    Apenas para recordar vou repassar conceitos de Lazy Loading e Eager Loading que serão usados no artigo:

    Lazy Loading - é o mecanismo utilizado pelos frameworks de persistência para carregar informações sob demanda. Esse mecanismo torna as entidades mais leves, pois suas associações são carregadas apenas no momento em que o método que disponibiliza o dado associativo é chamado. Assim quando objetos são retornados por uma consulta, os objetos relacionados não são carregados ao mesmo tempo, ao invés, eles são carregados automaticamente quando a propriedade de navegação for acessada. 

    Eager Loading - é o mecanismo pelo qual uma associação, coleção ou atributo é carregado imediatamente quando o objeto principal é carregado. Dessa forma todas as relações de uma entidade serão carregadas no mesmo momento em que esta entidade é carregada. É o contrário do Lazy Loading.

    1- Carregando dados usando Lazy Loading ativado (padrão)

    Eu vou usar o Visual Basic 2010 Express Edition e criar uma aplicação Windows Forms Application com o nome EF4_CarregaDados;

    No formulário form1.vb do projeto vamos incluir um controle Button(id=btnCarregar) e um controle ListBox(id=lstDados) conforme o leiaute abaixo:

    Nosso objetivo será exibir os produtos por categorias no controle ListBox(lstDados).

    Para isso vamos incluir o código a seguir no evento Click do botão Carregar Dados:

      Private Sub btnCarregar_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnCarregar.Click
            'lazy loading esta ativo
            Using ctx = New NORTHWNDEntities
    
                Dim categorias = From c In ctx.Categories Select c
    
                For Each cat In categorias
                    lstDados.Items.Add("Categoria : " & cat.CategoryName & vbCrLf)
                    lstDados.Items.Add("Produtos: Código / Nome ")
    
                    For Each prod In cat.Products
                        lstDados.Items.Add(prod.ProductID & " - " & prod.ProductName)
                    Next
    
                Next
            End Using
    
        End Sub

    Usando o contexto criado pelo EDM estamos obtendo as categorias existentes: Dim categorias = From c In ctx.Categories Select c

    A seguir usando um laço for/each percorremos as categorias e listamos o seu nome : lstDados.Items.Add("Categoria : " & cat.CategoryName & vbCrLf)

    Em outro laço for/each verificamos cada produto existente na categoria atual e o exibimos o ListBox: lstDados.Items.Add(prod.ProductID & " - " & prod.ProductName)

    Executando o projeto iremos obter:

    Neste cenário estamos usando o lazy loading (que esta ativo por padrão).

    - Podemos usar esta opção quando tivermos uma situação de navegação por paginação de dados e somente quando o usuário requisitar pois envolve múltiplas chamadas;
    - Quando for preciso passar informações entre camadas não devemos usar esta opção pois não teremos um contexto ativo aberto.

    2- Carregando dados usando Lazy Loading desabilitado

    Neste cenário vamos controlar o Lazy Loading carregando os dados somente quando requerido.

    Para fazer isso vamos desativar o Lazy Loading e fazer a chamada a ele de forma explicita.

    Vamos incluir outro controle Button (id=btnCarregar2) - Carregar Dados -Lazy Loading Inativo - e no seu evento Click incluir o seguinte código:

        Private Sub btnCarregar2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnCarregar2.Click
    
            Using ctx = New NORTHWNDEntities
    
                'desativando o lazy loading
                ctx.ContextOptions.LazyLoadingEnabled = False
    
                Dim categorias = From c In ctx.Categories Select c
    
                For Each cat In categorias
    
                    lstDados.Items.Add("Categoria : " & cat.CategoryName & vbCrLf)
                    lstDados.Items.Add("Produtos: Código / Nome ")
    
                    'carregando os produtos da categoria 
                    If 1 = 1 Then
                        cat.Products.Load()
                    End If
    
                    For Each prod In cat.Products
                        lstDados.Items.Add(prod.ProductID & " - " & prod.ProductName)
                    Next
                Next
            End Using
        End Sub

    Observe que estamos desativando o Lazy Loading => ctx.ContextOptions.LazyLoadingEnabled = False

    E que estamos fazendo a carga dos produtos explicitamente :

    If 1 = 1 Then
          cat.Products.Load()
    End If

    Se não fizermos isso , somente as categorias serão carregadas e o resultado será o seguinte:

    Neste cenário estamos controlando o número de chamadas com base na necessidade da aplicação usando um condição.

    3- Carregando dados com Eager Loading

    Se desabilitarmos o Lazy Loading conforme o cenário acima e precisarmos obter todos os dados disponíveis na memória teremos que usar método Include(entidade) para obter os dados;

    Vamos incluir outro controle Button (id=btnCarregar3) - Carregar Dados - Eager Loading- e no seu evento Click incluir o seguinte código:

     Private Sub btnCarregar3_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnCarregar3.Click
    
            Using ctx = New NORTHWNDEntities
    
                'desativando o lazy loading
                ctx.ContextOptions.LazyLoadingEnabled = False
    
                 'usando o método Include para carregar os produtos relacionados 
                Dim categorias = From c In ctx.Categories.Include("Products") Select c
    
                For Each cat In categorias
    
                    lstDados.Items.Add("Categoria : " & cat.CategoryName & vbCrLf)
                    lstDados.Items.Add("Produtos: Código / Nome ")
    
                    For Each prod In cat.Products
                        lstDados.Items.Add(prod.ProductID & " - " & prod.ProductName)
                    Next
                Next
            End Using
        End Sub

    Observe que estamos desativando o Lazy Loading => ctx.ContextOptions.LazyLoadingEnabled = False

    E que estamos fazendo a carga dos produtos relacionados com a categoria usando o método Include:

    Dim categorias = From c In ctx.Categories.Include("Products") Select c

    Executando o projeto iremos obter o seguinte resultado:

    Neste cenário estamos obtendo todas as categorias e os produtos em uma única consulta.

    Isto é necessário quando estamos passando informações entre camadas.

    Esta opção reduz o número de chamadas mas pode carregar uma grande quantidade de dados e pode ser crítico se houver pouca memória.

    Também podemos combinar as opções que foram vistas no artigo, e assim usar Lazy Loading e o método Include dependendo do cenário.

    Simples, simples assim...

    Pegue os projetos completos aqui: EF4_CarregaDados.zip

    Eu sei é apenas Entity Framework 4, mas eu gosto...

    Referências:

    José Carlos Macoratti