C# - Cadastro de Clientes com Entity Framework em Camadas - II


Na primeira parte deste artigo criamos a solução e os dois projetos e geramos o nosso Entity Data Model (EDM) a partir do nosso modelo de dados.

Vamos agora definir os métodos da nossa camada de acesso a dados para realizar as operações de persistência de dados.

Definindo os métodos da camada de acesso a dados

Com a criação do Entity Data Mode (EDM) Clientes.edmx já temos condições de definir os métodos que realizarão o acesso e a manutenção dos dados a partir do nosso modelo de entidades, existe outra abordagem onde não dependemos da criação do EDM que é conhecida como Persistence Ignorance (POCO).

O que é uma Camada de Acesso a Dados ?

É uma camada separada da camada da apresentação de dados que tem a função de efetuar a conexão com a fonte de dados e através de comandos SQL (neste nosso caso) obter os dados para apresentação.

Esta separação facilita a manutenção e a portabilidade da aplicação.

A camada de apresentação, quando deseja exibir algum dado, chama a camada de de negócios (ausente neste artigo) que chama a camada de acesso aos dados e solicita a informação.

A camada de apresentação não acessa dados nem a camada de dados faz apresentação. Cada uma cumpre o seu papel.

A definição dos métodos depende muito do que desejamos realizar em nosso projeto, para o caso deste artigo eu vou realizar apenas as operações básicas de acesso e manutenção de dados e para isso vou precisar definir os seguintes métodos:

Obs: Embora eu tenha usado o termo registros nós não vamos trabalhar diretamente com o banco de dados e com a tabela mas com a entidade que foi mapeada

Eu poderia definir os métodos diretamente em uma classe concreta mas seguindo as boas práticas vamos definir os métodos em uma interface que depois deverá ser implementada em uma classe concreta.(Programar para uma interface tem o benefício de não dependermos de nenhuma implementação)

Obs: Uma interface contém apenas as assinatura dos métodos, propriedades e eventos. A classe ou Struct que irá implementar a interface deve implementar os membros que são especificados na definição da interface

Selecione o projeto DAL e no menu Project escolha Add New Item, selecione o template Interface , informe o nome IAcessoDB.cs e clique no botão Add;

A seguir o inclua o código definindo os métodos que iremos usar em nosso projeto;

Os métodos definidos usam a coleção List<T> que representa uma coleção de objetos tipados altamente otimizada. Temos os seguintes métodos:(Em nosso exemplo o tipo esta definido como a entidade Cliente)

Feita a definição da interface devemos implementá-la em uma classe concreta para que possamos usá-los em nosso projeto.

Selecione o projeto DAL e no menu Project escolha Add Class e informe o nome ClienteDAL.cs e clique no botão Add;

Em seguida inclua o código abaixo no arquivo ClienteDAL.cs:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Data;

namespace DAL
{
    public class ClientesDAL : IAcessoDB<Cliente>
    {
        private CadastroEntities cadastroEntities;

        /// <summary>
        /// SaveRegistro - Salva uma entidade
        /// </summary>
        /// <param name="registro"></param>
        /// <returns></returns>
        public int SaveRegistro(Cliente registro)
        {
            using (cadastroEntities = new CadastroEntities())
            {
                cadastroEntities.AddToClientes(registro);
                cadastroEntities.SaveChanges();
            }
            return registro.id;
        }

        /// <summary>
        /// UpdateRegistro - Atualiza uma entidade pelo id
        /// </summary>
        /// <param name="registro"></param>
        /// <returns></returns>
        public bool UpdateRegistro(Cliente registro)
        {
            EntityKey key;
            object originalItem;

            using (cadastroEntities = new CadastroEntities())
            {
                key = cadastroEntities.CreateEntityKey("Clientes", registro);

                if (cadastroEntities.TryGetObjectByKey(key, out originalItem))
                {
                    cadastroEntities.ApplyCurrentValues(key.EntitySetName, registro);
                }
                cadastroEntities.SaveChanges();
                return true;
            }
        }

        /// <summary>
        /// GetRegistro - Obtem uma lista de clientes de acordo com o criterio de filtro
        /// </summary>
        /// <param name="registro"></param>
        /// <returns></returns>
        public List<Cliente> GetRegistro(Cliente registro)
        {
            cadastroEntities = new CadastroEntities();

            IQueryable<Cliente> consultaCliente = cadastroEntities.Clientes.AsQueryable<Cliente>();

            if (registro.id > 0)
            {
                consultaCliente = consultaCliente.Where(c => c.id == registro.id);
            }
            if (!string.IsNullOrEmpty(registro.nome))
            {
                consultaCliente = consultaCliente.Where(c => c.nome.Contains(registro.nome));
            }
            if (!string.IsNullOrEmpty(registro.email))
            {
                consultaCliente = consultaCliente.Where(c => c.email.Contains(registro.email));
            }
            if (!string.IsNullOrEmpty(registro.cidade))
            {
                consultaCliente = consultaCliente.Where(c => c.cidade.Contains(registro.cidade));
            }
            return consultaCliente.ToList();
        }

