ADO .NET - Usando o Micro ORM Dapper .net


  Neste artigo vou apresentar os conceitos básicos sobre o Micro ORM Dapper mostrando como podemos usá-lo em aplicações feitas na plataforma .NET.

Uma das operações comuns no desenvolvimento de um aplicativo de negócios é acessar dados usando um banco de dados relacional. Se você é um desenvolvedor .NET já deve saber que a plataforma .NET oferece muitas alternativas para realizar essa tarefa.

Podemos usar ADO .NET , LINQ to SQL , NHibernate e Entity Framework, apenas para citar as tecnologias de acesso a dados mais usadas na plataforma .NET.

Nos últimos anos a utilização de ferramentas ORM como o NHibernate e o Entity Framework têm crescido muito, afinal trabalhar com classes e objetos e abstrair os comandos SQL e os objetos da ADO .NET torna o trabalho mais simples, visto que a ferramenta ORM pode realizar o trabalho de mapeamento entre as tabelas e as entidades para nós de forma automática.

Infelizmente neste mundo nada é perfeito, e, usar uma ferramenta ORM sem conhecer muito bem o seu funcionamento pode camuflar problemas gravíssimos em uma aplicação mesmo que ele continue funcionando sem erros. (O problema Select + 1).  Outro problema é que o código gerado pelo ORM pode ser muito complexo e difícil de otimizar.

Acresça a tudo isso o fato de que quando você usa uma ferramenta ORM você esta incluindo uma camada a mais na sua aplicação e isso vai afetar o seu desempenho de uma forma mais ou menos sensível dependendo de como você usou a ferramenta ORM.  No caso do Entity Framework e o Linq to SQL ambos utilizam expressões LINQ causando sobrecarga no desempenho ao traduzir as instruções SQL nativas.

Neste cenário foi que surgiram os Micros ORM criados diretamente sobre ADO  .NET e com uma proposta de aumentar o desempenho das iterações com o banco de dados relacionais. De forma bem simplificada, eles usam Reflection (dynamic a partir da versão 4.0 da plataforma .NET) para gerar objetos a partir do resultado da leitura dos dados.

Abaixo, a título de comparação, temos uma figura que compara o desempenho de consultas com diversas ferramentas para acesso a dados:

