Proposta de Arquitetura – Parte 4 – Acesso a Dados

Neste artigo vamos conhecer as classes que são responsáveis pelo acesso aos dados, realizando a criação, atualização exclusão e consulta dos registros, através dos objetos que representam as tabelas do banco (entidades).

 

Começaremos pela interface IRepositorioCAD:

 

************ IRepositorioCAD.cs ************

 

using System;

using System.Collections.Generic;

using System.Data.Metadata.Edm;

using System.Data.Objects;

using System.Data.Objects.DataClasses;

using System.Linq.Expressions;

using HLMI.Cadastro.CES;

 

namespace HLMI.Cadastro.CAD

{

    public interface IRepositorioCAD<T> where T : EntityObject

    {

        T VerRegistroPorCodigo(int codigo);

        T Salvar(T registro);

        bool Atualizar(T registro);

        bool Excluir(T registro);

        EntitySetBase VerEntidadeBase(ObjectContext context, Type entityType);

        List<T> ListarTodos();

        List<T> ListarPorExpressao(Expression<Func<T, bool>> expression);

        List<T> ListarPorExpressao(Expression<Func<T, bool>> expression1, Expression<Func<T, bool>> expression2);

        List<T> ListarPorExpressao(Expression<Func<T, bool>> expression1, Expression<Func<T, bool>> expression2, Expression<Func<T, bool>> expression3);

        List<T> ListarPorExpressao(Expression<Func<T, bool>> expression1, Expression<Func<T, bool>> expression2, Expression<Func<T, bool>> expression3, Expression<Func<T, bool>> expression4);

        List<T> ListarPorExpressao(Expression<Func<T, bool>> expression1, Expression<Func<T, bool>> expression2, Expression<Func<T, bool>> expression3, Expression<Func<T, bool>> expression4, Expression<Func<T, bool>> expression5);

        List<T> ListarPorExpressao(Expression<Func<T, bool>> expression1, Expression<Func<T, bool>> expression2, Expression<Func<T, bool>> expression3, Expression<Func<T, bool>> expression4, Expression<Func<T, bool>> expression5, Expression<Func<T, bool>> expression6);

    }

}

 

***************************************

 

O objetivo de uma interface é separar o nome do metodo da sua implementação, assim como um objeto pode ser referenciado através da sua interface. Quando uma classe que implementa uma interface for criada, podemos instanciar esta classe através da sua interface, ou criar métodos que tem como parâmetros uma interface, assim qualquer classe que a implemente pode ser utilizada neste parâmetro. Essa é uma característica da herança na programação orientada a objetos.

 

A classe a seguir implementa a interface que apresentamos, e ela é a classe base para manipularmos todas as entidades. É a classe BaseCAD:

 

*********** BaseCAD.cs ******************

 

using System;

using System.Collections.Generic;

using System.Data;

using System.Data.Metadata.Edm;

using System.Data.Objects;

using System.Data.Objects.DataClasses;

using System.Linq;

using System.Linq.Expressions;

using HLMI.Cadastro.CES;

using LinqKit;

 

namespace HLMI.Cadastro.CAD

{

    public class BaseCAD<T> :  IRepositorioCAD<T> where T : EntityObject

    {

        #region Atributos

 

        private HLMI_CadastroEntities entidades;

        private IObjectSet<T> objeto;

        private ObjectSet<T> en;

 

        public HLMI_CadastroEntities Entidades

        {

            get { return entidades; }

            set { entidades = value; }

        }

 

        public IObjectSet<T> Objeto

        {

            get { return objeto; }

            set { objeto = value; }

        }

 

        public ObjectSet<T> En

        {

            get { return en; }

            set { en = value; }

        }

 

        #endregion

 

        #region Construtor

 

        public BaseCAD()

        {

            Entidades = new HLMI_CadastroEntities();

            En = Entidades.CreateObjectSet<T>();

            Objeto = En;

        }

 

        #endregion

 

