Design Patterns: Repository com Dapper SQL e MongoDB

Disponível também em inglês

Nesse artigo eu mostro como usar o Repository Pattern para acessar banco de dados. Eu demostro esse conceito usando o banco de dados SQL com o componente de acesso a dados Dapper (Stackoverflow) e outro usando banco de dados MongoDB com o driver oficial do .NET.

MongoDB é um dos bancos de dados gratuitos NÃO-RELACIONAL mais populares que existem. Isso quer dizer, comparando com o SQL Server, ele não possui tabelas que se relacionam entre si através de chaves primárias ou secundárias, e sim MongoDB trabalha com documentos (normalmente em JSON) que podem armazenar um conjunto de dados inteiro.

Conheça mais a fundo Repository Pattern e outros Design Patterns no meu eBook totalmente gratuito da série Programação no Mundo Real: Design Patterns vol.1.

Repository Pattern com Dapper SQL e MongoDB
 

Uma das principais regras do Repository Pattern é que a classe de negócios não precisa saber onde os dados estão armazenados ou simplemente não precisa saber qual é o banco de dados que está sendo utilizado.

Vamos começar essa parada!

Para esse código, você poderá usar o Visual Studio 2017 se preferir, mas dê uma olhada no artigo que escrevi UNBOXING VS2017: Primeiras Impressões no Mundo Real decida se realmente precisa do 2017.
 

Repository Pattern

O que é ou para que serve?
É um elo de ligação entre a camada de negócios e a camada de acesso a dados sem que a camada de negócios saiba qual é a base de dados que está sendo acessada.

Onde uso?
No acesso a base de dados.

Principal regra ou cenário:
Criar uma interface e uma classe que implementa essa interface. Nessa classe herde de uma outra classe básica que fará o acesso a base de dados correspondente.

 
Repository Pattern com Dapper SQL e MongoDB
 

O objetivo principal do exemplo é criar um método para buscar “taxas” (para calcular alguma coisa) em determinado repositório de dados.

Vamos definir a interface ITaxaRepository para o repositório:

public interface ITaxaRepository : IDisposable
{
   Task<IEnumerable<Models.Taxa>> ListarTaxa(int codigo);
}

 

Segundo passo é criar a classe do repositório para o MongoDB:

public class MongoDBTaxaRepository : MongoDBRepository, ITaxaRepository
{
        public async Task<IEnumerable<Taxa>> ListarTaxa(int codigo)
        {
            // comente esse bloco quando instalar o MONGODB, criar a tabela e carregar de dados antes.
            return await Task.Run(() =>
            {
                var taxas = new List<Taxa>();
                taxas.Add(new Taxa { Codigo = 1, Valor = 10, Fator = 2 });

                return taxas;
            });

            //código da implementação de mongodb
            return await Database.GetCollection<Taxa>("Taxas")
                .Find(x => x.Codigo == codigo)
                .ToListAsync();
        }
}

 

A classe de MongoDBTaxaRepository busca as taxas no MongoDB e serializa o documento em uma lista de Taxa. Uma coisa interessante a perceber é que essa classe herda de outra classe básica MongoDBRepository.

MongoDBRepository server para se conectar ao MongoDB e pode ser facilmente reutilizada:

public class MongoDBRepository : IDisposable
    {
        public MongoDBRepository()
            : this("localhost")
        {

        }

        public MongoDBRepository(string databaseName)
        {
            DatabaseName = databaseName;
            _client = new MongoClient();
            _database = _client.GetDatabase(DatabaseName);
        }

        public void Dispose()
        {
            _client = null;
            _database = null;
        }

        public string DatabaseName { get; set; }
        private IMongoClient _client;
        private IMongoDatabase _database;

        public IMongoDatabase Database
        {
            get
            {
                return _database;
            }
        }
    }

 

O próximo passo e criar a classe de acesso ao banco de dados SQL usando Dapper, então vamos fazer isso já!