(fonte : https://github.com/StackExchange/dapper-dot-net )

Dessa forma, os Micros ORMs são ferramentas simples e que oferecem um ótimo desempenho no acesso a dados. Dentre os mais conhecidos temos:

Você pode acessar o link de cada um deles e ver mais detalhes.

Neste artigo eu vou mostrar como usar o Dapper .net que foi criado por Sam Saffron e disponibilizou o projeto como open source para toda a comunidade.

Recursos usados:

Nota: Baixe e use a versão Community 2015 do VS ela é grátis e é equivalente a versão Professional.

Usando o Dapper .net

Abra o VS Community e clique em New Project;

Selecione a linguagem Visual C# e o template Console Application;

Informe o nome da solução como Usando_Dapper e clique no botão OK;

Após criar o projeto vamos incluir a referência a biblioteca do Dapper .net e isso pode ser feito de duas formas:

  1. Acessar diretamente o repositório do Dapper em https://github.com/StackExchange/dapper-dot-net . Ele é um arquivo único( ) que vai estender sua interface IDbConnection.

  2. Instalar o Dapper no seu projeto usando o Nuget (creio que a opção mais simples)

No menu Tools clique no link para acessar o repositório Nuget e procure pelo pacote Dapper selecionando-o e clicando no botão Install:

Nota: Você pode instalar o pacote via Console usando o comando : Install-Package Dapper

Para mostrar como usar o Dapper vou usar o banco de dados Northwind.mdf e trabalhar com as tabelas Customers , Products  e Suppliers.

Vamos armazenar a string de conexão com o banco de dados no arquivo App.Config :

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <startup> 
        <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
    </startup>
<connectionStrings>
     <add name="conexaoNorthwind" connectionString="Data Source=.\sqlexpress;Initial Catalog=Northwind;Integrated Security=True" providerName="System.Data.SqlClient" />
</connectionStrings>
</configuration>

Para acessar a string de conexão no arquivo App.Config vamos incluir  uma referência ao namespace System.Configuration no projeto :

Agora já temos tudo pronto para mostrar como usar o Dapper.

Então vamos lá...

Defina o código abaixo que obtém a string de conexão do arquivo App.Config na classe Program:

static string strConexao = ConfigurationManager.ConnectionStrings["conexaoNorthwind"].ConnectionString;

1- Acessando dados no SQL Server - Criando uma consulta simples para acessar a tabela Customers

   private static void Exemplo1()
   {	
            SqlConnection conexaoBD = new SqlConnection(strConexao);
            conexaoBD.Open();
            var resultado = conexaoBD.Query("Select * from Customers");
            Console.WriteLine("{0} - {1} - {2} ", "Código", "Nome do Contato", "Endereco do Cliente");
            foreach (dynamic cliente in resultado)
            {
                Console.WriteLine("{0} - {1} - {2} ", cliente.CustomerID, cliente.ContactName, cliente.Address);
            }
            conexaoBD.Close();
   }

 

 

Observe que usamos o método de extensão Query(), existem muitos outros, e informamos o comando SQL e percorremos o resultado usando dynamic, pois não temos aqui uma classe como retorno, para exibir as informações desejadas:

Estamos retornando uma lista de objetos dinâmicos  eliminando a necessidade de definir objeto DTO e simplificando o código.

Duas coisas importantes devem ser destacadas :

  1. Todos os métodos de extensão do Dapper assumem que a conexão já esta aberta. Se a conexão estiver fechada o código vai falhar

  2. Você é responsável por abrir e fechar as conexões

2- Retornado uma lista tipada de objetos

Vamos agora definir uma classe Produto e uma classe Fornecedor em nosso projeto com o código abaixo:

public class Produto
{
    public int ProductId { get; set; }
    public string ProductName { get; set; }
    public int SupplierID { get; set; }
    public int CategoryID { get; set; }
    public string QuantityPerUnit { get; set; }
    public decimal UnitPrice { get; set; }
    public short? UnitsInStock { get; set; }
    public short? UnitsOnOrder { get; set; }
    public short? ReorderLevel { get; set; }
    public bool Discontinued { get; set; }   
    // referencia
    public Fornecedor Fornecedor { get; set; }
}
public class Fornecedor
    {
        public int SupplierID { get; set; }
        public string CompanyName { get; set; }
        public string ContactName { get; set; }
        public string ContactTitle { get; set; }
        public string Address { get; set; }
        public string City { get; set; }
        public string PostalCode { get; set; }
        public string Country { get; set; }
        public IEnumerable<Produto> Produtos { get; set; }
    }

 

Agora vamos acessar a tabela Produtos e retornar uma lista selecionada de objetos tipados usando Dapper:

     private static void Exemplo2()
    {
            using (var conexaoBD = new SqlConnection(strConexao))
            {
                IEnumerable produtos = conexaoBD .Query<Produto>("Select * from Products");
                Console.WriteLine("{0} - {1} - {2} ", "Código", "Nome do Produto", "Preço do Produto");
                foreach (Produto produto in produtos)
                {
                    Console.WriteLine("{0} - {1} - {2}", produto.ProductID, produto.ProductName, produto.UnitPrice);
                }
            }
    }

Nesta consulta obtemos uma lista de objetos Produto (POCO). O Dapper usa os recursos do MSIL para acessar o data reader e converter os dados para o objeto de domínio.

3- Criando consultas com parâmetros

Agora vamos realizar uma consulta com parâmetros. É muito simples, basta definir a consulta com o parâmetro e depois passar um objeto anônimo com o valor desejado para o parâmetro.

  private static void Exemplo3()
        {
            using (var conexaoBD = new SqlConnection(strConexao))
            {
                IEnumerable produtos = conexaoBD .Query<Produto>
                    (
                      "Select ProductID, ProductName, UnitPrice from Products Where UnitPrice > @Preco", new { Preco = 40 }
                    );
                Console.WriteLine("{0} - {1} - {2} ", "Código", "Nome do Produto", "Preço do Produto");
                foreach (Produto produto in produtos)
                {
                    Console.WriteLine("{0} - {1} - {2}", produto.ProductID, produto.ProductName, produto.UnitPrice);
                }
            }
        }
 

No código acima temos a consulta filtrando pelo preço unitário : "Select ProductID, ProductName, UnitPrice from Products Where UnitPrice > @Preco"

Estamos definindo o parâmetro @Preco que a seguir criando um objeto anônimo passando o valor para o parâmetro: new { Preco = 40 }

4- Retornando múltiplos objetos com uma consulta

Agora vamos retornar múltiplos objetos com uma consulta. No exemplo definimos duas consultas SELECT para retornar o fornecedor com o código especificado e os respectivos produtos:

  private static void Exemplo4()
  {
            using (var conexaoBD = new SqlConnection(strConexao))
            {
               var consulta = @"SELECT * FROM dbo.Suppliers WHERE SupplierID = @Id
                                         SELECT * FROM dbo.Products WHERE SupplierID = @Id";
                
                using (var resultado = conexaoBD .QueryMultiple(consulta, new { Id = 1 }))
                {
                    var fornecedor = resultado.Read().Single();
                    var produtos = resultado.Read().ToList();
                    Console.WriteLine("Fornecedor  - {0} ", fornecedor.CompanyName);
                    Console.WriteLine(string.Format("Total de Produtos {0}", produtos.Count));
                    foreach (dynamic produto in produtos)
                    {
                        Console.WriteLine("{0} - {1} - {2}", produto.ProductID, produto.ProductName, produto.UnitPrice);
                    }
                }
            }
   }

Utilizamos o recurso QueryMultiple que suporta tratar com múltiplos conjuntos de resultados.

conexaoBD .QueryMultiple(consulta, new { Id = 1 }))

