Dapper é um micro-orm grátis e open source muito utilizado. Ele é super simples e muito utilizado… da forma errada. Um dos grandes problemas ao utilizar um ORM é tentar reinventar a roda e concatenar valores na variável que contém as queries.
Este tipo de coisa é um grande ponto de entrada para SQL Injections. Você pode fazer um helper para tentar contornar esta ameaça, mas para que reinventar a roda? Neste post, mostro como usar o Dapper de forma segura.
Dois pontos importantes para este post:
- Todos os exemplos utilizam o banco de dados AdventureWorks. Se quiser acompanhar, veja a seção extra deste post. Nele você terá as informações necessárias para gerar um container do Docker com o SqlServer pré carregado com o AdventureWorks.
- Considere que existe uma variável chamada connectionString com os dados de conexão com o banco de dados.
Instalando Dapper
Install-Package Dapper
Usings são necessários para este exemplo
using Dapper; using System.Data; using System.Data.SqlClient; using System.Linq; using System.Collections.Generic;
Você vai precisar dos usings acima para estes exemplos.
Começando com um exemplo básico
using(var conn = new SqlConnection(connectionString)) { conn.Open(); var employees = conn.Query<Employee>($@" SELECT BusinessEntityID, NationalIDNumber, LoginID, OrganizationLevel, JobTitle, BirthDate, MaritalStatus, Gender, HireDate, SalariedFlag, VacationHours, SickLeaveHours, CurrentFlag, ModifiedDate FROM HumanResources.Employee").ToList(); //Do something with the result... }
No exemplo acima, estou fazendo uma consulta simples e sem argumentos. Só para relembrar o básico.
Fazendo uma consulta utilizando argumentos
using (var conn = new SqlConnection(connectionString)) { conn.Open(); var salariedFlag = 1; var currentFlag = 1; List<Employee> employees = conn.Query<Employee>($@" SELECT BusinessEntityID, NationalIDNumber, LoginID, OrganizationLevel, JobTitle, BirthDate, MaritalStatus, Gender, HireDate, SalariedFlag, VacationHours, SickLeaveHours, CurrentFlag, ModifiedDate FROM HumanResources.Employee WHERE SalariedFlag = {salariedFlag} AND CurrentFlag = {currentFlag}").ToList(); //Do something with the result... }
Este exemplo se parece muito com o anterior, mas inclui duas variaveis na query…. Desta forma, a variável que possui o comando SQL ja está com todos os valores necessarios.
Então…. sim! Este é o jeito errado de utilizar o Dapper! É exatamente isso que não deve ser feito.
Fazendo uma consulta utilizando argumentos… da maneira correta.
using (var conn = new SqlConnection(connectionString)) { conn.Open(); var salariedFlag = 1; var currentFlag = 1; List<Employee> employees = conn.Query<Employee>($@" SELECT BusinessEntityID, NationalIDNumber, LoginID, OrganizationLevel, JobTitle, BirthDate, MaritalStatus, Gender, HireDate, SalariedFlag, VacationHours, SickLeaveHours, CurrentFlag, ModifiedDate FROM HumanResources.Employee WHERE SalariedFlag = @salariedFlagArg AND CurrentFlag = @currentFlagArg", new { salariedFlagArg = salariedFlag, currentFlagArg = currentFlag }).ToList(); //Do something with the results.... }
Ok, a query acima é a mesma do exemplo errado e os valores são os mesmos, mas a forma de utilizar está diferente.
- Adicionei variáveis na query. Elas são exatamente isso: variaveis, então é seguro utilizá-las. No caso, como estou utilizando Sql Server, coloquei a @ como prefixo. Todavia, isso varia de acordo com o banco de dados. O Oracle, por exemplo, exige que você utilize : (dois pontos).
- Na sequencia, adicionei outro argumento na chamada da função. Ele é um objeto dinâmico, onde cada propriedade tem o nome de uma variável que eu coloquei na query (sem a @) e cada uma destas propriedades recebe seu respectivo valor.
É isso. Facil, não?
Não precisa se preocupar em converter tipos de variáveis, preparar DateTimes ou strings… O Dapper vai fazer isso tudo para você.
Utilizando parametros dinamicos para fazer uma consulta utilizando argumentos… (também da maneira correta)
using (var conn = new SqlConnection(connectionString)) { conn.Open(); var queryArgs = new DynamicParameters(); queryArgs.Add("salariedFlagArg", 1); queryArgs.Add("currentFlag", 1); List <Employee> employees = conn.Query<Employee>($@" SELECT BusinessEntityID, NationalIDNumber, LoginID, OrganizationLevel, JobTitle, BirthDate, MaritalStatus, Gender, HireDate, SalariedFlag, VacationHours, SickLeaveHours, CurrentFlag, ModifiedDate FROM HumanResources.Employee WHERE SalariedFlag = @salariedFlagArg AND CurrentFlag = @currentFlagArg", queryArgs).ToList(); //Do something with the result. }
Neste exemplo, a query funciona da mesma forma. A diferença está na forma de montar os parâmetros. Ao invés de criar um objeto dinâmico com as variáveis e seus valores, utilizo um objeto do tipo DynamicParameters.
Com estes objetos, a lógica é a mesma. A função Add recebe dois argumentos: O primeiro é o nome da variaveis que você utilizou na query e o segundo é o valor dela.
É um processo bem simples, mas já é o suficiente para deixar sua aplicação mais eficaz e segura.
No proximo post sobre o assunto, vou mostrar como utilizar o Dapper para selecionar objetos compostos.
Espero ter ajudado!
Latest posts by Breno RdV (see all)
- O que é Metaclass e como ela funciona. (#python #dev #metaclass) - janeiro 11, 2023
- Entenda a mágica dos Generators. (#python, #dev, #generator, #iterator) - dezembro 28, 2022
- Ordenando um DataFrame por múltiplas colunas. (#python #pandas #jupyter #dev #data) - agosto 3, 2022