Desenvolvimento - ADO.NET

Entity Framework 4: Descobrindo o ADO.NET

Com este artigo podemos notar que o ADO.NET Entity Framework, apesar de ser um framework novo, já está bem mais robusto nesta nova versão, recebeu várias atualizações importantes e ainda receberá muito mais.

por André Baltieri



É normal no desenvolvimento de aplicações (Windows, Web, Mobile e etc) dirigirmos todo o nosso foco para a fonte de dados. Normalmente temos um banco de dados revisado, estruturado e pronto para ser consumido, sendo assim, nossa principal missão é fazer com que a aplicação acesse estes dados, manipule-os da forma desejada e se necessário devolva-os ao banco.

Nota: Chamamos este desenvolvimento de Database-First development.

Por outro lado, existe também um cenário cujo o desenvolvimento e o banco de dados são feitos sobre o diagrama de classes. Neste caso, temos ferramentas que automaticamente convertem nosso diagrama para as classes da aplicação.

Nota: Chamamos este desenvolvimento de Model-First development.

O ADO.NET Entity Framework é a nova plataforma de acesso a dados desenvolvida pela Microsoft e primeiramente incorporado no Service Pack 1 do Visual Studio 2008 e .NET Framework 3.5. A Microsoft desde então, tem investido bastante neste poderoso Framework, e atualizações constantes andam sendo feitas.

Mas por que uma nova plataforma de acesso a dados, se tínhamos os DataSets, DataReaders que já estão testados e funcionando a tempo? Talvez o principal benefício seja sua alta produtividade, visando que você não precisa se preocupar com o seu modelo de dados, tudo será gerado a partir de ferramentas integradas no Visual Studio. Os modelos gerados possuem entidades que representam as tabelas do seu banco de dados, sendo assim, trabalhamos de forma orientada à objetos. Resumidamente, todo controle de acesso ao banco, modelo conceitual de regras de negócio é feito pelo EF.

Características do ADO.NET Entity Framework 4.0

Nota: Esta sessão demonstra as novidades adicionadas ao ADO.NET Entity Framework 4.0, caso necessário, recorra a mesma mais tarde, quando estiver mais integrado com a plataforma.

  • Persistence Ignorance - Permite a definição do seu próprio POCO (Plain Old CLR Object), que são desacoplados de qualquer persistência específica.
  • T4 Code Generation - Foram adicionados vários T4 Code Generation templates, cujo podem ser alterados de acordo com as necessidades do projeto.
  • Lazy Loading - Com esta adição, podemos com simples comandos fazer com que um objeto pai, carregue automaticamente seus objetos filhos. Exemplo: Podemos carregar um pedido e automaticamente os itens do pedido serão carregados.
  • POCO Change-Tracking - Foram adicionados dois modelos para rastrear mudanças nos POCOs. Por padrão, o EF tira um snapshot do estado original do objeto e então compara com o novo estado, quando salvando as alterações. No outro caso, podemos definir as propriedades como Virtual para que o estado possa ser rastreado continuamente e mantido em sincronia com o Object State Manager.
  • Melhorias no suporte a aplicações N-tier com entidades Self-Tracking - Inclusão de templates T4 para geração de entidades que rastreiam suas próprias mudanças no cliente, que são serializadas e salvas na base de dados.
  • Model-First development - Neste modo, pode-se criar diretamente o modelo de entidades dentro do Visual Studio e exportá-lo para um script SQL que gerará o banco de dados.
  • Code-Only development - Neste modo, primeiro escreve-se o código, em seguida o modelo e banco de dados são gerados.

Aplicação do ADO.NET Entity Framework no cenário de Web Services

Em grandes corporações é fato que encontraremos vários tipos de aplicações distintas, uma em C#, outra em Delphi, Java e assim por diante. Sendo assim, cada vez mais o conceito de serviços vem sendo utilizado, de forma que podemos integrar aplicações expondo e consumindo serviços.

O ADO.NET Entity Framework também pode ser utilizado neste cenário, interagindo perfeitamente com Web Services e o WCF (Windows Communication Foundation).

Entity Data Model

O EDM (Entity Data Model) é um conceito que no EF foi implementado de forma que nos trouxe muita produtividade. Quando falamos em modelo de entidades de dados, nos referimos aos arquivos .edmx, que armazenam as informações de mapeamento de cada entidade para sua tabela na fonte de dados. Este conjunto de entidades e relacionamentos são o que chamamos de Entity Data Model.

Ainda no EDM, temos duas propriedades importantes, EntityContainerName e seu Namespace, que é utilizado para que suas entidades possam ser acessadas.

Criando um Entity Data Model