        /// <summary>
        /// GetRegistroPorCodigo - obtem uma entidade pelo codigo
        /// </summary>
        /// <param name="registro"></param>
        /// <returns></returns>
        public Cliente GetRegistroPorCodigo(int codigo)
        {
            cadastroEntities = new CadastroEntities();
            Cliente cliente = cadastroEntities.Clientes.First(c => c.id == codigo);
            return cliente;
        }

        /// <summary>
        /// GetAll - Obtem uma lista de objetos de todos os clientes
        /// </summary>
        /// <param name="registro"></param>
        /// <returns></returns>
        public List<Cliente> GetAll()
        {
            cadastroEntities = new CadastroEntities();

            IQueryable<Cliente> consultaCliente = cadastroEntities.Clientes.AsQueryable<Cliente>();
            return consultaCliente.ToList();
        }

        /// <summary>
        /// DeleteRegistro - exclui uma entidade pelo id informado
        /// </summary>
        /// <param name="registro"></param>
        /// <returns></returns>
        public bool DeleteRegistro(Cliente registro)
        {

            using (cadastroEntities = new CadastroEntities())
            {
                var cli = cadastroEntities.Clientes.FirstOrDefault(c => c.id == registro.id);
                cadastroEntities.DeleteObject(cli);
                cadastroEntities.SaveChanges();
                return true;
            }
        }
    }
}

Note que nossos métodos são dependentes do Entity Data Model gerado e representando por CadastroEntities; é por isso que criamos uma instância do ObjectContext - CadastroEntities - criado no Entity Data Model, para podermos acessar as entidades e aos recursos do Entity Framework.

Estamos também usando os métodos definidos pelo Entity Framework no modelo de entidades :

1- SaveChanges() - Usado para persistir as operações no banco de dados;

2- DeleteObject() -Usado para Excluir um objeto do Contexto;

3- AddToClientes() -Você pode incluir novos objetos a um contexto de objeto através do método AddObject ou chamando um dos métodos AddToEntitySetName do ObjectConext. Você também pode incluir um objeto a um contexto de objeto adicionando o objeto a um EntityCollection existente. Quando você chama o método Add em um EntityCollection que esta anexada a um contexto de objeto , o objeto que você esta incluindo é adicionado ao mesmo ObjectContext.

Além disso estamos usando consultas LINQ para selecionar objetos a partir do modelo de entidades onde usamos expressões lambda.

O que são Expressões Lambda ?

As expressões lambda foram incluídas no VS/VB 2008 para dar suporte a consultas LINQ. As cláusulas Where são assim compiladas como expressões lambdas e chamadas em itens aplicáveis do seu dataset. Podem ser consideradas uma forma de delegate que pode passar ou retornar outra função.

Nota: Delegates permitem que uma classe use métodos de outra classe. Para saber mais sobre delegates leia o meu artigo: Usando Delegates
No LINQ as expressões lambda são usadas para realizar ações sobre listas de objetos e com extensões de métodos.
Uma expressão lambda é então uma função sem nome que calcula e retorna um valor único e podem ser usadas em qualquer lugar que um tipo delegate for válido.

Note que no projeto DAL temos o arquivo App.Config com o seguinte conteúdo:

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <connectionStrings>
    <add name="CadastroEntities" connectionString="metadata=res://*/Clientes.csdl|res://*/Clientes.ssdl|res://*/Clientes.msl;provider=System.Data.SqlClient; _
provider connection string=&quot;Data Source=.\SQLEXPRESS;AttachDbFilename=c:\dados\Cadastro.mdf;Integrated Security=True;Connect Timeout=30; _
User Instance=True;MultipleActiveResultSets=True&quot;" providerName="System.Data.EntityClient" />
  </connectionStrings>
</configuration>

Observe a entity connection definida com o nome CadastroEntities que permite a conexão com os recursos definidos no Entity Data Model.

Uma EntityConnection não é uma conexão com um banco de dados. Embora você possa abrir e fechar uma EntityConnection, isso não significa que você esta abrindo e fechando uma conexão com um banco de dados. Se você usar o EntityClient diretamente ou deixar que os Object Services executem os seus comandos e consultas, a EntityConnection será apenas um caminho para a conexão com o banco de dados.

Nota: O provedor EntityClient usa os recursos de armazenamento específico das classes do ADO .NET Data Provider e o mapeamento para interagir com um modelo de entidades de dados e traduzir as operações realizadas no modelo conceitual em operações realizadas na fonte de dados física.

Uma EntityConnection é composto por 4 partes:

  1. MetaData - O ponteiro para os arquivos de metadados CSDL, MSL e SSDL;
  2. Provider Connection - a string de conexão com o banco de dados;
  3. Provider Name - O namespace do provedor do banco de dados;
  4. Name - O nome da string de conexão;

Dessa forma definimos os métodos para acesso e persistência dos dados na camada de acesso a dados. Como, por questão de simplicidade não vamos implementar uma camada de negócios (jamais faça isso em uma aplicação de produção) falta definir a interface e usar os recursos que já temos prontos.

Veja a terceira parte em : C# - Cadastro de Clientes com Entity Framework em Camadas - III

Referências:

José Carlos Macoratti