.NET

2 mar, 2015

Entity Framework 6 – Aplicação em camadas – criando o repositório da nossa solução – Parte 03

Publicidade

Neste artigo vamos continuar o nosso exemplo do artigo anterior agora criando o repositório da nossa solução.

Criando o repositório da nossa solução

O padrão de projeto Repository acrescenta uma camada de abstração no topo da camada de consultas e ajuda a eliminar a lógica duplicada na implementação do código de suas consultas ao modelo de entidades.

Foi Martin Fowler que definiu o padrão Repository no seu livro – Patterns of Enterprise Application Architecture – da seguinte forma:“Intermedeia entre o domínio e as camadas de mapeamento de dados usando uma interface de coleção para acessar objetos de domínio” (numa tradução livre by Macoratti)

Assim, um repositório é essencialmente uma coleção de objetos de domínio em memória, e, com base nisso, o padrão Repository permite realizar o isolamento entre a camada de acesso a dados (DAL) de sua aplicação, sua camada de apresentação (UI) e de negócios (BLL).

Ao utilizar o padrão Repository, você pode realizar a persistência e a separação de interesses em seu código de acesso a dados, visto que ele encapsula a lógica necessária para persistir os objetos do seu domínio na sua fonte de armazenamento de dados.

Em suma, você pode usar o padrão Repository para desacoplar o modelo de domínio do código de acesso a dados.

Martin Fowler afirma: “O padrão Repository faz a mediação entre o domínio e as camadas de mapeamento de dados, agindo como uma coleção de objetos de domínio em memória. Conceitualmente, um repositório encapsula o conjunto de objetos persistidos em um armazenamento de dados e as operações realizadas sobre eles, fornecendo uma visão mais orientada a objetos da camada de persistência e também dá suporte ao objetivo de alcançar uma separação limpa e uma forma de dependência entre o domínio e as camadas de mapeamento de dados” (http://martinfowler.com/eaaCatalog/repository.html)

Em uma das implementações do padrão repositório podemos começar definindo uma interface que atuará como a nossa fachada de acesso aos dados. Podemos usar a camada DAL e criar nesse projeto uma pasta para definir o nosso repositório; estamos assim organizando o nosso código.

Como nosso exemplo é mais simples, eu vou criar o repositório diretamente no projeto DAL (não vou criar a pasta) definindo uma interface com o nome IRepositorio.

Então, selecione o projeto DAL e no menu PROJECT clique em Add New Item. Selecione o template Interface, informe o nome IRepositorio.cs e clique no botão Add.

ef6_dalrp31

Agora vamos definir os métodos na nossa interface que deverão ser implementados para realizar o acesso e persistência dos dados na camada de acesso a dados.

Lembre-se que uma interface é um contrato que define como uma classe deve ser implementada, assim vamos definir assinaturas de métodos que deverão ser implementadas por qualquer classe que desejar usar a nossa interface.

Abaixo vemos os métodos definidos na nossa interface IRepositorio:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
namespace DAL
{
        public interface IRepositorio<T> where T : class
        {
            IQueryable<T> GetTodos();
            IQueryable<T> Get(Expression<Func<T, bool>> predicate);
            T Find(params object[] key);
            T First(Expression<Func<T, bool>> predicate);
            void Adicionar(T entity);
            void Atualizar(T entity);
            void Deletar(Func<T, bool> predicate);
            void Commit();
            void Dispose();
        }
}

Vamos fazer algumas observações sobre o código usado:

  1. Note que estamos usamos o namespace using System.Linq.Expressions, que contém classes e enumerações que permitem representar expressões de código no nível da linguagem, como objetos na forma de árvores de expressões;
  2. Na assinatura da classe estamos declarando public interface IRepositorio<T> where T : class  ; aqui, T é uma classe;
  3. IQueryable<T> GetTodos() – Este método retorna todos os dados como IQueryable, dessa forma podemos retornar a lista e aplicar expressões lambdas para filtrar e classificar os dados;
  4. IQueryable<T> Get(Expression<Func<T, bool>> predicate) – Retorna os dados que atendem o critério informado em tempo de execução via expressão lambada. Estamos usando o delegate Func e aplicando o predicate para verificar se o dado atende o critério (retorna true ou false);
  5. T Find(params object[] key) – Recebe um array de objetos e efetua a pesquisa pela chave primária;
  6. T First(Expression<Func<T, bool>> predicate) – Retorna o primeiro dado que atende o critério informado via expressão lambda. Usamos novamente o delegate Func e aplicamos o predicate para verificar se o dado atende o critério;
  7. void Adicionar(T entity) – Recebe o objeto T para realizar a inclusão no banco de dados;
  8. void Atualizar(T entity) – Recebe o objeto T para realizar a atualização no banco de dados;
  9. void Deletar(<Func<T, bool>> predicate) – Exclui registros usando uma condição definida na expressão lambda (via delegate Func) e aplicando o predicate (retorna true ou false) para verificar o critério;
  10.  void Commit() – Chama o método ChaveChanges() do contexto para efetivar todas as alterações realizadas no contexto. Ao final de cada operação você deve sempre chamar este método para efetivar as operações que foram feitas na memória no banco de dados. Se não fizer isso irá perder todas as operações realizadas;
  11. void Dispose() – Executa a limpeza dos objetos;

Observe que não temos nenhum comando SQL, nenhuma declaração de objetos ADO .NET como connection, command, dataset, datareader etc.

Já temos o contrato definido e agora vamos definir a classe que irá implementar esse contrato.

Implementando a interface IRepositorio na classe Repositorio

Vamos, então, criar uma classe chamada Repositorio, que irá implementar a nossa interface.

Então selecione o projeto DAL e no menu PROJECT clique em Add New Item.

Selecione o template Class, informe o nome Repositorio.cs e clique no botão Add.

Vamos definir a assinatura da classe Repositorio conforme a figura abaixo:

ef6_dalrp32

Note que estamos implementando a interface IRepositorio<T> e a interface IDisposable<T>.

A mensagem de alerta do compilador indica que a classe ainda não implementou os métodos definidos na Interface e precisa fazê-lo.

Vemos abaixo o código da classe Repositorio implementando a interface IRepositorio e a interface IDisposable:

using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Linq.Expressions;
namespace DAL
{
    public class Repositorio<T> : IRepositorio<T> , IDisposable where T : class
    {
        private CadastroEntities Context;

        protected Repositorio()
        {
            Context = new CadastroEntities();
        }

        public IQueryable<T> GetTodos()
        {
            return Context.Set<T>();
        }

        public IQueryable<T> Get(Expression<Func<T, bool>> predicate)
        {
            return  return Context.Set<T>().Where(predicate);
        }

        public T Find(params object[] key)
        {
            return Context.Set<T>().Find(key);
        }

        public T First(Expression<Func<T, bool>> predicate)
        {
            return Context.Set<T>().Where(predicate).FirstOrDefault();
        }

        public void Adicionar(T entity)
        {
            Context.Set<T>().Add(entity);
        }

        public void Atualizar(T entity)
        {
            Context.Entry(entity).State = EntityState.Modified;
        }

        public void Deletar(Func<T, bool> predicate)
        {
            Context.Set<T>()
           .Where(predicate).ToList()
           .ForEach(del => Context.Set<T>().Remove(del));
        }

        public void Commit()
        {
            Context.SaveChanges();
        }

        public void Dispose()
        {
            if (Context != null)
            {
                Context.Dispose();
            }
                GC.SuppressFinalize(this);
            }
        }
}

Na próxima parte do artigo vamos explicar em detalhes cada implementação feita na classe Repositorio.