.NET

25 ago, 2017

Dapper: exemplos de utilização em ASP.NET Core e .NET Full

Publicidade

Dapper: exemplos de utilização em ASP.NET Core e .NET Full

Frameworks ORM surgiram com o objetivo de simplificar a conversão de informações estruturadas em objetos, contribuindo para uma maior produtividade na construção de aplicações que dependam de bancos de dados relacionais. As principais plataformas de desenvolvimento da atualidade contam com soluções deste tipo, existindo inclusive um grande engajamento de comunidades técnicas na implementação de projetos ORM.

No caso da plataforma .NET temos atualmente o Entity Framework e o NHibernate como frameworks ORM mais populares. Embora úteis num grande número de situações, estas alternativas podem apresentar limitações em cenários mais específicos. Consultas envolvendo tabelas com grandes volumes de informações constituem um bom exemplo disto: as instruções geradas por meio de uma solução ORM nem sempre serão executadas da forma mais performática possível.

E como então superar este tipo de problema envolvendo consultas?

Um caminho seria empregar recursos básicos do ADO.NET, além de utilizar instruções SQL escritas de forma a se beneficiar de índices que otimizem o seu processamento. Esta alternativa pode, entretanto, não ser tão produtiva em termos de codificação.

É neste ponto que o micro-ORM Dapper entra em ação. Embora não possua todas as funcionalidades típicas de um ORM convencional, este framework disponibiliza Extension Methods que simplificam em muito o trabalho com os objetos de conexão do ADO.NET (neste último caso implementações da interface IDbConnection).

Esta característica (integração com o ADO.NET) permite que o Dapper seja utilizado para acessar qualquer tecnologia relacional compatível com o .NET. O SQL Server, o Oracle, o PostgreSQL e o MySQL são alguns exemplos de SGDBs possíveis.

Tabelas, views e stored procedures estão entre as estruturas suportadas pelo Dapper. Transações criadas a partir de um objeto de conexão também podem ser usadas em operações envolvendo inserções, atualizações e exclusões de registros.

A seguir é possível observar um exemplo de utilização do Dapper em ASP.NET Core:

 

  • Os Query e QueryFirstOrDefault são extensões que este framework disponibiliza para uso apartir da classe SqlConnection (empregada na conexão com uma base do SQL Server);
  • Este trecho de código aborda ainda a utilização de queries e de uma procedure para a consulta de dados com o Dapper;
  • Recomenda-se também a passagem de parâmetros por meio de um objeto anônimo (devendo coincidir o nome de cada propriedade com a identificação do respectivo parâmetro). Esta prática tem por finalidade evitar falhas que levem a ataques do tipo SQL Injection, algo bastante possível em instruções geradas via concatenação de strings.
using System.Collections.Generic;
using System.Data;
using System.Data.SqlClient;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Dapper;
namespace ExemploASPNETCore.Controllers
{
 [Route("api/[controller]")]
 public class EstadosController : Controller
 {
 private IConfiguration _config;
public EstadosController(IConfiguration configuration)
 {
 _config = configuration;
 }
[HttpGet("todos")]
 public IEnumerable<Estado> GetEstados()
 {
 using (SqlConnection conexao = new SqlConnection(
 _config.GetConnectionString("ExemplosDapper")))
 {
 return conexao.Query<Estado>(
 "SELECT E.SiglaEstado, E.NomeEstado, E.NomeCapital, " +
 "R.NomeRegiao " +
 "FROM dbo.Estados E " +
 "INNER JOIN dbo.Regioes R ON R.IdRegiao = E.IdRegiao " +
 "ORDER BY E.NomeEstado");
 }
 }
[HttpGet("detalhes/{siglaEstado}")]
 public Estado GetDetalhesEstado(string siglaEstado)
 {
 using (SqlConnection conexao = new SqlConnection(
 _config.GetConnectionString("ExemplosDapper")))
 {
 return conexao.QueryFirstOrDefault<Estado>(
 "SELECT E.SiglaEstado, E.NomeEstado, E.NomeCapital, " +
 "R.NomeRegiao " +
 "FROM dbo.Estados E " +
 "INNER JOIN dbo.Regioes R ON R.IdRegiao = E.IdRegiao " +
 "WHERE E.SiglaEstado = @CodEstado",
 new { CodEstado = siglaEstado });
 }
 }
[HttpGet("detalhes2/{siglaEstado}")]
 public Estado GetDetalhesEstado2(string siglaEstado)
 {
 using (SqlConnection conexao = new SqlConnection(
 _config.GetConnectionString("ExemplosDapper")))
 {
 return conexao.QueryFirstOrDefault<Estado>(
 "dbo.PRC_SEL_DETALHES_ESTADO",
 new { CodEstado = siglaEstado },
 commandType: CommandType.StoredProcedure);
 }
 }
 }
}

