DEV Community

Cover image for DataAccess: Dapper
Bruno Freschi for He4rt Developers

Posted on

DataAccess: Dapper

O Dapper é um micro ORM (Object-Relational Mapper) para .NET que estende o ADO.NET. Ele foi projetado para oferecer:

  • Alta performance (próximo ao ADO.NET puro)
  • Baixo overhead
  • Controle total sobre SQL
  • Mapeamento simples entre objetos e queries

Diferente de ORMs completos como Entity Framework, o Dapper não abstrai o SQL, ele trabalha junto com ele.

Quando usar Dapper

Use Dapper quando:

  • Performance é crítica (ex: ETL, processamento em lote)
  • Queries são complexas ou altamente otimizadas
  • Você quer controle total do SQL
  • Baixo overhead é necessário

Evite quando:

  • Precisa de tracking automático de entidades
  • Quer abstração completa do banco
  • CRUD simples sem preocupação com performance

Instalação

Via CLI:

dotnet add package Dapper
Enter fullscreen mode Exit fullscreen mode

Ou via NuGet Package Manager:

Install-Package Dapper
Enter fullscreen mode Exit fullscreen mode

Conceitos Fundamentais

3.1 Extensão do IDbConnection

O Dapper funciona como extensão de IDbConnection:

using (var connection = new SqlConnection(connectionString))
{
    var result = connection.Query("SELECT * FROM Clientes");
}
Enter fullscreen mode Exit fullscreen mode

3.2 Query (SELECT)

Retorna dados mapeados automaticamente:

var clientes = connection.Query<Cliente>(
    "SELECT Id, Nome, Email FROM Clientes"
);
Enter fullscreen mode Exit fullscreen mode

Mapeia por convenção:

  • Nome da coluna = Nome da propriedade

3.3 QueryFirst / QuerySingle

Diferença importante:

// Retorna o primeiro ou default
var cliente = connection.QueryFirstOrDefault<Cliente>(
    "SELECT * FROM Clientes WHERE Id = @Id",
    new { Id = 1 }
);

// Espera exatamente 1 resultado
var cliente = connection.QuerySingle<Cliente>(
    "SELECT * FROM Clientes WHERE Id = @Id",
    new { Id = 1 }
);
Enter fullscreen mode Exit fullscreen mode

Use QuerySingle quando:

  • Você garante que existe exatamente 1 registro

3.4 Execute (INSERT, UPDATE, DELETE)

var rows = connection.Execute(
    "INSERT INTO Clientes (Nome, Email) VALUES (@Nome, @Email)",
    new { Nome = "Gabrielly", Email = "email@email.com" }
);
Enter fullscreen mode Exit fullscreen mode

Retorna:

  • Número de linhas afetadas

Parâmetros e Segurança

4.1 Evitando SQL Injection

Sempre use parâmetros:

var cliente = connection.Query<Cliente>(
    "SELECT * FROM Clientes WHERE Email = @Email",
    new { Email = email }
);
Enter fullscreen mode Exit fullscreen mode

Nunca faça isso:

// ERRADO
$"SELECT * FROM Clientes WHERE Email = '{email}'"
Enter fullscreen mode Exit fullscreen mode

4.2 Parâmetros Dinâmicos

var parameters = new DynamicParameters();
parameters.Add("Id", 1);

var cliente = connection.Query<Cliente>(
    "SELECT * FROM Clientes WHERE Id = @Id",
    parameters
);
Enter fullscreen mode Exit fullscreen mode

Mapeamento Avançado

5.1 Multi-mapping (JOIN)

var sql = @"
SELECT c.*, p.*
FROM Clientes c
INNER JOIN Pedidos p ON c.Id = p.ClienteId
";

var result = connection.Query<Cliente, Pedido, Cliente>(
    sql,
    (cliente, pedido) =>
    {
        cliente.Pedidos.Add(pedido);
        return cliente;
    }
);
Enter fullscreen mode Exit fullscreen mode

5.2 Query Multiple

Executa múltiplas queries em uma chamada:

using var multi = connection.QueryMultiple(@"
    SELECT * FROM Clientes;
    SELECT * FROM Pedidos;
");

var clientes = multi.Read<Cliente>();
var pedidos = multi.Read<Pedido>();
Enter fullscreen mode Exit fullscreen mode

Transações

using var connection = new SqlConnection(connectionString);
connection.Open();

using var transaction = connection.BeginTransaction();

try
{
    connection.Execute(sql1, param1, transaction);
    connection.Execute(sql2, param2, transaction);

    transaction.Commit();
}
catch
{
    transaction.Rollback();
    throw;
}
Enter fullscreen mode Exit fullscreen mode

Essencial para:

  • ETL
  • Processamento em lote
  • Consistência de dados

Performance

7.1 Por que o Dapper é rápido?

  • Usa IL emit (geração dinâmica de código)
  • Não faz tracking de entidades
  • Não possui abstrações pesadas
  • Trabalha direto sobre ADO.NET

7.2 Boas práticas de performance

  • Reutilize conexões (connection pooling já ajuda)
  • Use QueryBuffered: false para grandes volumes:
var data = connection.Query<Cliente>(
    sql,
    buffered: false
);
Enter fullscreen mode Exit fullscreen mode
  • Evite SELECT *
  • Use índices no banco
  • Prefira queries específicas

Uso em ETL (seu cenário)

Dapper é excelente para ETL por:

  • Baixo overhead
  • Controle total do fluxo
  • Alta velocidade em leitura/escrita

Exemplo simplificado ETL:

var dados = connectionOrigem.Query<Cliente>("SELECT * FROM Clientes");

foreach (var cliente in dados)
{
    connectionDestino.Execute(
        "INSERT INTO Clientes (Id, Nome) VALUES (@Id, @Nome)",
        cliente
    );
}
Enter fullscreen mode Exit fullscreen mode

Otimização recomendada:

  • Processamento em lote
  • Uso de transações
  • Bulk insert quando possível

Comparação Técnica

Característica Dapper ADO.NET Entity Framework
Performance Alta Muito Alta Média
Controle SQL Total Total Parcial
Facilidade Média Baixa Alta
Tracking Não Não Sim
Overhead Baixo Muito baixo Alto

Boas Práticas

  • Sempre use parâmetros
  • Evite lógica no banco desnecessária
  • Separe queries por responsabilidade
  • Use DTOs específicos
  • Não misture Dapper com lógica de domínio diretamente
  • Centralize acesso a dados (Repository ou similar)

Armadilhas Comuns

  • Esquecer de abrir conexão
  • Não tratar múltiplos resultados corretamente
  • Uso incorreto de QuerySingle
  • Falta de transação em operações críticas
  • Carregar grandes volumes em memória sem controle

Top comments (0)