Nenhum comentário Download


ADO.NET Entity Framework

 

O assunto mapeamento objeto relacional (O/R) sempre foi algo “nebuloso” para alguns desenvolvedores e um pouco de receio. Afinal, deixar que a ferramenta seja responsável por executar os comandos SQL para inserir, alterar, remover registros no banco é algo que muitos ficam com a pulga atrás da orelha, pois querem ter o “controle” sobre essas ações.

 

As facilidades que temos nesse tipo de mapeamento é bastante interessante. Tiramos o conceito de banco de dados relacional e começamos a trabalhar com um modelo de dados. Com isso, podemos trabalhar com herança (sim, isso é possível), mapear relacionamentos entre as entidades etc.

 

Nosso exemplo será bem simples. Teremos um sistema de vendas. Com cadastros de vendedores, clientes e fornecedores (que no nosso modelo será uma PESSOA). Teremos assim, entrada de mercadorias para dar baixa no estoque (a funcionalidade de entrada de produtos pode ser implementada por você).

Acredito que com isso, podemos ter uma base importante para conhecermos o funcionamento do Entity Framework (EF).

Conhecendo o Entity Framework

A ferramenta EF esta a cada nova versão ganhando aprimoramentos. Usaremos neste artigo a versão 5.0 que é totalmente independente do Visual Studio. O que isso significa? Que você pode usar essa versão com versões diferentes do Visual Studio. Usaremos a versão 2012 (Express) e precisaremos apenas “instalar” a ferramenta no nosso projeto.

 

Assim, se tivermos projetos com versões diferentes, não seremos afetados com alterações da ferramenta.  Crie um novo projeto Windows Forms (se quiser, pode ser ASP.NET). Vamos separar em camadas nosso projeto.

 

Teremos os formulários no projeto Windows Forms, o modelo em uma Class Library e também um Class Library para as classes que usaremos. Acesse o menu Tools>Library Package Manager>Package Manager Console. No console, digite: “Install-Package EntityFramework” (Figura 1).

 

Figura 1. Instalando o EF pelo Visual Studio

 

Se nenhum erro ocorrer, você receberá a mensagem que o pacote do EF foi instalado com sucesso.

 

Nota: Caso a opção do menu anterior não esteja presente em seu ambiente, acesso o menu Tools>Extension Manager, procure por NuGet Package Manager e faça a instalação do mesmo.

Criando o modelo

Vamos fazer o passo contrário do que estamos acostumados. Sempre começamos a nossa aplicação criando o banco de dados relacional. Tabelas, campos, views, procedures etc. Agora, vamos começar pelo modelo, e após o Visual Studio gera os scripts para a criação do banco de dados.

 

Crie uma Class Library na Solution e adicione um ADO.NET Entity Model (Figura 2).

 

Figura 2. Criando o modelo de dados

 

Na próxima tela, podemos escolher se vamos criar um modelo vazio (nossa opção nesse artigo) ou vamos criar um modelo baseado em um banco de dados já existente. Clique em Finish. Será mostrado o Entity Data Model Designer, onde trabalharemos as entidades do modelo.

 

Clique com o botão direito e escolha a opção Add>Entity e preencha conforme a Figura 3.

 

 

Figura 3. Criando a entidade PESSOA

 

Criamos uma entidade chamada PESSOA, ela será responsável por definir as informações do vendedor, fornecedor e cliente. Mas você deve estar pensando, mas no banco eu crio uma tabela para cada entidade ou apenas uma tabela com um campo indicando o tipo de cada pessoa. Sim, mas teremos algo mais legal de utilizar: herança.

 

Continuando para que você possa entender melhor, a entidade PESSOA, terá atributos comuns para as outras entidades (código, nome, endereço etc). As entidades herdadas terão atributos específicos para a mesma, como: data de nascimento (cliente), valor de limite (fornecedor) e comissão (vendedor).

 