Nota: Para este trecho do artigo, serão utilizados o Visual Studio 2010, SQL Server 2008 Express e o banco de dados Northwind. Ao final deste artigo você poderá encontrar os mesmos para download.

Com o Visual Studio 2010 aberto, clique com o botão direito do mouse sobre o projeto (Ou pasta onde desejar criar o modelo) e em seguida acesse a opção Add e New Item, como mostrado na Figura 1.


Figura 1 - Adicionando um novo Entity Data Model

Na janela que se abre, selecione a opção Data no painel a esquerda, e em seguida selecione o item ADO.NET Entity Data Model no painel central. Nomeie o arquivo como desejar e por fim, clique sobre a opção Add, como mostrado na Figura 2.


Figura 2 - Adicionando um item do tipo ADO.NET Entity Data Model.

Sendo assim, o Wizard para criação do EDM aparecerá, contendo duas opções:

  • Generate From Datebase - Gera o EDM baseado em uma fonte de dados, mapeando as tabelas para suas respectivas entidades.
  • Empty Data Model - Cria um EDM vazio, onde será possível criar manualmente entidades.

Para este cenário, deixe a opção Generate from Database selecionada e clique sobre Next, como mostrado na Figura 3.


Figura 3 - Entity Data Model Wizard.

A tela sequente é uma tela conhecida, que é a tela de configuração da string de conexão a fonte de dados, a famosa Connection String. Apenas não se esqueça de marcar a opção Save entity connection strings in App.Config as: e nomeie a connection string como desejada, em seguida, clique em Next, como mostrado na Figura 4.


Figura 4 - Configurando a Connection String.

Na próxima tela, temos as informações mais importantes, primeiro temos a possibilidade de escolher se queremos trabalhar com Tabelas, Views e Stored Procedures. Para este exemplo selecione somente Tables. Seguindo em frente, temos a opção de pluralizar ou singularizar o nome dos objetos gerados, ou seja, se sua tabela chama Categoria, seu Entity Set se chamará Categorias. Por fim, temos o Namespace.

A Figura 5 ilustra as opções mencionadas anteriormente.


Figura 5 - Configurando os objetos a serem gerados.

Se tudo ocorreu certo, no final deste Wizard, teremos o seguinte modelo, como demonstrado na Figura 6.


Figura 6 - Modelo de entidades gerado pelo Wizard.

A partir deste momento, temos um diagrama, que pode ser manipulado visualmente inclusive.

A Figura 7 mostra as propriedades do arquivo .edmx, cujo as mais importantes são:

  • Code Generation Strategy -
  • Connection String -
  • Database Generation Workflow -
  • DDL Generation Template -
  • Entity Container Name - Nome do conjunto completo de entidades que foram geradas.
  • Namespace - Caminho lógico onde o conjunto de entidades está.


Figura 7 - Propriedades do arquivo .edmx.

A Figura 8 mostra as propriedades da entidade Customer, sendo as mais importantes:

  • Access - Tipo de acesso que a classe poderá receber.
  • EntitySet Name - Nome do conjunto de entidades.
  • Name - Nome da entidade.


Figura 8 - Propriedades da entidade.

Trabalhando com o EDM gerado

Com o EDM feito, podemos facilmente acessar dados, sem necessidade de muito hard-code e sem necessidade de ficar preocupando-se com abertura e fechamento de conexões com o banco de dados.

Além disso, o retorno de suas consultas resulta em um IQueryable, que pode ser facilmente percorrido por um foreach, atribuído a uma GridView e outros controles com suporte. Pode-se também filtrar a lista retornada de forma simples, utilizando LINQ.

Listando todos os registros de uma tabela (Select - Read)

Consultas a fonte de dados serão necessárias a todo momento, chamamos estas de seleções (Selects) que se encaixam nos métodos de leitura (Read) dentro do conceito de CRUD (Create, Read, Update e Delete), que são os métodos básicos (E muitas vezes essenciais) de uma entidade.

O código da Listagem 1ilustra como podemos percorrer de forma simples um conjunto de entidades e listá-los na tela.

