.NET
- O padrão Repositório revisitado - I
![]() |
Neste artigo vamos rever os conceitos relacionados ao padrão repositório com um exemplo prático em uma aplicação ASP .NET MVC 5 usando a linguagem C#. |
Atualmente trabalhar com uma arquitetura em camadas no desenvolvimento de aplicações é quase um padrão.
E podemos implementar a arquitetura com 3, 4, 5 e n camadas, dependendo do contexto do nosso projeto.
Adotar uma arquitetura em camadas para o seu projeto visa estimular a organização do sistema em camadas coesas mas com um acoplamento fraco entre as mesmas.
Cada camada é formada por um conjunto de classes com um propósito e responsabilidade definidas.
Podemos representar uma arquitetura em 3 camadas (a mais usada) da seguinte forma:
![]() |
A camada superior conhece apenas a camada imediatamente inferior |
Ocorre que não é uma boa ideia acessar a lógica de acesso a dados diretamente na camada de negócios (BLL), pois isso cria um forte acoplamento da lógica de acesso a dados na lógica de negócios tornando a aplicação mais difícil de testar, estender e manter.
Assim, o acesso direto da camada de acesso a dados na camada de negócios causa os seguintes problemas:
Dificulta a realização de Testes Unitários da camada de negócios;
Cria dependências externas (Banco de dados) na lógica de negócio;
Duplica o código de acesso a dados através da camada de negócio;
É justamente para resolver esse problema que a utilização do padrão repositório é indicada.
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) |
O padrão Repository separa a lógica de acesso dados e mapeia essa lógica para entidades na lógica de negócio. Ele trabalhar com as entidades de domínio e realiza a lógica de acesso a dados.
No padrão Repository, as entidades de domínio e a lógica de acesso a dados se comunicam usando interfaces, e isso, esconde os detalhes do acesso a dados da camada de negócios.
Trocando em miúdos, a camada de negócio pode acessar os objetos de dados sem ter conhecimento da arquitetura de acesso a dados correspondente.
Dessa forma no padrão Repository, a lógica de negócio não tem conhecimento se o aplicativo esta usando LINQ to SQL ou Entity Framework ou qualquer outro ORM, e, no futuro as fontes de dados subjacentes podem ser alteradas sem afetar a lógica de negócio.
Assim, podemos destacar as seguintes vantagens na aplicação do padrão Repository:
A camada de negócios pode ser testada sem a necessidade de fontes externas
A lógica de acesso a dados pode ser testada separadamente
Não existe a duplicação de código
A estratégia de cacheamento dos dados para a fonte de dados pode ser centralizada
O desenvolvimento orientado ao domínio fica mais fácil
A centralização da lógica de acesso a dados , o que torna a manutenção mais fácil;
Vamos então para a parte prática onde irei implementar o padrão Repository criando um repositório genérico.
Recursos usados :
Implementando o padrão Repository
Abra o VS 2013 Express for web e clique em New Project;
A seguir selecione Visual C# -> ASP .NET Web Application;
Informe o nome Mvc_Repositorio e clique no botão OK;
A seguir selecione o template Empty, marque MVC e clique no botão OK;
Será criado um projeto contendo toda a estrutura de pastas criadas pelo framework ASP .NET MVC.
Vamos incluir um novo projeto do tipo Class Library em nossa solução.
No menu File clique em Add -> Project e selecione o template Class Library e informe o nome Mvc_Repositorio.Dominio;
Vamos incluir uma referência ao Entity Framework neste projeto via Nuget.
No menu TOOLS clique em Nuget Package Manager e a seguir em Manage Nuget Packages for Solution;
Selecione o Entity Framework e clique no botão Install escolhendo para ser instalado somente no projeto Mvc_Repositorio.Dominio.
Apague o arquivo Class1.cs criado por padrão e a seguir crie uma pasta chamada Repositorio no projeto Mvc_Repositorio.Dominio.
Nesta pasta vamos criar a nossa interface do Repositorio.
No menu PROJECT clique em Add New Item;
Selecione o template Interface e informe o nome IRepositorio.cs
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 implementados por qualquer classe que desejar usar a nossa interface.
Abaixo vemos os métodos definidos na nossa interface IRepositorio:
using System;
namespace Mvc_Repositorio.Dominio.Repositorio |
Vamos entender o código acima:
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) - Excluir 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.
Antes de implementar a interface IRepositorio vamos definir o nosso domínio.
Definindo o Domínio
Vamos criar uma pasta chamada Entidades no projeto Mvc_Repositorio.Dominio.
Selecione o projeto e no menu PROJECT clique em New Folder e informe o nome Entidades. Nesta pasta vamos definir as entidades do nosso domínio.
Para tornar as coisas bem simples eu vou definir apenas uma entidade chamada Usuario e vou mapear esta entidade para uma tabela Usuarios existente em um banco SQL Server chamado Cadastro.mdf.
Abaixo vemos a estrutura da tabela Usuarios:
Selecione a pasta criada e no menu PROJECT clique em Add Class e informe o nome Usuario.
Defina o código baixo nesta classe:
using System.ComponentModel.DataAnnotations;
using System.ComponentModel.DataAnnotations.Schema;
namespace Mvc_Repositorio.Dominio.Entidades
{
[Table("Usuarios")]
public class Usuario
{
[Key]
public int UsuarioId { get; set; }
[Required(ErrorMessage = "Informe o login do usuário.")]
[Display(Name = "Usuário")]
public string Nome { get; set; }
[Required(ErrorMessage = "Informe a senha do usuário.")]
[DataType(DataType.Password)]
public string Senha { get; set; }
[Required(ErrorMessage = "Informe o email do usuário.")]
public string Email { get; set; }
}
}
|
O código acima usa os atributos do Data Annotations para definir o mapeamento para a tabela Usuarios e restrições de validações que deverão ser aplicadas na renderização das views que iremos criar.
Agora para realizar o mapeamento ORM vamos definir uma classe onde iremos usar os recursos do Entity Framework através do DbSet.
Selecione a pasta criada e no menu PROJECT clique em Add Class e informe o nome Usuario.
Defina o código baixo nesta classe:
using System.Data.Entity;
namespace Mvc_Repositorio.Dominio.Entidades
{
public class UsuarioContexto : DbContext
{
public UsuarioContexto()
: base("name=ConexaoUsuarios")
{ }
protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
Database.SetInitializer<UsuarioContexto>(new CreateDatabaseIfNotExists<UsuarioContexto>());
}
public DbSet<Usuario> Usuarios { get; set; }
}
}
|
Nesta classe usamos o DbContext e realizamos o mapeamento da entidade Usuario com a tabela Usuarios.
O último detalhe que não podemos esquecer e definir no arquivo web.config da aplicação web a string de conexão ConexaoUsuarios do banco de dados Cadastro.mdf.
Implementando a interface IRepositorio na classe Repositorio
Selecione a pasta Repositorio do projeto de Dominio e selecione o 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:
using Mvc_Repositorio.Dominio.Entidades;
using System;
using System.Data.Entity;
using System.Linq;
using System.Linq.Expressions;
namespace Mvc_Repositorio.Dominio.Repositorio { public class Repositorio<T> : IRepositorio<T> , IDisposable where T : class { private UsuarioContexto Context; protected Repositorio()
{
Context = new UsuarioContexto();
}
public IQueryable<T> GetTodos()
{
return Context.Set<T>();
}
public IQueryable<T> Get(Expression<Func<T, bool>> predicate)
{
return Context.Set<T>().Where(predicate);
}
public T Procurar(params object[] key)
{
return Context.Set<T>().Find(key);
}
public T Primeiro(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); } } } |
Dessa forma como já temos o nosso repositório criado vamos definir agora as interfaces para representam o repositório específico para a entidade Usuario.
Então selecione a pasta Repositorio e no menu PROJECT clique em Add New Item;
Selecione o template Interface, informe o nome IUsuarioRepositorio.cs e clique no botão Add;
A seguir defina o código a seguir para a interface IUsuarioRepositorio :
using Mvc_Repositorio.Dominio.Entidades; namespace Mvc_Repositorio.Dominio.Repositorio { public interface IUsuarioRepositorio : IRepositorio<Usuario> { } } |
Deveremos criar também a classe que implementa a interface IUsuarioRepositorio.
Então selecione a pasta Repositorio e no menu PROJECT clique em Add New Item;
Selecione o template Class, informe o nome UsuarioRepositorio.cs e clique no botão Add;
A seguir defina o código a seguir para a classe UsuarioRepositorio :
using Mvc_Repositorio.Dominio.Entidades; namespace Mvc_Repositorio.Dominio.Repositorio { public class UsuarioRepositorio : Repositorio<Usuario>, IUsuarioRepositorio { } } |
Observe que não precisamos definir nenhum código nas interfaces e classes acima pois estamos usando o mecanismo da herança e da implementação da interface e assim estamos usando os métodos definidos na interface IRepositorio e na classe Repositorio. Note também que estamos usando as entidades que foram separadas no projeto de Dominio.
Neste momento nossa solução tem a seguinte estrutura:
Na próxima parte do artigo iremos criar a camada de negócios da nossa aplicação.
Então disse Jesus aos seus
discípulos: Se alguém quiser vir após mim, renuncie-se a si mesmo, tome sobre si
a sua cruz, e siga-me;
Porque aquele que quiser salvar a sua vida, perdê-la-á, e quem perder a sua vida
por amor de mim, achá-la-á.
Mateus 16:24,25
Veja os
Destaques e novidades do SUPER DVD Visual Basic
(sempre atualizado) : clique e confira !
Quer migrar para o VB .NET ?
Quer aprender C# ??
Quer aprender os conceitos da Programação Orientada a objetos ? Quer aprender o gerar relatórios com o ReportViewer no VS 2013 ? Quer aprender a criar aplicações Web Dinâmicas usando a ASP .NET MVC 5 ? |
Gostou ?
Compartilhe no Facebook
Compartilhe no Twitter
Referências:
Super DVD Vídeo Aulas - Vídeo Aula sobre VB .NET, ASP .NET e C#
Sistema para Pizzaria com Entity Framework 6 e padrão Repository