Clique em OK e será mostrada a entidade pessoa. Para criar outros atributos, clique na entidade e escolha Add>Scalar property. Dê o nome da propriedade de “sNmPessoa” e mude as características da mesma na janela de propriedades (mude Max Length para 50 e Nullable para True). Crie uma nova propriedade chamada “sDsEndereco” (configurando as mesmas propriedades da anterior).

 

Agora vamos criar outra entidade que herdará de PESSOA. Execute o mesmo passo anterior, mas no editor, em Base type, escolha PESSOA. Veja que ao fazer isso, as opções para configuração ficam desabilitadas. Clique em OK.

 

Note que temos a nova entidade com uma ligação com PESSOA. Crie uma propriedade chamada “tDtNascimento” (em Type escolha DateTime em Nullable escolha True). Faça a mesma configuração para as entidades FORNECEDOR e VENDEDOR, adicionando os campos da Tabela 1 para as respectivas entidades.

 

Entidade

Nome

Propriedade

Valor

FORNECEDOR

tDtCadastro

Type

DateTime

Nullable

False

nVlLimite

Type

Decimal

Nullable

False

Precision

18

Scale

2

VENDEDOR

tDtAdmissao

Type

DateTime

Nullable

False

nVlComissao

Type

Decimal

Nullable

False

Precision

18

Scale

2

Tabela 1. Atributos das entidades FORNECEDOR e VENDEDOR

Veja na Figura 4 o modelo até agora criado.

 

 

Figura 4. Modelo com suas entidades

 

Agora vamos criar as entidades: PRODUTO, VENDA e VENDA_ITENS. Veja na Tabela 2 a configuração dessas entidades (elas não herdam de nenhuma outra entidade).

 

Entidade

Nome

Propriedade

Valor

PRODUTO

nCdProduto

KeyProperty

sNmProduto

Type

String

Nullable

False

MaxLenght

50

nVlProduto

Type

Decimal

Nullable

False

Precision

18

Scale

2

nQtdeMin

Type

Decimal

Nullable

False

Precision

18

Scale

2

nQtdeAtual

Type

Decimal

Nullable

False

Precision

18

Scale

2

VENDA

nCdVenda

KeyProperty

tDtVenda

Type

Datetime

Nullable

False

nVlTotal

Type

Decimal

Nullable

False

Precision

18

Scale

2

VENDA_ITEM

nCdItemVenda

KeyProperty

nQtdeItem

Type

Decimal

Nullable

False

Precision

18

Scale

2

nVlItem

Type

Decimal

Nullable

False

Precision

18

Scale

2

Tabela 2. Atributos das entidades do nosso exemplo

Como você pode ter notado, não criamos os campos na entidade VENDA_ITEM referente a venda e ao produto. Vamos fazer isso, usando a associação entre as entidades. Na ToolBox escolha o item Association. Clique sobre a entidade VENDA e arraste o mouse até a entidade VENDA_ITEM.

 

Veja que a associação foi criada e temos as propriedades de navegação nas respectivas entidades. Repita o mesmo processo para a associação do produto em VENDA_ITEM, relacionando com PRODUTO. Com isso, finalizamos nosso modelo.

 

Você pode ter ficado em dúvida, por que não existe um campo para o relacionamento entre as entidades. Estamos trabalhando com Objetos, no banco, teremos os respectivos campos. Veja o resultado final na Figura 5.

 

Figura 5. Modelo final e suas entidades

 

Se quisermos modificar a associação, basta clicar sobre a mesma e alterar suas propriedades.

Criando o banco de dados

Precisamos agora, baseado nesse modelo, criar o nosso banco de dados. O Visual Studio gera os scripts necessários para isso. Clique com o botão direito no editor e escolha a opção Generate Database from Model.

 

Será aberta uma janela para conexão com o banco de dados. O Visual Studio não cria o banco de dados, apenas o script dos objetos, portanto você deve criar o database antes. Após isso, voltando a opção anterior, escolha o banco no wizard de conexão.

 

Clique em Next e veja o script para execução no banco de dados (Figura 6).

 

Figura 6. Script para criar as entidades no banco de dados

 

