Entity Framework - Usando Lazy Load e Eager Load
Este série de artigos é dedicada ao Entity Framework e tem o objetivo de dar uma introdução básica e uma visão geral de como usar este importante recurso da plataforma .NET. Os artigos são parcialmente baseados na documentação da MSDN de onde são citadas as respectivas referências.
Iniciando com o Entity Framework
Conceito
A ADO .NET Entity Framework foi projetado para permitir que a criação de aplicações com acesso a dados use o modelo de programação feito contra um modelo conceitual ao invés do antigo modelo de programação feito diretamente contra um banco de dados relacional. O objetivo é diminuir a quantidade de código e o tempo de manutenção necessária exigida nestas aplicações orientada a dados.
A ADO .NET Entity Framework é uma framework que abstrai o esquema de um banco de dados relacional e o apresenta como um modelo conceitual. Abaixo a figura que representa a arquitetura em camadas do Entity Framework: (Até o lançamento do VS 2010)
Data Source
: Representa a base da arquitetura onde estão armazenados os dados;
Data Providers : Os dados são acessados por um ADO.NET data provider. Até o momento tanto o SQL Server como o MySQL são suportados e provavelmente em breve os principais RDBMS do mercado (Oracle, MySQL, DB2, Firebird, Sybase, VistaDB, SQLite, ...) terão um provider para o EF. Entity Data Model (EDM) : O Entity Data Model é constituído de 3 partes:
Entity Client : O EntityClient é um provedor gerenciado ADO.NET que suporta o acesso a dados descritos no EDM. Ele é similar ao SQLClient, e fornece diversos componentes como EntityCommand, EntityConnection e EntityTransaction; Object Services : Este componente permite realizar consultas, atualizações, inclusões e exclusões nos dados, expressados como objetos CLR fortemente tipados que são instâncias de entity types. Ele da suporte tanto a consultas Entity SQL como LINQ to Entities; Entity SQL (ESQL) : É uma derivação da Transact-SQL, projetada para consultar e manipular entidades definidas no EDM. Ele dá suporte herança e associação sendo que tanto os componentes Object Services como os componentes Entity Client podem executar instruções Entity SQL; LINQ to Entities : É
uma linguagem de consulta fortemente tipada para consultar entidades
definidas no EDM; |
Quando você esta aprendendo uma nova forma de tratar os dados através do mapeamento objeto relacional um ponto importante a considerar e saber como manipular os dados.
Existem duas formas básicas de manipular dados usando o Entity Framework, são elas:
Neste artigo eu vou tratar apenas da segunda opção.
Vamos começar criando um projeto e gerando um Entity Data Model:
Abra o Visual Studio 2008 com SP1 e crie um novo projeto do tipo WIndows Forms Application com o nome EF_ORM;
A seguir no menu Project selecione a opção Add New Item e em templates escolha ADO .NET Entity Data Model informando o nome Northwind.edmx;
Siga o assistente e selecione o item : Generate From Database e clique em Next>;
Ainda no assistente selecione a conexão com o banco de dados Northwind.mdf e aceite o nome padrão conforme a figura abaixo:
A seguir selecione as tabelas Employees, EmployeeTerritories e Territories , aceite nome padrão para o modelo e clique em Finish;
O modelo conceitual de entidades gerado no mapeamento será apresentado graficamente conforme figura abaixo:
Todo esse trabalho que tivemos foi necessário apenas para gerar o Entity Data Model que representa o modelo conceitual das nossas entidades. Vejamos agora como manipular as informações através desse modelo.
Vamos começar com a tarefa básica de acessar e obter dados.
No formulário padrão criado inclua um controle Combobox (cboEmployees) e um controle ListBox (lstTerritories). Veja abaixo leiaute do formulário como ficou:
Nosso objetivo será carregar o controle Combobox com os nomes dos empregados (Employees) e conforme um nome for selecionado vamos exibir os respectivos territórios relacionados no controle ListBox.
Agora vamos definir o código usado para acessar os dados usando o modelo de entidades. Primeiro vamos declarar a variável dc como sendo do tipo do container das entidades ou do tipo ObjectContext, isso irá permitir o acesso a todas as instâncias das entidades para o Entity Data Model criado:
No Entity Framework, instâncias de ObjectContext encapsulam a conexão com o banco de dados (EntityConnection), o metadados que descreve o modelo (MetadataWorkspace) e um gerenciador de objetos que rastreia alterações e mantém cache de objetos persistidos (ObjectStateManager). Cada objeto retornado por uma consulta seja usando LINQ to Entities ou Entity SQL será automaticamente anexado a um ObjectContext. |
Dim dc As NorthwindEntities
A seguir no evento Load do formulário vamos incluir o código que irá carregar o controle Combobox conforme abaixo:
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load dc = New NorthwindEntities Dim consulta = From emp In dc.Employees _ Select emp cboEmployees.DisplayMember = "FirstName" cboEmployees.ValueMember = "EmployeeID" cboEmployees.DataSource = consulta.ToList End Sub |
O código cria uma nova instância para o ObjectContext e efetua uma consulta retornando todos os objetos da entidade Employees;
Em seguida configuramos o controle Combobox para exibir o primeiro nome(FirstName) dos empregados retornados e tratar o valor selecionado pelo código do empregado (EmployeeID);
Agora vamos exibir os territórios relacionados com o empregado selecionado.
Para isso vamos usar o evento SelectedIndexChanged do controle Combobox de forma que feita uma seleção no controle o evento será disparado.
Neste evento temos que colocar o código que vai exibir os territórios do empregado. Veja abaixo como ficou este código:
Private Sub cboEmployees_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) _ Handles cboEmployees.SelectedIndexChanged Dim id As Integer = cboEmployees.SelectedValue Dim empregado = (From emp In dc.Employees _ Where emp.EmployeeID = id _ Select emp).First empregado.Territories.Load() lstTerritories.Items.Clear() For Each territorio In empregados.Territories lstTerritories.Items.Add(territorio.TerritoryDescription) Next End Sub |
Agora preste atenção neste código !!!
- Obtive o id referente ao código do empregado selecionado na combobox: Dim id As Integer = cboEmployees.SelectedValue
- Em seguida eu efetuei uma consulta que irá retornar um único objeto do tipo Employees com o código do empregado selecionado;
Dim consulta = (From emp In dc.Employees _
Where emp.EmployeeID = id _
Select emp).First
- Depois eu carrego os territórios para o objeto empregado selecionado: empregado.Territories.Load()
Temos aqui o que é conhecido como Lazy Load , ou em outras palavras : "se o programador não solicitar a carga, o relacionamento entre entidades não será recuperado."
Lazy Load é o mecanismo utilizado pelos frameworks de persistência para carregar informações sobre 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. É também conhecido como "lazy loading". |
Você pode comprovar que isso é verdade tentando contar o número de territórios para o cliente selecionado antes de chamar o Load para o objeto empregado:
lstTerritories.Items.Add(empregado.Territories.Count)
O resultado apontado será sempre zero.
Logo o Entity Framework nesta versão não suporta o Lazy Loading, para isso temos que chamar o Load para o objeto.
Você pode verificar se uma coleção de objetos está carregada utilizando a propriedade : “IsLoaded”. Para o nosso exemplo ficaria assim:
If (Not
empregado.Territories.IsLoaded)
Then empregado.Territories.Load() End If |
Finalmente percorremos cada objeto territorio para o objeto empregado e exibimos o nome do território:
For Each territorio In empregados.Territories
lstTerritories.Items.Add(territorio.TerritoryDescription)
Next
O resultado pode ser visto na tela a seguir:
Uma outra forma de obter o mesmo resultado seria usar o que é conhecido como Eager Load.
Eager Load é o mecanismo pelo qual uma associação, coleção ou atributo é carregado imediatamente quando o objeto principal é carregado. |
No Entity Framework o eager load é obtido explicitamente por meio da função Include.
Para o nosso exemplo o código ficaria assim:
Private Sub cboEmployees_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) _ Handles cboEmployees.SelectedIndexChanged Dim id As Integer = cboEmployees.SelectedValue Dim empregado = (From emp In dc.Employees.Include("Territories") _ Where emp.EmployeeID = id _ Select emp).First lstTerritories.Items.Clear() lstTerritories.Items.Add(empregado.Territories.Count) For Each territorio In empregado.Territories lstTerritories.Items.Add(territorio.TerritoryDescription) Next End Sub
|
Neste exemplo a coleção de objetos Territories é carregado em um único SELECT através da função Include :
Dim empregado = (From emp In dc.Employees.Include("Territories") _ Where emp.EmployeeID = id _ Select emp).First
No eager load é preciso informar o caminho completo das associações que você deseja recuperar caso contrário os objetos não serão carregados.
Nota:
Não é o caso do nosso exemplo mas se tivéssemos gerado o modelo completo
para o banco de dados Northwind para carregar as regiões usando o eager
load faríamos assim :
Dim empregado = (From
emp In dc.Employees.Include("Territories.Region") _ |
Considere isso quando você pretender usar eager load explicitamente.
Pegue o projeto completo aqui: EF_ORM.zip
Eu sei é apenas Entity Framework mas eu gosto...
Referências:
José Carlos Macoratti