01static void Main(string[] args)02{03    // Instancia o objeto que contém as entidades04    NorthwindEntities _db = new NorthwindEntities();05 06    // Percorre todos os customers07    foreach (Customer item in _db.Customers)08    {09        // Escreve o ContactName na tela10        Console.WriteLine(item.ContactName);11    }12 13    Console.ReadKey();14}

Listagem 1 - Percorrendo um conjunto de entidades e listando-os na tela.

Criando uma consulta simples com LINQ para filtrar registros

Outro ponto interessante, é que com LINQ podemos criar consultas de forma simples, como mostrado no Listagem 2.

01// Instancia o objeto que contém as entidades02NorthwindEntities _db = new NorthwindEntities();03 04// Utiliza LINQ para filtrar os clientes do Brasil05var customersInBrazil = (from c in _db.Customers where c.Country == "Brazil" select c);06 07Console.WriteLine("------------------- Customers in Brazil -------------------");08 09// Percorre os clientes do Brazil10foreach (Customer item in customersInBrazil)11{12    Console.WriteLine(item.ContactName);13}

Listagem 2 - Criando uma consulta simples com LINQ para listar os clientes do Brasil.

Alterando os dados de um registro

Na versão 4.0 do ADO.NET Entity Framewor, um novo método para atualização de registros fora adicionado. Trata-se do método ApplyApplyPropertyChanges(string entitySetName, object changed).

Este método possibilita que as atualizações sejam feitas simplesmente informando o nome do conjunto de entidades da qual a entidade a ser atualizada pertence e o próprio objeto a ser atualizado.

A Listagem 3 ilustra como uma atualização pode ser feita.

01// Instancia o objeto que contém as entidades02NorthwindEntities _db = new NorthwindEntities();03 04// Instancia um novo objeto do tipo Customer05Customer customer = new Customer();06// Seleciona o objeto a ser atualizado utilizando uma consulta com LINQ07customer = (from c in _db.Customers where c.CustomerID == "VAFFE" select c).First();08 09// Modifica o país do cliente10customer.Country = "Brazil";11 12// Aplica as modificações a entidade13_db.ApplyPropertyChanges("Customers", customer);14// Persiste o objeto (Salva as mudanças no banco)15_db.SaveChanges();

Listagem 3 - Alterando o país de um cliente.

Devemos observar dois detalhes nesse código, sendo o primeiro o método First() adicionado ao final da sintaxe do LINQ, e que tem a finalidade de retornar apenas o primeiro objeto (Tipado) da consulta. Isto evita que o retorno seja mais de 1 (Um) objeto, transformando-o em uma lista, sendo que o retorno esperado é um objeto do tipo Customer, não uma lista de Customer.

O outro detalhe é o método SaveChanges(), que deve ser chamado após cada atualização, inclusão ou remoção de entidades, pois só assim as atualizações feitas serão persistidas na fonte de dados.

Excluindo um registro

A exclusão de uma entidade é ainda mais fácil. Devemos apenas nos atentar a questão de relacionamentos em nossa fonte de dados, tendo em vista que alguns relacionamentos podem resultar na impossibilidade de exclusão de um registro.

A Listagem 4 ilustra como a exclusão de um registro pode ser feita.

1// Exclui o objeto do conjunto de entidades2_db.DeleteObject((from c in _db.Customers where c.CustomerID == "SIMOB" select c).First());3// Persiste o objeto (Salva as mudanças no banco)4_db.SaveChanges();

Listagem 4 - Excluindo um cliente.

Como previamente dito, algumas operações de exclusão de registro não serão possíveis pois podem conter registros relacionados a este em outras tabelas. Sendo assim, a seguinte excessão será gerada:

{"The DELETE statement conflicted with the REFERENCE constraint \"FK_Orders_Customers\". The conflict occurred in database \"Northwind\", table \"dbo.Orders\", column "CustomerID".\r\nThe statement has been terminated."}

Esta exceção informa que um conflito com a chave estrangeira FK_Orders_Customer foi encontrado. A Figura 9 mostra a imagem deste erro.


Figura 9 - Exceção gerada pelo limite da chave estrangeira ser excedido, resultando em um conflito.

Inserindo um registro no banco

Podemos incluir uma nova entidade a lista de entidades e persisti-la na fonte de dados de duas formas, sendo a primeira utilizando o método AddObject(string entitySetName, object entity) e a outra utilizando o método AddCustomer(object entity).

A diferença é que o primeiro método (AddObject) é mais genérico, e o nome do conjunto de entidades precisa ser informado. Já no segundo método (AddCustomer), é o método gerado para cada entidade. Pode-se notar também, que para cada entidade gerada, existe um método Add.

A Listagem 5 ilustra a adição de uma entidade das duas formas possíveis.

01// Cria e popula o novo cliente02Customer customerToBeAdd = new Customer();03customerToBeAdd.Address = "Rusk Street";04customerToBeAdd.City = "Houston";05customerToBeAdd.CompanyName = "THE Company";06customerToBeAdd.ContactName = "John Rock";07customerToBeAdd.ContactTitle = "Mr";08customerToBeAdd.Country = "United States";09customerToBeAdd.CustomerID = "JHNRK";10 11// Adiciona o cliente a lista de entidades12_db.AddToCustomers(customerToBeAdd);13// Esta é uma forma alternativa de se adicionar uma entidade14// _db.AddObject("Customers", customerToBeAdd);      15// Persiste o objeto (Salva as mudanças no banco)16_db.SaveChanges();

Listagem 5 - Adicionando um cliente.

Estas operações passadas acima cobrem boa parte das necessidades na utilização do EF, cabe agora estudar os meios alternativos necessários para cada projeto.

Atualizando o EDM quando a fonte de dados for atualizada

No decorrer dos projetos, mudanças no escopo são comuns. Como normalmente o banco de dados concentra regras, se as regras são alteradas, o banco de dados também é, sendo assim, temos que atualizar o modelo de entidades da aplicação.

O EF faz isso de forma simples e fácil, bastando apenas abrir o EDM, clicar com o botão direito do mouse no fundo da tela e selecionar a opção "Update model from database", como mostrado na Figura 10.


Figura 10 - Atualizando o modelo de entidades.

Trabalhando com Stored Procedures

Até o momento, tudo está ótimo, estamos modelando a partir das tabelas, ou das classe. Mas e quando temos Stored Procedures para fazer as ações no banco?

No CTP2 do Entity Framework 4 foi adicionado essa função, que permite delegar as ações a Stored Procedures. Para facilitar este exemplo, resolvi criar um banco de dados novo, com apenas uma tabela e suas Stored Procedures. Faça o download abaixo e execute os scripts.

Download dos Scripts para criação do banco de dados de teste e de suas Stored Procedures

Nota: Criei um novo projeto e repeti os passos para criação do arquivo EDM como mostrado acima, exceto pelo fato que na tela de seleção de objetos, selecionei também as Stored Procedures, como mostrado na Figura 11.


Figura 11 - Gerando objetos para Stored Procedures.

Após finalizar a criação do EDM, pode-se notar que nada de diferente acontece visualmente, porém, ao acessar os detalhes do mapeamento (Mapping Details), temos a opção de mapear a entidade selecionada para uma função, como mostrado na Figura 12, Figura 13 e Figura 14.


Figura 12 - Detalhes do Mapeamento.


Figura 13 - Adicionando uma função.


Figura 14 - Atribuindo uma Stored Procedures a uma função.

Agora temos a função INSERT (Método AddObject) da entidade Usuário delegada a uma Stored Procedure. Além disso, é importante notar a atribuição de valores aos parâmetros na Figura 13, que caso necessário podem ser alterados.

Para finalizar, vamos codificar a inserção de um novo usuário. A Listagem 6 aborda a criação de um novo usuário.

01static void Main(string[] args)02{03    // Cria a instância do conjunto de entidades04    EF_TESTEntities _db = new EF_TESTEntities();05             06    // Cria o novo usuário a ser inserido07    Usuario u = new Usuario();08    u.Nome = "André Baltieri";09    u.Email = "andre.baltieri@insidedotnet.com.br";10             11    // Insere o novo usuário e persiste12    _db.Usuarios.AddObject(u);13    _db.SaveChanges();14 15    // Lista todos os usuários cadastrados16    foreach (var item in _db.Usuarios)17    {18        Console.WriteLine("{0} - {1}", item.Nome, item.Email);19    }20    Console.ReadKey();21}

Listagem 6 - Inserindo um novo usuário utilizando Stored Procedures.

Se tudo ocorrer certo, o usuário inserido deve ser mostrado na tela, como na Figura 15.


Figura 15 - Listando os usuários inseridos.

Download do Código Fonte do exemplo

Model-First Development

Até o momento, basicamente tudo que fizemos foi sobre o modelo de dados que já estava definido, porém existem situações em que o banco de dados será gerado apartir do seu modelo de classes. Isto se chama Model-First development.

O Entity Framework também tem uma ferramenta para geração de código SQL, facilitando muito a geração do banco de dados. Vamos começar criando um novo arquivo EDM, clicando com o botão direito do mouse sobre o projeto e selecionando a opção Add > New, como mostrado na Figura 16.


Figura 16 - Adicionando um novo item a solução.

Sendo assim, uma nova janela se abrirá, selecione a opção Data no menu esquerda, a opção ADO.NET Entity Data Model na caixa central, nomeie o arquivo e clique em Next, como mostrado na Figura 17.


Figura 17 - Adicionando um novo ADO.NET Entity Data Model.

O próximo passo é criar o modelo. Como havíamos visto anteriormente, temos duas opções aqui, que são Generate from Database (Gerar do banco de dados) ou Empty (Vazio). Como o intuito é gerar o banco de dados a partir do nosso modelo, vamos iniciar um modelo vazio (Empty).

Sendo assim, selecione Empty e clique em Next, como mostrado na Figura 18.


Figura 18 - Gerando um novo arquivo EDM vazio.

Com o modelo gerado, podemos notar que não existe nenhuma entidade. O que devemos fazer agora é adicionar novas entidades.

Para adicionar uma nova entidade, basta clicar com o botão direito do mouse sobre o fundo da tela e selecionar as opções Add > Entity..., como mostrado na Figura 19.


Figura 19 - Adicionando uma nova entidade.

Neste ponto, uma nova janela, de configuração da entidade se abrirá. Dentre as opções mostradas, devemos nos atentar ao Entity Name, que é o nome da entidade, Entity Set que será o nome do conjunto destas entidades, Create Key Property, que é a criação automática da propriedade chave que utilizaremos para identificar unicamente nossa entidade, Property Name, que eu particularmente deixo como Id e por fim o Property Type, que particularmente deixo como int também.

A Figura 20 mostra este contexto.


Figura 20 - Configurando a entidade a ser criada.

Com a entidade criada, podemos adicionar mais propriedades, funções e até associações a entidade. Aqui irei demonstrar a criação de uma propriedade, utilizando a opção Scalar Property, como mostrado na Figura 21 e Figura 22


Figura 21 - Adicionando uma nova propriedade na entidade.


Figura 22 - Renomeando a propriedade adicionada.

Apenas com intuito de aprendizado, com a propriedade da entidade selecionada, podemos acessar suas propriedades na lateral direita do Visual Studio (Ou apertar F4), note que temos entre várias propriedades, o tipo (Type) da propriedade, que neste caso está definida como String.

Sempre que necessário, recorra a esta tela para alterar as propriedades necessárias.

A Figura 23 ilustra esta passagem.


Figura 23 - Alterando as propriedades da propriedade da entidade.

Com a entidade criada e as propriedades definidas, podemos então gerar o script para criação do banco de dados.

Novamente, vamos recorrer aos recursos do próprio EF, deixando para ele todo o trabalho de criação do hard code para gerar nosso banco (Ô menino bom...).

Para isto, basta clicar no fundo da tela (Desde que não seja sobre alguma entidade) com o botão direito do mouse e acessar a opção "Generate Database From Model", que o wizard para geração do código SQL se abrirá, como mostrado na Figura 24.


Figura 24 - Iniciando a criação do código SQL apartir do modelo.

Na primeira tela do wizard, temos a famosa connection string. Creio que esta tela seja familiar a todos. A Figura 25 ilustra a tela.


Figura 25 - Tela para gerar a connection string.

Em seguida, o código SQL a ser gerado será apresentado. Ele mostrará o nome do arquivo a ser salvo e todo o código, que eu particularmente nunca precisei alterar.

A Figura 26 ilustra esta passagem.


Figura 26 - Código SQL a ser gerado.

Após gerar o arquivo, o mesmo será aberto dentro do Visual Studio, porém este ainda não foi executado.

O próprio Visual Studio tem a opção de executar este código, sem a necessidade de ter o SQL Server Management Studio ou outra ferramenta.

Para isto, basta clicar com o botão direito do mouse sobre o código gerado e acessar a opção "Execute SQL" ou CTRL+SHIFT+E, como mostrado na Figura 27.


Figura 27 - Executando o código SQL gerado a partir do Visual Studio.

Uma tela do SQL Server se abrirá, informe as credenciais necessárias, como mostrado na Figura 28.


Figura 28 - Conectando-se ao SQL Server.

Se tudo ocorreu certo, ao final da execução, a mensagem "Command(s) completed succesfully" será informada, como na Figura 29.


Figura 29 - Scripts executados com sucesso.

Apenas com intuito de demonstrar que o script realmente rodou, no SQL Server podemos ver a tabela que foi gerada, como na Figura 30.


Figura 30 - Tabela gerada pelo Script.

Até este ponto, temos a entidade gerada, e o banco de dados com a tabela gerada, mas e quanto a ligação (Relação) entre a entidade e a tabela? Terá que ser feita manualmente?

A resposta é NÃO. O próprio EF é inteligente o bastante para identificar que a tabela agora existe e como foi gerada a partir do modelo, tem um vínculo com alguma entidade.

A Figura 31 mostra novamente as propriedades da Entidade, agora relacionada com a tabela.


Figura 31 - Entidade já mapeada para a tabela.

Com nosso modelo/base de dados certos, vamos a codificação. A Listagem 7 ilustra a criação e listagem de uma empresa utilizando o modelo que criamos.

01static void Main(string[] args)02{03    // Instancia o modelo de entidades04    MyEmptyDataModelContainer _db = new MyEmptyDataModelContainer();05 06    // Cria uma nova empresa07    Empresa emp = new Empresa();08    emp.Nome = "Inside .NET";09 10    // Insere a empresa e salva as mudanças11    _db.Empresas.AddObject(emp);12    _db.SaveChanges();13 14    // Lista todas as empresas cadastradas15    foreach (var item in _db.Empresas)16    {17        Console.WriteLine("{0} - {1}", item.Id, item.Nome);18    }19 20    Console.ReadKey();21}

Listagem 7 - Inserindo e listando uma nova empresa.

Se tudo ocorrer certo, a empresa registrada deve ser mostrada, como na Figura 32.


Figura 32 - Listando as empresas cadastradas.

Para fazer o download do código fonte deste exemplo, clique no link abaixo:

Download do Exemplo

Lazy Load

Lazy Load é uma técnica cujo deixamos para carregar os objetos "filhos" de um objeto "pai" apenas quando necessário. Esta opção vem por padrão habilitada no EF, e pode ser modificada através do atributo ContextOptions.LazyLoadingEnabled.

Se tomarmos como exemplo uma empresa, que tem vários funcionários e cada funcionário possui vários dependentes, podemos facilmente visualizar como o LazyLoad funciona. Supondo que carregamos todas as empresas cadastradas, neste momento, ainda NÃO TEMOS os funcionários e seus dependentes carregados. Em seguida então carregamos os funcionários, e ainda NÃO TEMOS os dependentes carregados. Resumindo, os conjuntos de objetos filhos serão carregados sob demanda.

Lazy Load é uma ótima aplicação para quando se tem uma grande quantidade de objetos filhos, tendo em vista que estes só serão carregados quando necessário, mas novamente, varia muito de projeto para projeto, o importante é saber como a funcionalidade se comporta, e depois cabe a cada um decidir onde utilizar.

A Listagem 8 demonstra um exemplo utilizando o Lazy Load.

01static void Main(string[] args)02{03    // Instancia as entidades04    LazyLoadTestsEntities _db = new LazyLoadTestsEntities();05    // Habilita a opção LazyLoad (Por padrão já vem habilitada)06    _db.ContextOptions.LazyLoadingEnabled = true;07 08    // Percorre todas as empresas09    foreach (var item in _db.Empresas)10    {11        // Escreve o nome da empresa na tela12        Console.WriteLine("Empresa: {0}", item.Nome);13 14        // Percorre todos os funcionários da empresa15        foreach (var func in item.Funcionarios) // Somente aqui os funcionários foram carregados16        {17            // Escreve o nome do funcionário an tela18            Console.WriteLine("\tFuncionário: {0}", func.Nome);19 20            // Percorre todos os dependentes dos funcionários21            foreach (var dep in func.Dependentes) // Somente aqui os dependentes foram carregados22            {23                // Escreve o nome do dependente na tela24                Console.WriteLine("\t\tDependente: {0}", dep.Nome);25            }26        }27        Console.WriteLine("---------------------------------------");28    }29 30    Console.ReadKey();31}

Listagem 8 - Exemplo de LazyLoad.

A Listagem 9 demonstra de uma forma simplificada o Lazy Load.

01static void Main(string[] args)02{03    // Instancia as entidades04    LazyLoadTestsEntities _db = new LazyLoadTestsEntities();05    // Habilita a opção LazyLoad (Por padrão já vem habilitada)06    _db.ContextOptions.LazyLoadingEnabled = true;07 08    Console.WriteLine(_db.Empresas.First()); // Funcionários ainda não foram carregados09    Console.WriteLine(_db.Empresas.First().Funcionarios.First().Nome); // Funcionários foram carregados; Dependentes ainda não10 11    Console.ReadKey();12}

Listagem 9 - Exemplo simplificado de LazyLoad.

Eager Load

Eager Load é basicamente o contrário do Lazy Load. Enquanto o Lazy Load carrega sob demanda os objetos, o Eager Load carrega tudo que lhe for informado, através do comando Include(). Uma aplicação prática para o Eager Load seria por exemplo a necessidade de carregar um objeto que possua poucos (Ou apenas 1) objeto filho.

A Listagem 10 exemplifica o uso de Eager Load.

01static void Main(string[] args)02{03    // Instancia as entidades04    LazyLoadTestsEntities _db = new LazyLoadTestsEntities();05    // Desabilita a opção LazyLoad (Por padrão já vem habilitada)06    _db.ContextOptions.LazyLoadingEnabled = false;07 08 09    foreach (var item in _db.Dependentes.Include("Funcionario"))10    {11        Console.WriteLine("Dependente: {0}", item.Nome);12        Console.WriteLine("Funcionário: {0}", item.Funcionario.Nome);13        Console.WriteLine("---------------------------------------");14    }            15 16    Console.ReadKey();17}

Listagem 10 - Exemplo de Eager Load.

Plain Old CLR(Common Language Runtime) Objects - POCO

POCOs são classes que não dependem de componentes externos ou seja, ela é criada somente com o que temos no .NET Framework. Este conceito de POCO vem do Java, onde estes mesmos objetos chama-se POJOs (Plain Old Java Objects.

A principal vantagem de se trabalhar com POCO é ter um domínio independente, já que como dito acima, ele não depende de nenhum componente externo.

A algum tempo atrás participei de algumas discussões de quando "deveríamos" utilizar ou não POCO. Novamente é uma situação delicada, pois os POCOs não vão melhorar a performance da sua aplicação (As vezes inclusive podem dificultar -- Tome como exemplo que não devemos decorar uma classe poco), então cabe a cada um analisar em qual situação o POCO se aplica, e se realmente tem a necessidade de se ter um domínio independente.

Para exemplificar o uso de POCOs criaremos um novo projeto de testes, como descrito nos passos abaixo, começando pela Figura 33. É importante prestar atenção na versão do .NET Framework que o projeto usará


Figura 33 - Criando um novo projeto.

Com o projeto criado, vamos adicionar um novo Entity Data Model, para isto, clique com o botão direito do mouse sobre o projeto criado acesse a opção Add e em seguida New Item.


Figura 34 - Adicionando um novo item ao projeto.

Nesta nova tela que se abre, selecione Data no menu lateral esquerdo e ao centro, selecione ADO.NET Entity Data Model. Nomeie o modelo como desejado e em seguida clique em Add, como na Figura 35.


Figura 35 - Adicionando um novo ADO.NET Entity Data Model.

Para esta abordagem, criaremos um modelo vazio. Então, selecione Empty Data Model e clique em Finish, como na Figura 36.


Figura 36 - Criando um modelo de entidades vazio.

Após finalizar o Wizard, teremos um modelo vazio na tela. Temos então que criar as nossas entidades. Para isto, clique com o botão direito do mouse sobre o fundo do modelo, acesse a opção Add, e em seguida New Item, como mostrado na Figura 37.


Figura 37 - Adicionando uma nova entidade ao modelo vazio.

Neste ponto, a tela de adição de entidades irá aparecer. Sem muitos mistérios, preencha o nome da entidade e o Entity Set Name. A Figura 38 ilustra esta passagem.


Figura 38 - Criando uma nova entidade.

Com a entidade criada, adicionaremos mais uma propriedade, como mostrado na Figura 39 e Figura 40.


Figura 39 - Adicionando uma nova propriedade.


Figura 40 - Renomeando a propriedade criada.

Repita os passos para a criação da entidade Funcionário, como mostrado na Figura 41 e Figura 42


Figura 41 - Adicionando a entidade Funcionário.


Figura 42 - Adicionando a propriedade Nome à entidade Funcionário.

Com as entidades pai(Empresa) e filha(Funcionário) criadas, precisamos associá-las. Para isto, selecione a ferramenta Association, em seguida clique sobre a entidade da empresa, e depois sobre a entidade funcionário, como mostrado na Figura 43, Figura 44 e Figura 45.


Figura 43 - Ferramenta de associação.


Figura 44 - Iniciando a associação.


Figura 45 - Associação feita.

Com o modelo feito, precisamos então codificar. Como codificaremos nossas próprias classes, não há necessidade que o EF gere código algum para elas. Sendo assim, clique no fundo da tela do e acesse as propriedades do modelo(Tecla F4). Acesse então a propriedade Code Generation e selecione None, como mostrado na Figura 46.


Figura 46 - Desabilitando a geração de código automático pelo EF.

Com a geração de código desabilitada, adicionaremos 3 novas classes, uma para a entidade funcionário, uma para a entidade empresa e a última para o contexto que neste caso também não será gerado automaticamente.


Figura 47 - Adicionando uma nova classe.

O código da classe Empresa.cs fica como a Listagem 11.

01using System.Collections.Generic;02 03namespace InsideDotNet_DescubraEF_404{05    public class Empresa06    {07        public virtual int Id { get; set; }08        public string Titulo { get; set; }09 10        private IList funcionarios = new List();11        public virtual IList Funcionarios { get { return this.funcionarios; } set { this.funcionarios = value; } }12    }13}

Listagem 12 - Classe Empresa.cs.

Para a classe Funcionario.cs, a Listagem 13 mostra como ela deve ficar

01namespace InsideDotNet_DescubraEF_402{03    public class Funcionario04    {05        public virtual int Id { get; set; }06        public virtual string Nome { get; set; }07 08        private Empresa empresa = new Empresa();09        public virtual Empresa Empresa { get { return this.empresa; } set { this.empresa = value; } }10    }11}

Listagem 13 - Classe Funcionario.cs.

Para finalizar, vamos criar a classe de contexto, que neste caso chamei de MyPocoContext.cs, e pode ser vista na Listagem 14.

01using System.Data.Objects;02 03namespace InsideDotNet_DescubraEF_404{05    public class MyPocoContext : ObjectContext06    {07        public MyPocoContext()08            : base("name=POCOEntityDataModelContainer", "POCOEntityDataModelContainer")09        {10 11        }12 13        private IObjectSet funcionarios;14        public IObjectSet Funcionarios15        {16            get17            {18                if (funcionarios == null)19                    funcionarios = CreateObjectSet();20 21                return funcionarios;22            }23        }24 25        private IObjectSet empresas;26        public IObjectSet Empresas27        {28            get29            {30                if (empresas == null)31                    empresas = CreateObjectSet();32 33                return empresas;34            }35        }36    }37}

Listagem 14 - Classe MyPocoContext.cs.

Com as classes criadas, temos então que gerar o banco de dados, para isto siga asFiguras 48a53.


Figura 48 - Gerando script para criação do banco de dados apartir do modelo de entidades.


Figura 49 - Selecionando a Connection String.


Figura 50 - Resumo do script gerado.


Figura 51 - Executando o script gerado.


Figura 52 - Conectando-se ao SQL Server.


Figura 53 - Comandos executados com sucesso.

Podemos notar que na classe MyPocoContext.cs, fiz uma herança da classe base, passando o nome de uma connection string para ela, como mostrado na Listagem 15.

1public MyPocoContext()2    : base("name=POCOEntityDataModelContainer", "POCOEntityDataModelContainer")3{4 5}

Listagem 15 - Construtor da classe MyPocoContext.cs.

A Figura 54 mostra o arquivo App.Config, e o local de onde retirei a informação referente ao nome da Connection String.


Figura 54 - Arquivo App.Config (Connection String).

Por fim, vamos criar uma aplicação simples para testar se nossos POCOs funcionaram certinho. A Listagem 16 mostra este programa.

01using System;02 03namespace InsideDotNet_DescubraEF_404{05    class Program06    {07        static void Main(string[] args)08        {09            // Cria a instância do contexto criado10            var meuContexto = new MyPocoContext();11 12            // Cria um novo objeto Empresa13            Empresa emp = new Empresa();14            emp.Titulo = "Inside .NET";15 16            // Adiciona o objeto empresa e persiste no banco17            meuContexto.Empresas.AddObject(emp);18            meuContexto.SaveChanges();19 20            // Cria um novo objeto funcionário21            Funcionario f = new Funcionario();22            f.Nome = "André";23            f.Empresa = emp;24 25            // Adiciona o objeto funcionário e persiste no banco26            meuContexto.Funcionarios.AddObject(f);27            meuContexto.SaveChanges();28 29            // Percorre todas as empresas30            foreach (var item in meuContexto.Empresas)31            {32                Console.WriteLine(item.Titulo);33 34                // Percorre todos os funcionários35                foreach (var fun in item.Funcionarios)36                {37                    Console.WriteLine(fun.Nome);38                }39 40                Console.WriteLine("-----------------------");41            }42 43            Console.ReadKey();44        }45    }46}

Listagem 16 - Testando os POCOs criados.

Nota: Em alguns casos, precisamosreferenciaro namespace System.Data.Entity. Para isso, acesse a opção Project > Add Reference.

A Figura 55 mostra a tela final do programa em execução.


Figura 55 - Resultado da execução do programa.

Download do Código fonte

Conclusão

Podemos notar que o ADO.NET Entity Framework, apesar de ser um Framework novo, já está bem mais robusto nesta nova versão, recebeu várias atualizações importantes e ainda receberá muito mais. Podemos notar que há um grande foco sobre esta nova plataforma, que eu particularmente gosto muito.

Espero que tenham gostado. Até o próximo artigo.

Referências

Livro - O"Reilly - Programming Entity Framework, 1st Edition

POCOs
http://viniciusquaiato.com/blog/index.php/entity-framework-4-model-first-com-pocos/

Eager Loading
http://viniciusquaiato.com/blog/index.php/eager-loading-no-entity-framework-4-0/

Lazy Loading
http://viniciusquaiato.com/blog/index.php/lazy-loading-no-entity-framework-4-0/

André Baltieri

André Baltieri - Trabalha com desenvolvimento de aplicações web a mais de 7 anos, e com ASP.NET desde 2003. É líder da comunidade Inside .NET (http://www.insidedotnet.com.br/) e do projeto Learn MVC .NET (http://learn-mvc.net/). Bacharelando em Sistemas de Informação, atualmente trabalha com desenvolvimento e suporte de aplicações web em ASP.NET/C# em projetos internacionais e ministra treinamentos e consultorias sobre a plataforma .NET.