Clique em Finish para criar o arquivo SQL. Execute o script na base de dados. Quando quisermos validar o mapeamento do banco com o modelo, basta clicar com o botão direito no editor e escolha Validate. Caso ocorra algum erro a janela Error List mostraria os problemas encontrados.

 

Caso alguma alteração precise ser feita, o mais interessante é criar o campo no banco de dados e usar a opção Update Model from Database no editor do modelo. Caso criarmos apenas no modelo, será necessário refazer o script SQL para executarmos no banco.

Criando as classes

Agora precisamos criar as classes que vão auxiliar na manipulação dos dados. Essas classes são semelhantes as características de um controller do padrão MVC muito falado atualmente. Temos o modelo com as entidades, vamos criar o controller com as classes e as views serão nossos formulários.

 

Crie uma nova Class Library na Solution e adicione uma pasta chamada “DAL”. Para explicar o que faremos: teremos classes para manipular cada entidade. Essas classes terão acessado ao modelo para executar os métodos do EF para manipular suas entidades (métodos CRUD).

 

Teremos também classes que “conversam” com as classes de negócio, apenas chamando seus métodos no formulário. Assim, separamos nosso projeto em uma melhor organização. Agora vamos criar para cada entidade, a sua respectiva classe, responsável por manipular os dados da entidade.

 

Mas antes, vamos criar uma classe base que será herdada por cada classe da entidade. Crie uma classe chamada “BaseClass” e preencha com o código da Listagem 1.

 

Listagem 1. Classe base para as classes de cadastro

public class BaseClass<T>

{

   public virtual bool Salvar(bool bInsert, T objeto)

   {

             return false;

   }

 

   public virtual bool Excluir(T objeto)

   {

             return false;

   }

 

   public virtual List<T> PesquisarTodos()

   {

             return null;

   }

 

   public virtual List<T> PesquisarPorDescricao(string sDescricao)

   {

             return null;

   }

 

   public virtual T PesquisarPorCodigo(int nCdObjeto)

   {

             return default(T);

   }

}

 

Veja que a classe base espera um objeto (T), que será substituído pela entidade que vamos usar na classe herdada. Agora sim, vamos criar a classe que irá manipular a entidade CLIENTE. Na Listagem 2 temos a implementação dos métodos Salvar e Excluir.

 

Listagem 2. Classe CLIENTE

public class Cliente: BaseClass<CLIENTE>

{

   public override bool Salvar(bool bInsert, CLIENTE objeto)

   {

      using (ModeloDB db = new ModeloDB())

      {

         if (bInsert)

            db.AddToPESSOA(objeto);

         else

         {

            db.PESSOA.Attach(objeto);

            db.ObjectStateManager.ChangeObjectState(

               objeto, EntityState.Modified);

         }

         return (db.SaveChanges() > 0);

      }

   }

 

   public override bool Excluir(CLIENTE objeto)