        #region Sem Auditoria

 

        public T Salvar(T registro)

        {

            En.MergeOption = MergeOption.NoTracking;

            Objeto.AddObject(registro);

            try

            {

                Entidades.SaveChanges();

            }

            catch (Exception e)

            {

                return null;

            }

            return registro;

        }

 

        public bool Atualizar(T registro)

        {

            EntityKey key;

            object originalItem;

            En.MergeOption = MergeOption.NoTracking;

            key = Entidades.CreateEntityKey(VerEntidadeBase(Entidades, registro.GetType()).Name, registro);

            if (Entidades.TryGetObjectByKey(key, out originalItem))

            {

                Entidades.ApplyCurrentValues(key.EntitySetName, registro);

            }

            try

            {

                Entidades.SaveChanges();

            }

            catch (Exception e)

            {

                return false;

            }

            return true;

        }

 

        public bool Excluir(T registro)

        {

            EntityKey key;

            En.MergeOption = MergeOption.NoTracking;

            key = Entidades.CreateEntityKey(VerEntidadeBase(Entidades, registro.GetType()).Name, registro);

            var obj = (T)Entidades.GetObjectByKey(key);

            Objeto.DeleteObject(obj);

            try

            {

                Entidades.SaveChanges();

            }

            catch (Exception e)

            {

                return false;

            }

            return true;

        }

 

        #endregion

        

        #region Consultas

 

        public T VerRegistroPorCodigo(int codigo)

        {

            string containerName = Entidades.DefaultContainerName;

            string setName = Entidades.CreateObjectSet<T>().EntitySet.Name;

            var entityKey = new EntityKey(containerName + “.” + setName, “Id”, codigo);

            return (T)Entidades.GetObjectByKey(entityKey);

        }

 

        public List<T> ListarTodos()

        {

            return Objeto.ToList();

        }

 

        public List<T> ListarPorExpressao(Expression<Func<T, bool>> expression)

        {

            var retorno = Entidades.CreateObjectSet<T>().AsExpandable().Where(expression.Compile());

            if (retorno != null)

                if (retorno.Count() > 0)

                    return retorno.ToList();

            return null;

        }

 

        public List<T> ListarPorExpressao(Expression<Func<T, bool>> expression1, Expression<Func<T, bool>> expression2)

        {

            var retorno = Entidades.CreateObjectSet<T>().AsExpandable().Where(expression1.Compile()).Where(expression2.Compile());

            if (retorno != null)

                if (retorno.Count() > 0)

                    return retorno.ToList();

            return null;

        }

 

        public List<T> ListarPorExpressao(Expression<Func<T, bool>> expression1, Expression<Func<T, bool>> expression2, Expression<Func<T, bool>> expression3)

        {

            var retorno = Entidades.CreateObjectSet<T>().AsExpandable().Where(expression1.Compile()).Where(expression2.Compile()).Where(expression3.Compile());

            if (retorno != null)

                if (retorno.Count() > 0)

                    return retorno.ToList();

            return null;

        }

 

        public List<T> ListarPorExpressao(Expression<Func<T, bool>> expression1, Expression<Func<T, bool>> expression2, Expression<Func<T, bool>> expression3, Expression<Func<T, bool>> expression4)

        {

            var retorno = Entidades.CreateObjectSet<T>().AsExpandable().Where(expression1.Compile()).Where(expression2.Compile()).Where(expression3.Compile()).Where(expression4.Compile());

            if (retorno != null)

                if (retorno.Count() > 0)

                    return retorno.ToList();

            return null;

        }

 

        public List<T> ListarPorExpressao(Expression<Func<T, bool>> expression1, Expression<Func<T, bool>> expression2, Expression<Func<T, bool>> expression3, Expression<Func<T, bool>> expression4, Expression<Func<T, bool>> expression5)

