ASP .NET Core - Criando uma Web API com Dapper - I
Hoje vamos criar uma Web API ASP .NET Core usando o Dapper. |
O Dapper é um mapeador de objetos simples para a plataforma .NET de alto desempenho, sendo considerado um micro-ORM.
Ele estende a interface IDbConnection, fornecendo métodos de extensão úteis para consultar seu banco de dados, e, foi criado pela equipe do Stackoverflow.
Destaques dos recursos do Dapper:
Podemos dizer que o foco principal do Dapper é o desempenho.
O
Dapper a rigor não pode ser considerado um ORM se
formos levar em conta alguns recursos que praticamente todos os ORMs full
do mercado possuem.
Assim o Dapper :
Dessa forma podemos considerar o Dapper um micro ORM.
Como o Dapper funciona ?
O Dapper funciona com o objeto ADO.NET IDbConnection,
o que significa que funcionará com qualquer sistema de banco de dados para o
qual exista um provedor ADO.NET.
Para usar o Dapper basicamente fazemos o seguinte:
Nesta perspectiva, as funcionalidades do Dapper podem ser resumidas a : Consultar , Parametrizar a consulta e Mapear o resultado obtido.
Quando você deve considerar usar o Dapper ?
A seguir alguns fatores que você deve considerar para usar o Dapper:
- Considere o principal motivo do Dapper existir :
desempenho
- Cenários onde os dados read-only mudam e são solicitados com frequência
- Cenários onde não existe estado (aplicações web)
- Considere que você vai ter que escrever consultas SQL
- Cenários onde a estrutura do banco de dados não é normalizada
- Considere que você pode usar o EF Core e também o Dapper no mesmo projeto
Como instalar o Dapper ?
O Dapper é distribuído via pacotes Nuget e pode ser obtido neste endereço :
https://www.nuget.org/packages/Dapper/
O código fonte do Dapper pode ser consultado aqui : https://github.com/DapperLib/Dapper
Para instalar o
Dapper em seu aplicativo .NET você pode usar a janela do Package Manager Console
e digitar o comando: install-package Dapper -Version
2.0.90
Usando a ferramenta de linha de comando NET CLI o comando usado é o seguinte:
dotnet add package Dapper --version 2.0.90
Principais métodos de extensão do Dapper
O Dapper oferece
sete métodos de extensão para do objeto IDbConnection,
além de seus respectivos métodos assíncronos e dinâmicos e todos os métodos
podem ser chamados a partir deste objeto.
1-Execute - Pode executar um comando uma ou várias
vezes e retornar o número de linhas afetadas. Usado para executar: Stored
procedures e instruções INSERT, UPDATE e DELETE
2- Query - Executa uma consulta e mapeia o
resultado para um objeto. O resultado pode ser mapeado para : tipo fortemente
tipado, objeto anônimo, multi-mapeamento(um-para-um) e (um-para-muitos),
multi-tipo.
3- QueryFirst - Executa uma consulta e mapeia a
primeira linha do resultado. Se a consulta não tiver resultado, uma exceção
InvalidOperationException é disparada.
4- QueryFirstOrDefault - Executa uma consulta e
mapeia a primeira linha do resultado. Se a consulta não tiver resultado pode
retornar um valor padrão ou retornar null.
5- QuerySingle - Executa uma consulta e retorna uma
única linha caso contrário, se não houver resultado, dispara uma exceção
InvalidOperationException
6- QuerySingleOrDefault - Executa uma consulta e
mapeia o primeiro resultado ou um valor padrão se a sequência estiver vazia;
este método lança uma exceção se houver mais de um elemento na sequência.
7- QueryMultiple - Pode manipular
múltiplos results sets, permitindo escrever consultas que retornem mais
de um select.
O Dapper permite parametrizar as consultas de 3 formas principais:
1- Anonymous - Usar objetos/tipos anônimos. É a forma mais usada e simples de parametrização:
IEnumerable<Product> produto;
using (var connection = new SqlConnection(configuration.GetConnectionString("DefaultConnection")))
{
produto = connection.Query<Product>(@"SELECT * FROM Products WHERE ProductID = @ID", new { id = 2 });
}
|
2- Dynamic - Usar o mapeamento dinâmico. Cria e usa um parâmetro em um método Dapper. Ideal para executar Stored Procedures parametrizadas:
var sql = “VendasPorCategoria";
using (var connection = new SqlConnection(configuration.GetConnectionString("DefaultConnection")))
{
var parameter = new DynamicParameters();
parameter.Add("@CategoryName", categoryName, DbType.String, ParameterDirection.Input);
parameter.Add("@OrdYear", orderYear.ToString(), DbType.String, ParameterDirection.Input);
parameter.Add("@RowCount", dbType: DbType.Int32, direction: ParameterDirection.ReturnValue);
connection.Execute(sql, parameter, commandType: CommandType.StoredProcedure);
var totalRows = parameter.Get<int>("@RowCount");
}
|
3-List - Permite que você especifique vários parâmetros em uma cláusula IN usando uma lista.
IEnumerable<Product> produto; using (var connection = new SqlConnection(configuration.GetConnectionString("DefaultConnection"))) { produto = connection.Query<Product>(@"SELECT * FROM Products WHERE ProductID IN @ID", new { id = new[] { 2, 3, 8, 20 } }); } |
Criando uma API com Dapper : Definindo o banco de dados e a tabela
Para mostrar um exemplo prático usando o Dapper vamos criar uma Web API ASP .NET Core no ambiente do .NET 5.0 onde vamos definir o padrão repositório usando a biblioteca Dapper.
A Web API vai expor endpoints que permitem consultar e realizar as operações para incluir, alterar e excluir informações de Tarefas. Para isso vamos usar um banco de dados SQL Server chamado Teste.mdf onde temos a tabela Tarefas com a seguinte estrutura :
A tabela
Tarefas já possui os seguintes dados para teste:
Criando o projeto Web API no VS 2019
Abra o VS 2019 e clique em New Project e selecione o template ASP .NET Core Web API e clique em Next;
Informe o nome DapperAPI e clique em Next;
A seguir selecione o Target Framework, Authentication Type e demais configurações conforme mostrada na figura:
Clique em Create.
Vamos incluir no projeto o pacote do Dapper via menu Tools usando a opção Manage Nuget Packages for Solution;
Selecione a guia Browse e informe o nome do pacote : Dapper
Agora vamos criar as pastas Data e Repositories no projeto.
Na pasta Data vamos criar a classe Tarefa que representa o nosso modelo de domínio:
public class Tarefa { public int Id { get; set; } public string Descricao { get; set; } public bool IsCompleta { get; set; } } |
Vamos criar nesta pasta a classe TarefaContainer que iremos usar para obter informações usando o método QueryMultiple que vai retornar o total de tarefas e a lista de tarefas:
public class TarefaContainer { public int Contador { get; set; } public List<Tarefa> Tarefas { get; set; } } |
A seguir vamos criar a classe DbSession que vai gerenciar as conexões com o banco de dados:
using Microsoft.Extensions.Configuration;
using System;
using System.Data;
using System.Data.SqlClient;
namespace API.Data
{
public class DbSession : IDisposable
{
public IDbConnection Connection { get; }
public DbSession(IConfiguration configuration)
{
Connection = new SqlConnection(configuration
.GetConnectionString("DefaultConnection"));
Connection.Open();
}
public void Dispose() => Connection?.Dispose();
}
}
|
A classe
DbSession usa a interface IDbConnection responsável por gerenciar a
conexão. Ela implementa a interface IDisposable e
vai criar e abrir uma conexão e a seguir vai liberar o objeto
Connection.
No construtor da classe sempre iniciamos uma conexão e para isso obtemos a
string de conexão do arquivo appsettings,json injetando uma instancia de
IConfiguration.
O método Dispose da interface
IDisposable será executado no término da instância desta classe, e, com
isso podemos usar esta classe com a instrução using
iniciando o contexto e ao final fechamos a conexão.
Nota: Se você precisar reabrir a conexão novamente pode usar o
método Close ao invés de Dispose().
Vamos concluir este artigo incluindo no arquivo appsettings.json a string de conexão com o banco de dados:
{ "ConnectionStrings": { "DefaultConnection": "Data Source=SUA_STRING_DE_CONEXAO" }, "Logging": { "LogLevel": { "Default": "Information", "Microsoft": "Warning", "Microsoft.Hosting.Lifetime": "Information" } }, "AllowedHosts": "*" } |
Na próxima parte do artigo vamos implementar o padrão Repository e criar o controlador TarefasController.
"Porque, se
alguém cuida ser alguma coisa, não sendo nada, engana-se a si mesmo. Mas prove
cada um a sua própria obra, e terá glória só em si mesmo, e não noutro."
Gálatas 6:3,4
Referências:
C# - Tasks x Threads. Qual a diferença
VB .NET - Datas, horas: conceitos e operações
C# - Programação Assíncrona como : Asycn e Task
O tratamento de datas no VB.NET
C# - Obtendo a data e a hora por TimeZone
C# - O Struct Guid
C# - Checando Null de uma forma mais elegante
DateTime
Null o que é isso ?
Formatação de data e hora para uma cultura ...
C# - Calculando a diferença entre duas datas
NET - Padrão de Projeto - Null Object Pattern
C# - Fundamentos : Definindo DateTime como Null
C# - Os tipos Nullable (Tipos Anuláveis)