   {

      using (ModeloDB db = new ModeloDB())

      {

         PESSOA pessoa = (from p in db.PESSOA.OfType<CLIENTE>()

            where p.nCdPessoa == objeto.nCdPessoa

            select p).FirstOrDefault();

         db.DeleteObject(pessoa);

 

         return (db.SaveChanges() > 0);

       }

   }

 

Note que a classe herda da classe base que fizemos e ao digitar o método Salvar, basta digitar “public override”,  dar um espaço e o Visual Studio mostra os métodos que podem ser implementados, já preenchendo o parâmetro (T) com a classe indicada no BaseClass.

 

Na implementação do Salvar, verificamos o valor do parâmetro bInsert para chamar o método que inclui um novo objeto ou atualiza o objeto passado por parâmetro. Para o Excluir, fizemos uma consulta LINQ para retornar o objeto que passamos por parâmetro para em seguida chamar o método que exclui a entidade.

 

Vale uma dica aqui, como CLIENTE, VENDEDOR e FORNECEDOR herdam de PESSOA, sempre vamos pesquisar a entidade PESSOA, mas precisamos indicar ao EF que estamos pesquisando o tipo que queremos, usando o código:

 

db.PESSOASet.OfType<CLIENTE>()

 

Veja que os dois métodos retornam um bool, assim, verificamos o retorno do SavChanges (inteiro) que indica a quantidade de registros afetados pela inserção ou atualização. Agora, na Listagem 3 temos a implementação dos métodos de pesquisa.

 

Listagem 3. Métodos de pesquisa

public override List<CLIENTE> PesquisarTodos()

{

   using (ModeloDB db = new ModeloDB())

   {

      return (from p in db.PESSOA.OfType<CLIENTE>()

        select p).ToList();

   }

}

 

public override List<CLIENTE> PesquisarPorDescricao(string sDescricao)

{

   using (ModeloDB db = new ModeloDB())

   {

      return (from p in db.PESSOA.OfType<CLIENTE>()

        where p.sNmPessoa.ToUpper().Contains(sDescricao.ToUpper()) 

        select p).ToList();

   }

}

 

public override CLIENTE PesquisarPorCodigo(int nCdObjeto)

{

   using (ModeloDB db = new ModeloDB())

   {

      CLIENTE cliente = (from p in db.PESSOA.OfType<CLIENTE>()

        where p.nCdPessoa == nCdObjeto select p).FirstOrDefault();

 

      if (cliente != null)

         return cliente;

      else

         throw new Exception("Registro não encontrado.");

    }

}

 

O método PesquisarTodos, simplesmente retorna todos os registros da entidade (CLIENTE). No PesquisarPorDescricao usamos o Contains (método de tipo String) onde comparamos o valor de sNmPessoa com o parâmetro do método, com os dois valores em maiúsculo, para que a comparação seja a mais precisa possível.

 

Para o método que retorna o tipo da entidade, filtramos a mesma pelo código, onde verificamos se o registro foi encontrado e em caso negativo, emitimos uma mensagem de erro. Com a classe Cliente criada, você pode adaptar as classes Fornecedor, Vendedor e Produto.

Classes com relacionamento

Como podemos ver no modelo, a classe VENDA tem relacionamento com VENDA_ITENS, mas sabemos que para incluir um item na tabela filha, precisamos ter um registro na tabela pai. Então, como podemos fazer isso? Não precisamos fazer nada, o EF faz isso pra gente J.

 

Como temos relacionamento basta preencher, por exemplo, a entidade VENDA e simultaneamente os itens, usando a propriedade VENDA_ITEM presente na entidade VENDA. Após, basta adicionar a entidade (igual ao código do Salvar) e os filhos e pai serão inseridos. Para a classe Venda não teremos o método para pesquisar por descrição. A principio, não precisamos implementar as classes dos itens, já que preencheremos os mesmos pela entidade relacionada (VENDA).

 

As classes que criamos, são nossas classes de dados (poderíamos dizer que essas classes seriam as entidades do EF), agora vamos criar as classes de negócios, que nada mais são do que classes que vão chamar os métodos das classes de dados e quando necessário realizar validações e regras de negócios.

Na Listagem 4 temos um exemplo da classe Cliente.

 

Listagem 4. Classe de exemplo para a classe de negócio do cliente

...

using EntityController.Dados;

using EntityModel;

 

namespace EntityController.Negocio

{

   public class Cliente

   {

      private Dados.Cliente objCliente = new Dados.Cliente();

 

      public bool Salvar(bool bInsert, CLIENTE objeto)

      {

         return objCliente.Salvar(bInsert, objeto);

      }

 

      public bool Excluir(CLIENTE objeto)

      {

         return objCliente.Excluir(objeto);

      }

 

      public List<CLIENTE> PesquisarTodos()

      {

         return objCliente.PesquisarTodos();

      }

 

      public CLIENTE PesquisarPorCodigo(int nCdObjeto)

      {

         return objCliente.PesquisarPorCodigo(nCdObjeto);

      }

 

      public List<CLIENTE> PesquisarPorDescricao(string sDescricao)

