.NET Core - Implementando o padrão Repositório - II


  Hoje veremos como implementar o padrão repositório na plataforma .NET Core.

O objetivo principal deste artigo é mostrar como implementar o padrão repositório na plataforma .NET Core.

Vou aplicar o conceito de arquitetura em camadas para realizar um nível mínimo de separação de responsabilidades e de organização de código.

Na abordagem usada vamos criar uma solução no VS 2017 Community contendo três projetos :

Vou aplicar alguns padrões de projeto como o padrão Repository e o padrão Unit Of Work e vou usar o Entity Framework Core para persistência.

Neste artigo iremos implementar um repositório genérico onde vamos definir a interface IRepository<T> e a sua implementação na classe Repositoy<T>

Vamos implementar o padrão Unit Of Work que pode ser visto como um contexto, sessão ou objeto que acompanha as alterações das entidades de negócio durante uma transação sendo também responsável pelo gerenciamento dos problemas de concorrência que podem ocorrer oriundos dessa transação.

Da mesma forma vamos criar uma interface IUnitOfWork e a classe UnitOfWork que implementa esta interface.

Para materializar esse repositório genérico vou definir um repositório para um domínio Cliente onde vou criar a interface IClienteRepository e sua implementação ClienteRepository e assim gerenciar as informações de Cliente fazendo um CRUD básico definindo essa lógica na camada de negócios.

Abaixo vemos o diagrama de classes para os artefatos gerados no projeto:

Assim, o padrão de repositório é a abordagem para abstrair os detalhes da camada de acesso a dados do restante do aplicativo. É muito mais fácil usar um repositório genérico para evitar que a lógica de negócios se misture com a lógica de acesso a dados.

O repositório atua como um mediador entre a camada de acesso a dados e as camadas de negócios do aplicativo. Ele consulta a fonte de dados, mapeia os dados da fonte de dados para uma entidade e persiste alterações na entidade para a fonte de dados.

Dentre os benefícios em usar o padrão repositório temos :

Recursos :

Criando o projeto no VS 2017 Community

Abra o VS 2017 Community e crie uma solução em branco via menu File-> New Project;

Selecione o template Other Type Projects ->Visual Studio Solution;

Clique em Blank Solution e inform e nome EstudoRepo;

A seguir inclua um novo projeto do tipo Class Library neste solução via menu File ->Add -> New Project;

Selecione o template Class Library(.NET Standard), informe o nome DataAccess e clique em OK;

Exclua o arquivo Class1.cs criado e crie neste projeto 3 pastas :

Agora vamos incluir uma referência no projeto ao Entity Framework Core que vamos usar para acesso a dados e persistência.

No menu Tools -> Nuget Package Manager -> Manage Nuget Packages for Solution;

Na guia Browse selecione :  entityframeworkcore.sqlserver  e clique no botão Install;

Após esses passos seu projeto deverá possuir a seguinte estrutura:

Definindo o modelo de domínio

O modelo de domínio representa o domínio da nossa aplicação que para o exemplo deste artigo será representado por uma classe Cliente que representa os dados dos clientes que iremos gerenciar.

Na pasta Domain inclua a classe Cliente com o código abaixo:

public class Cliente
{
        public int ClienteId { get; set; }
        public string Nome { get; set; }
        public string Email { get; set; }
}

Vamos usar essa classe também como um Data transfer object. (DTO)

Definindo a classe de contexto

Como eu vou usar o EF Core tenho que criar uma classe de contexto que herda de DbContext onde vou definir o provedor para o banco de dados e a string de conexão com o banco de dados SQL Server que iremos acessar.

Na pasta Context crie uma classe chamada AppDbContext com o código abaixo:

using DataAccess.Domain;
using Microsoft.EntityFrameworkCore;
namespace DataAccess.Context
{
    public class AppDbContext : DbContext
    {
        public DbSet<Cliente> Clientes { get; set; }

        public AppDbContext(DbContextOptions<AppDbContext> options) : base(options)
        { }
        public AppDbContext()
        { }
        protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        {
            optionsBuilder.UseSqlServer(@"Data Source=Macoratti;Initial Catalog=Cadastro;Integrated Security=True");
        }
    }
}

Nesta classe definimos o seguinte:

  1. O mapeamento da entidade Cliente para a tabela Clientes via DbSet;
  2. O provedor do banco de dados SQL Server
  3. A string de conexão indicando o servidor e banco de dados usados;

Vamos acessar o banco de dados Cadastro.mdf que já existe no SQL Server e a tabela Clientes que possui os seguintes dados:

Implementando o Repositório

Começaremos desenvolvendo nosso Repositório definindo uma interface chamada IRepository<T> na pasta Repository

A interface definida será bem simples, com apenas alguns métodos, assim não teremos uma implementação completa, mas sim um exemplo que serve para destacar o tipo de funções mais comuns que são implementadas em um padrão de repositório.

using System;
using System.Collections.Generic;
using System.Linq.Expressions;
namespace DataAccess.Repository
{
    public interface IRepository<T> where T : class
    {
        IEnumerable<T> Get();
        IEnumerable<T> Get(Expression<Func<T, bool>> predicate);
        T GetById(Expression<Func<T, bool>> predicate);
        void Add(T entity);
        void Delete(T entity);
        void Update(T entity);
    }
}

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-  IEnumerable<T> Get() - Este método retorna os dados como IEnumerable;

4-  IEnumerable<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- void Add(T entity) - Recebe o objeto T para realizar a inclusão no banco de dados;

6- void Update(T entity) - Recebe o objeto T para realizar a atualização no banco de dados;

7- void Delete(T entity) - Recebe o objeto T e realiza a exclusão no banco de dados;

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.

Selecione a pasta Repository e no menu PROJECT clique em Add New Item;

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

Inclua o código abaixo nesta classe:

using DataAccess.Context;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
namespace DataAccess.Repository
{
    public class Repository<T> : IRepository<T> where T : class
    {
        private readonly AppDbContext _context;
        public Repository(AppDbContext context)
        {
            _context = context;
        }
        public void Add(T entity)
        {
            _context.Set<T>().Add(entity);
        }
        public void Delete(T entity)
        {
            _context.Set<T>().Remove(entity);
        }
        public void Update(T entity)
        {
            _context.Entry(entity).State = EntityState.Modified;
            _context.Set<T>().Update(entity);
        }
        public IEnumerable<T> Get()
        {
            return _context.Set<T>().AsEnumerable<T>();
        }
        public IEnumerable<T> Get(Expression<Func<T, bool>> predicate)
        {
            return _context.Set<T>().Where(predicate).AsEnumerable<T>();
        }
        public T GetById(Expression<Func<T, bool>> predicate)
        {
            return _context.Set<T>().SingleOrDefault(predicate);
        }   
    }
}

Na próxima parte do artigo vamos explicar a implementação feita na classe Repository<T>.

"Com o ouvir dos meus ouvidos ouvi, mas agora te vêem os meus olhos.
Por isso me abomino e me arrependo no pó e na cinza. "

Jó 42:5,6

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:


José Carlos Macoratti