No exemplo definimos a consulta e passamos o valor para o parâmetro Id igual a 1.

5- Incluindo informações no banco de dados

Para incluir informações basta definir a consulta SQL Insert usando os valores e usar o método Execute():

  private static void Exemplo5()
        {
            using (var conexaoBD = new SqlConnection(strConexao))
            {
                var fornecedor = new Fornecedor()
                {
                    Address = "Rua Projetada 100",
                    CompanyName = "JcmSoft Inc."
                };
                conexaoBD.Execute(@"insert Suppliers(CompanyName, Address)
                                    values (@CompanyName, @Address)", fornecedor);
                Console.WriteLine("Informações do fornecedor incluídas com sucesso.");
            }
     }

6- Atualizando informações no banco de dados

A atualização de dados possui uma sintaxe parecida com a da inclusão. Aqui usamos uma instrução SQL Update com um objeto anônimo como parâmetro.

  private static void Exemplo6()
   {
            using (var conexaoBD = new SqlConnection(strConexao))
            {
                var atualizarBD = @"Update Products Set UnitPrice = @UnitPrice
                                               Where Id = @ProductId";
                conexaoBD.Execute(atualizarBD, new
                {
                    UnitPrice = 99.9m,
                    ProductId = 50
                });
             Console.WriteLine("Informações do fornecedor incluídas com sucesso.");
        }
   }

Neste artigo mostrei alguns dos recursos do Dapper .net usando os cenários mais comuns mas existem outros recursos que pretendo abordar nos próximos artigos.

Pegue o projeto completo aqui :  Usando_Dapper.zip

Todavia digo-vos a verdade, que vos convém que eu vá; porque, se eu não for, o Consolador não virá a vós; mas, quando eu for, vo-lo enviarei.
E, quando ele vier, convencerá o mundo do pecado, e da justiça e do juízo.
Do pecado, porque não crêem em mim;
Da justiça, porque vou para meu Pai, e não me vereis mais;
E do juízo, porque já o príncipe deste mundo está julgado.
João 16:7-11

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