Já abordei o uso do Dapper em um artigo anterior, utilizando o mesmo juntamente com o ASP.NET Core e o SQL Server:

ASP.NET Core: criando uma API REST com Dapper e SQL Server

E também em um Live Demo do Canal .NET, no qual demonstrei a implementação de uma API REST em Linux com o ASP.NET Core e o Visual Studio Code:

O Dapper também foi assunto de uma apresentação que realizei recentemente:

Para esta palestra implementei diversos exemplos em .NET Full e ASP.NET Core, disponibilizando os mesmos no GitHub:

https://github.com/renatogroffe/Exemplos_Dapper

Neste repositório há aplicações que fazem uso dos seguintes packages:

  • Dapper: biblioteca principal para uso deste micro-ORM;
  • Dapper.Contrib: extensões adicionais do Dapper que simplificam operações de CRUD, de maneira a dispensar a inclusão de expressões SQL (SELECT, INSERT, UPDATE e DELETE) em código C#.

 

Estes projetos demonstram a utilização de tabelas, views e procedures com o Dapper, além da implementação de controle transacional e como converter o resultado de uma consulta ao se empregarem objetos compostos (formados por entidades que correspondem a mais de uma tabela).

As próximas listagens trazem um exemplo similar ao trecho de código anterior, já empregando o Dapper.Contrib. Primeiramente será definida uma classe representando uma entidade (Estado), mapeando-se na mesma o nome da tabela e sua chave primária (através dos atributos Table e ExplicityKey, ambos pertencentes ao namespace Dapper.Contrib.Extensions):

using Dapper.Contrib.Extensions;
namespace ExemploASPNETCoreDapperContrib
{
 [Table("dbo.Estados")]
 public class Estado
 {
 [ExplicitKey]
 public string SiglaEstado { get; set; }
 public string NomeEstado { get; set; }
 public string NomeCapital { get; set; }
 public int IdRegiao { get; set; }
 }
}

Já no Controller os Extension Methods GetAll e Get dispensam o uso de queries para a obtenção dos dados:

using System.Collections.Generic;
using System.Data.SqlClient;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Configuration;
using Dapper.Contrib.Extensions;
namespace ExemploASPNETCoreDapperContrib.Controllers
{
 [Route("api/[controller]")]
 public class EstadosController : Controller
 {
 private IConfiguration _config;
public EstadosController(IConfiguration configuration)
 {
 _config = configuration;
 }
[HttpGet("todos")]
 public IEnumerable<Estado> GetEstados()
 {
 using (SqlConnection conexao = new SqlConnection(
 _config.GetConnectionString("ExemplosDapper")))
 {
 return conexao.GetAll<Estado>();
 }
 }
[HttpGet("detalhes/{siglaEstado}")]
 public Estado GetDetalhesEstado(string siglaEstado)
 {
 using (SqlConnection conexao = new SqlConnection(
 _config.GetConnectionString("ExemplosDapper")))
 {
 return conexao.Get<Estado>(siglaEstado);
 }
 }
 }
}