        {

 

            var retorno = Entidades.CreateObjectSet<T>().AsExpandable().Where(expression1.Compile()).Where(expression2.Compile()).Where(expression3.Compile()).Where(expression4.Compile()).Where(expression5.Compile());

            if (retorno != null)

                if (retorno.Count() > 0)

                    return retorno.ToList();

            return null;

        }

 

        public List<T> ListarPorExpressao(Expression<Func<T, bool>> expression1, Expression<Func<T, bool>> expression2, Expression<Func<T, bool>> expression3, Expression<Func<T, bool>> expression4, Expression<Func<T, bool>> expression5, Expression<Func<T, bool>> expression6)

        {

            var retorno = Entidades.CreateObjectSet<T>().AsExpandable().Where(expression1.Compile()).Where(expression2.Compile()).Where(expression3.Compile()).Where(expression4.Compile()).Where(expression5.Compile()).Where(expression6.Compile());

            if (retorno != null)

                if (retorno.Count() > 0)

                    return retorno.ToList();

            return null;

        }

 

        #endregion

 

        #region Auxiliar

 

        public EntitySetBase VerEntidadeBase(ObjectContext context, Type entityType)

        {

            if (context == null)

            {

                throw new ArgumentNullException(“context”);

            }

            if (entityType == null)

            {

                throw new ArgumentNullException(“entityType”);

            }

            EntityContainer container = context.MetadataWorkspace.GetEntityContainer(context.DefaultContainerName, DataSpace.CSpace);

            if (container == null)

            {

                return null;

            }

            EntitySetBase entitySet = container.BaseEntitySets.Where(item => item.ElementType.Name.Equals(entityType.Name)).FirstOrDefault();

            return entitySet;

        }

 

        #endregion

    }

}

 

***************************************

 

A classe BaseCAD permite realizar as principais operações com qualquer entidade do sistema. Por exemplo: se quero consultar uma entidade Cliente através do seu ID, podemos usar o método VerRegistroPorCodigo da seguinte forma:

 

BaseCAD<Cliente> base = new BaseCAD<Cliente>();

Cliente cliente = base.VerRegistroPorCodigo(1);

 

onde o valor 1 (um) é o valor do Id no registro que está no banco de dados, e o retorno é o objeto cliente preenchido com todos os artributos que retornaram do banco de dados.

 

Estas duas classes devem ser criadas no projeto HLMI.Cadastro.CAD, e podemos criar outras classes que herdam de BaseCAD para acesso aos dados das entidades. Por exemplo: caso eu queira criar uma consulta específica para Cliente, então devo criar a classe ClienteCAD (observe a nomenclatura) que herda de BaseCAD, da seguinte forma:

 

*********** ClienteCAD *******************

 

using System.Collections.Generic;

using System.Linq;

using HLMI.Cadastro.CES;

 

namespace HLMI.Cadastro.CAD

{

    public class ClienteCAD : BaseCAD<Cliente>

    {

        public List<Cliente> VerRegistro(Cliente registro)

        {

            List<Cliente> consulta = this.ListarTodos();

 

            if (registro.Id > 0)

            {

                consulta = consulta.Where(c => c.Id == registro.Id).ToList();

            }

            if (!string.IsNullOrEmpty(registro.NomeCliente))

            {

                consulta = consulta.Where(c => c.NomeCliente.Contains(registro.NomeCliente)).ToList();

            }

            if (!string.IsNullOrEmpty(registro.Endereco))

            {

                consulta = consulta.Where(c => c.Endereco.Contains(registro.Endereco)).ToList();

            }

            

            return consulta.ToList();

        }

    }

 

}

 

***************************************

 

O método VerRegistro é um método exclusivo da classe ClienteCAD, que auxilia na consulta ao cliente pelo nome ou pelo endereço, se estiverem preenchidos. Ou seja, em um formulário de consulta, este método retorna uma lista de acordo com os campos informados no formulário (digamos que sejam apenas dois: nome e endereço).

 

No próximo artigo, abordaremos das classes da camada de lógiga de negócios (CLN).