Nenhum comentário Download


ADO.NET Entity Framework – Parte II

 

Vimos no artigo anterior, como criar uma aplicação usando Entity Framework. Neste artigo, mostraremos mais algumas dicas sobre o uso do EF e LINQ. Nessa segunda parte, vamos modificar algumas coisas: vamos refazer nosso banco, como se já estivéssemos com a aplicação em desenvolvimento e decidíssemos usar o Entity Framework.

 

A única diferença do banco de dados do artigo anterior será que teremos apenas uma tabela para armazenar os dados de Cliente, Vendedor e Fornecedor (tabela PESSOA). Teremos um campo para indicar o tipo de pessoa que estamos salvando.

 

Assim, na aplicação não teremos uma classe para casa entidade. Veja na Listagem 1 como ficará a tabela PESSOA.

 

Listagem 1. Tabela PESSOA modificada

CREATE TABLE PESSOA

(

        nCdPessoa               int not null identity,

        nIdTipo         int not null, --1: cliente, 2: vendedor, 3: fornecedor

        sNmPessoa               varchar(50) not null,

        sDsEndereco             varchar(50) not null,

        tDtNascimento   date null,

        nVlLimite               decimal (18,2) null

)

 

Na tabela VENDA_ITEM teremos informações sobre venda e o produto vendido. Acesso o modelo na aplicação, selecione todas as entidades e exclua as mesmas. Clique com o botão direito no modelo e escolha Update Model from Database. Selecione todas as tabelas e escolha Finish (Figura 1).

 

 

Figura 1. Atualizando o modelo da aplicação

 

Precisamos modificar as classes e adaptá-las para que a aplicação continue funcional. Precisaremos apenas trocar a entidade CLIENTE, VENDEDOR e FORNECEDOR pela PESSOA. Se você quiser apenas remover as classes e criar uma nova (Pessoa.cs) nos mesmos moldes das outras, fique a vontade.

 

Após, não esqueça de configurar a propriedade nIdTipo para o respectivo valor, em cada cadastro.

Vendas e itens

Nosso modelo apresenta as tabelas de vendas e de itens da venda. Nesse caso, precisamos inserir a venda e depois os itens (produtos), onde os mesmos devem ter uma venda relacionada. Não podemos adicionar itens sem uma venda. Como proceder?

 

Caso você acompanhe meus artigos e aulas, sempre fiz assuntos relacionados a carrinho de compras na web, onde temos o mesmo cenário vendas e itens. Sempre precisei fazer a inserção da venda, retornar o código criado e adicionar nos itens. Com o Entity Framework será muito mais fácil.

 

Bastará preenchermos a entidade de venda e junto a mesma (através da propriedade de relacionamento) os seus itens. Ao mandar inserir, o Entity Framework realiza a inserção da venda e dos respectivos itens. Fácil J.

 

Vamos criar a tela para inserção da venda e itens. Veja na Figura 2 a tela de cadastro de vendas. A mesma é bem simples, onde temos um campo para digitar o código do produto e realizar a pesquisa, retornando o nome do produto.

 

 

Figura 2. Tela de vendas

 

Na Listagem 2, temos os principais códigos da tela.

 

Listagem 2. Tela de vendas

private List<VENDA_ITEM> itens = new List<VENDA_ITEM>();

...

private void txtProduto_KeyDown(object sender, KeyEventArgs e)

{

   if (e.KeyCode == Keys.Enter)

   {

      //procura o produto

      Produto objProduto = new Produto();

      PRODUTO produto = new PRODUTO();

      produto = objProduto.PesquisarPorCodigo(int.Parse(txtCodigo.Text));

      txtProduto.Text = produto.sNmProduto;

 

      txtQuantidade.Focus();

   }

}

 

private void btnInserir_Click(object sender, EventArgs e)

{

   PRODUTO produto = new PRODUTO();

   Produto objProduto = new Produto();

 

   produto = objProduto.PesquisarPorCodigo(int.Parse(txtCodigo.Text));

 

   VENDA_ITEM item = new VENDA_ITEM();

   item.nCdProduto = int.Parse(txtCodigo.Text);

   item.nQtdeItem = int.Parse(txtQuantidade.Text);

   item.nVlItem = produto.nVlProduto;

 

   itens.Add(item);

 

   PreencheGrid();

}

 

private void btnSalvar_Click(object sender, EventArgs e)

{

   if (itens.Count > 0)

   {

      //cria a entidade Venda

      VENDA entidade = new VENDA();

      Venda objVenda = new Venda();

      decimal nVlVenda = 0;

               

      //itens

      foreach (VENDA_ITEM item in itens)

      {

         //incrementa valor total

         nVlVenda += ((decimal)item.nQtdeItem * (decimal)item.nVlItem);

         //adiciona os itens na venda

         entidade.VENDA_ITEM.Add(item);

      }

 

      entidade.tDtVenda = dtVenda.Value;

      entidade.nVlTotal = nVlVenda;

 

      if (objVenda.Salvar(true, entidade))

         MessageBox.Show("Venda cadastrada com sucesso.", "Sucesso", MessageBoxButtons.OK, MessageBoxIcon.Information);

   }

   else

      MessageBox.Show("Não existem itens na venda.", "Erro", MessageBoxButtons.OK, MessageBoxIcon.Error);

}

 

private void PreencheGrid()