      {

         return objCliente.PesquisarPorDescricao(sDescricao);

      }

   }

}

 

Vale lembrar que essas classes de negócio, servem para fazermos as regras de negócio da aplicação, como por exemplo: validação, campos com valores default, baixa de quantidade em estoque, adição de quantidade quando de compras etc.

 

Note que temos classes com mesmo nome, mas com namespace diferentes, isso é importante para não ocorrer erro. Poderíamos usar nomes diferentes, fica à seu critério de padronização. Veja na Figura 7 temos a estrutura do nosso projeto com todas as classes criadas.

 

 

Figura 7. Estrutura de arquivos do nosso projeto

Criando os formulários

Para os cadastros, vamos usar a técnica de herança visual, onde já fiz um artigo sobre o mesmo na The Club. Caso você não possa ver o artigo, indico o mesmo que esta publicado no meu site: http://www.lucianopimenta.com/post.aspx?id=193. Não iremos nos ater nessa funcionalidade do sistema, indico a leitura do referido artigo para tirar as dúvidas necessárias.

 

Veja na Figura 8 temos formulário base do nosso cadastro.

 

Figura 8. Formulário base de cadastro

 

Vamos implementar o cadastro de cliente e os outros são muito semelhantes (produto, vendedor e comprador), portanto podem ser facilmente adaptados. Veja na Listagem 5 os métodos virtuais implementados.

 

Listagem 5. Métodos do formulário base, implementado no formulário de cadastro

private CLIENTE entidade = new CLIENTE();

private EntityController.Negocio.Cliente ngCliente = new EntityController.Negocio.Cliente();

...

public override void PreencheEntidade()

{

   entidade.nCdPessoa = (lblCodigo.Text == "" ? 0 : int.Parse(lblCodigo.Text));

   entidade.sNmPessoa = txtNomeCliente.Text;

   entidade.sDsEndereco = txtEndereco.Text;

   entidade.tDtNascimento = tDtNascimento.Value;

}

 

public override void PreencheCadastro()

{

   EntityController.Negocio.Cliente cliente = new EntityController.Negocio.Cliente();

   entidade = cliente.PesquisarPorCodigo(_nCdGenerico);

 

   lblCodigo.Text = entidade.nCdPessoa.ToString();

   txtNomeCliente.Text = entidade.sNmPessoa;

   txtEndereco.Text = entidade.sDsEndereco;

   tDtNascimento.Value = entidade.tDtNascimento.Value;

}

 

public override void Pesquisa()

{

   List<CLIENTE> lista = ngCliente.PesquisarPorDescricao(txtPesquisa.Text);

 

   lvPesquisa.Items.Clear();

 

   foreach (CLIENTE cliente in lista)

   {

      ListViewItem item = new ListViewItem(cliente.nCdPessoa.ToString());

      item.SubItems.Add(cliente.sNmPessoa);

 

      lvPesquisa.Items.Add(item);

   }

}

 

public override bool Salvar()

{

   return ngCliente.Salvar(sStatus == StateCadastro.scInserindo, entidade);

}

 

public override bool Excluir()

{

   return ngCliente.Excluir(entidade);

}

 

Veja que temos os métodos virtuais implementados chamando os respectivos métodos das classes criadas anteriormente (Pesquisa, Salvar etc). Atente para a variável privada entidade, que será preenchida quando da pesquisa e ela será a responsável por informar para a classe os dados alterados, inseridos etc.

 

Veja na Figura 9 o cadastro de cliente em execução.

 

Figura 9. Cadastro de cliente funcionando

 

Como já comentado, os cadastros de fornecedor, vendedor e produto, são praticamente iguais ao do cliente (claro, com exceção de campos diferentes). Então, deixo como algo para você praticar.

Conclusões

Vimos nesse artigo uma ideia inicial de como funciona a ferramenta de mapeamento objeto relacional Entity Framework. A ferramenta esta em constante atualização e foi divulgado que a ferramenta se tornará open source, mas sem descontinuar suas atualizações.

 

Existem outras técnicas, como usarmos somente classes das entidades, sem o modelo. Veremos exemplos disso em próximos artigos. No próximo artigo, vamos continuar alguns exemplos e vamos ver como usar relatórios no nosso exemplo.

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