DapperTaxaRepository com Dapper acessando SQL Server:

public class DapperTaxaRepository : SqlServerRepository, ITaxaRepository
    {
        public async Task<IEnumerable<Taxa>> ListarTaxa(int codigo)
        {
            var command = @"SELECT  Valor, Fator, Codigo 
                            FROM    Taxas 
                            WHERE   Codigo = @codigo";

            return await Database.QueryAsync<Taxa>(command, new { codigo = codigo });
        }
    }

 

O uso do Dapper é muito simples pois possui diversos Extensions Methods úteis para realizar as consultas e operações no banco de dados SQL.

O comando básico para consultas com Dapper é enviar uma string contendo o comando SQL para o método QueryAsync explicitando a serialização/conversão dos dados para a model Taxa. No último parâmetro deste método, passe um objeto anônimo para ser usado na cláusula WHERE. Fácil hein! Retornará uma lista de taxas.

Ambas as classes MongoDBTaxaRepository e DapperTaxaRepository implementam a interface ITaxaRepository.

DapperTaxaRepository também herda de uma classe básica SqlServerRepository, que serve para se conectar ao banco de dados SQL e também pode facilmente ser reutilizada:

public class SqlServerRepository : IDisposable
    {
        public SqlServerRepository()
            : this("sqlserver")
        {

        }

        public SqlServerRepository(string connectionStringId)
        {
            _connectionStringId = connectionStringId;
        }

        public virtual string ConnnectionStringId
        {
            get
            {
                return _connectionStringId;
            }
        }

        protected SqlConnection Database
        {
            get
            {
                if (_connection == null)
                {
                    if (string.IsNullOrEmpty(_connectionString))
                    {
                        _connectionString = ConfigurationManager.ConnectionStrings[ConnnectionStringId].ConnectionString;
                    }

                    _connection = new SqlConnection(_connectionString);
                }

                return _connection;
            }
        }

        public SqlServerRepository UseConnectionStringId(string connectionStringId)
        {
            _connectionStringId = connectionStringId;

            return this;
        }

        public SqlServerRepository UseConnectionString(string connectionString)
        {
            _connectionString = connectionString;

            return this;
        }

        public virtual void Dispose()
        {
            if (_connection != null)
            {
                _connection.Close();
                _connection.Dispose();
                _connection = null;
            }
        }

        private SqlConnection _connection = null;
        private string _connectionStringId;
        private string _connectionString;
    }

 

Exemplos de uso:

// Exemplos de chamadas paralelas usando diferentes repositórios

// TaxaService se vira para achar o repositório
var calculoA = TaxaService.CalcularTaxa(1);

// TaxaService recebe o repositório (instanciado via Dependency Injection)
var calculoB = TaxaService.CalcularTaxa(1, _repository);

// TaxaService recebe o repositório especifico do MongoDB
var calculoC = TaxaService.CalcularTaxa(1, new MongoDBTaxaRepository());

await Task.WhenAll(calculoA, calculoB, calculoC);

 

Eu costumo usar Dependency Injection na definição dos serviços, onde configuro o apontamento uma interface para uma determinada classe sem explicitá-la (primeiro exemplo).

Conheça mais a fundo Dependency Injection no meu eBook totalmente gratuito da série Programação no Mundo Real: Design Patterns vol.1.

Bom é isso. Espero que tenha ajudado.

Ajude a aprimorar o conteúdo deste site sugerindo um artigo ou tema.

Repository Pattern com Dapper SQL e MongoDB

Repository SQL Dapper MongoDB: Perguntas, sugestões ou críticas são bem vindas. Boa sorte!

Esse artigo dedico as 30 Pessoas que Influenciaram Minha Carreira Profissional.


 

Faça download completo do código fonte no github.
Sobre o Autor:
Trabalha como arquiteto de soluções e desenvolvedor, tem mais de 18 anos de experiência em desenvolvimento de software em diversas plataformas sendo mais de 16 anos somente para o mercado de seguros.