{

   listView1.Items.Clear();

 

   Produto objProduto = new Produto();

 

   foreach (VENDA_ITEM item in itens)

   {

      PRODUTO entidade = objProduto.PesquisarPorCodigo(item.nCdProduto);

      ListViewItem novoitem = new ListViewItem(entidade.sNmProduto);

      novoitem.SubItems.Add(item.nQtdeItem.ToString());

      novoitem.SubItems.Add(((decimal)item.nVlItem).ToString("C"));

      novoitem.SubItems.Add(      ((decimal)item.nVlItem * item.nQtdeItem).ToString("C"));

 

      listView1.Items.Add(novoitem);

   }

}

 

O código é simples. Temos uma lista de itens que serão adicionados pelo usuário. Essa lista será responsável por preencher o Grid com as informações do produto digitado pelo usuário (método PreencherGrid).

 

O evento txtCodigo_KeyDown pesquisa o produto pelo código digitado e adiciona o mesmo na lista. O Salvar percorre a lista de itens, para calcular o subtotal (quantidade * valor) para salvar o valor total da venda, assim como inserir no objeto VENDA os seus respectivos itens.

 

No final, chamamos o Salvar da classe de negócio. Na tabela PRODUTO, temos o campo nQtdeAtual. Esse campo deverá ser atualizado para que ao executar a venda, a quantidade atual do produto seja decrementada.

Deixo como tarefa a ser executada pelo leitor para ver se conseguiu diferençar as classes de negócio e de dados. Execute a aplicação e realize a pesquisa e venda de produtos (Figura 3).

 

 

Figura 3. Salvando os itens e a venda

 

Clique no Salvar e verifique no banco de dados que a venda e seus respectivos itens foram salvos com sucesso (Figura 4).

 

 

Figura 4. Registros salvos no banco de dados

Code First

Usamos nesses dois artigos, o desenvolvimento do Entity Framework, usando um designer (modelo), um arquivo com a extensão EDMX. Para quem gosta de ter “o controle sobre tudo”, podemos utilizar uma abordagem diferente, chamada CodeFirst, usando classes POCO.

 

Nota: Classes POCO, são classes que não depende e não conhecem o framework ao qual fazem parte. Esse tipo de classe esta bastante ligada a ferramentas ORM.

 

Assim, o Entity Framework utiliza as classes POCO, usando um container de banco de dados chamado Contexto. O Contexto mapeia as classes POCO e também informa a engine do banco de dados, usando apenas uma string de conexão.

 

Caso mude de banco, basta mudar essa string. Fácil. Para mapear sua classe, podemos controlar os aspectos do mapeamento como campos obrigatórios, tamanho, FK etc. Para não ter todo o trabalho de mapear o banco de dados em classes, podemos usar uma ferramenta para EF, o Entity Frmework Power Tools, que pode ser baixado em: http://visualstudiogallery.msdn.microsoft.com/72a60b14-1581-4b9b-89f2-846072eff19d

 

Atualmente, esta na versão beta 3. Com a ferramenta, podemos gerar um modelo, baseado nas classes POCO, gerar scripts, fazer engenharia reversa etc. Baixe o arquivo vsix e execute. Após instalar, acessando o modelo com o botão direito, temos algumas opções.

 

Ao clicarmos no projeto, temos a possibilidade de fazer engenharia reversa para CodeFirst. Após clicar na opção, será necessário conectar ao banco de dados. Após, as classes são geradas no projeto (Figura 5).

 

 

Figura 5. Engenharia reversa para CodeFirst

Lazy Load

Outra dica bastante interessante, se refere a performance do Entity Framework. Existe um mecanismo chamado Lazy Load, que carrega informações sobre demanda de objetos, de acordo com seus relacionamentos.

 

Para entender melhor. Quando fizemos uma consulta na tabela de VENDA. Para cada objeto VENDA, teremos seus respectivos objetos VENDA_ITEM carregados. Isso é bom, mas também ruim, pois é um carregamento desnecessário em determinados casos, consome memória, aumenta o tráfego de dados etc.

 

Esse mecanismo vem configurado como padrão no Entity Framework, mas podemos remover. No modelo, altere a propriedade Lazy Loading Enabled para false. Para vermos um pequeno exemplo, vamos usar o debug para visualizar os dados. O código a seguir, simplesmente, preenche uma lista com dados do objeto VENDA.

 

List<VENDA> lista = new List<VENDA>();

Venda objVenda = new Venda();

 

lista = objVenda.PesquisarTodos();

 

Debugando o código, após preencher a lista, podemos ver que os objetos VENDA_ITEM, não são retornados na pesquisa (Figura 6).

 

 

Figura 6. Consulta não retorna os objetos do relacionamento de VENDA

 

Caso seja necessário retornar os dados relacionados, basta mudar o código que retorna todos os dados da VENDA:

 

(from p in db.VENDAs.Include("VENDA_ITEM") select p).ToList();

 

Apenas adicionamos o Include no código, passando o nome da tabela de relacionamento. Caso tivéssemos mais relacionamentos, bastaria ir adicionando quanto Includes forem necessários. Veja na Figura 7 o exemplo.

 

 

Figura 7. Consulta retorna os objetos do relacionamento de VENDA usando Include

Links

Fernando Henrique Ferreira: http://ferhenriquef.com/

Carlos do Santos: http://carloscds.net/category/entity-framework/

Conclusões

Vimos nesse artigo mais algumas dicas interessantes sobre a ferramenta de mapeamento objeto relacional Entity Framework. Deixei uma seção de links para dois sites que curto muito sobre a ferramenta, do grande Fernando Henrique Ferreira, que sabe tudo do Entity Framework. Outro link é do blog do meu amigo Carlos dos Santos, mestre MVP.

 

Um grande abraço a todos e até a próxima!