Ubicado en https://github.com/dapperlib/dapper/releases
Myget antes de la realización: https://www.myget.org/gallery/dapper
Paquete | Establo nuget | NUGET PREPRENDE | Descargas | Myget |
---|---|---|---|---|
Apuesto | ||||
Dapper.EntityFramework | ||||
Dapper.entityframework.strongname | ||||
Dapper.Rainbow | ||||
Dapper.sqlbuilder | ||||
Dapper.strongname |
Propósitos de paquete:
Dapper se desarrolló originalmente para y por el desbordamiento de la pila, pero es F/OSS. El patrocinio es bienvenido e invitado: vea el enlace del patrocinador en la parte superior de la página. Muchas gracias a todos (individuos u organizaciones) que han patrocinado a Dapper, pero un gran agradecimiento en particular a:
Dapper es una biblioteca Nuget que puede agregar a su proyecto que mejorará sus conexiones ADO.NET a través de métodos de extensión en su instancia DbConnection
. Esto proporciona una API simple y eficiente para invocar SQL, con soporte para el acceso a datos sincrónicos y asincrónicos, y permite consultas buffered y no tamponadas.
Proporciona múltiples ayudantes, pero las API clave son:
// insert/update/delete etc
var count = connection . Execute ( sql [ , args ] ) ;
// multi-row query
IEnumerable < T > rows = connection . Query < T > ( sql [ , args ] ) ;
// single-row query ({Single|First}[OrDefault])
T row = connection . QuerySingle < T > ( sql [ , args ] ) ;
donde args
pueden estar (entre otras cosas):
Dictionary<string,object>
DynamicParameters
public class Dog
{
public int ? Age { get ; set ; }
public Guid Id { get ; set ; }
public string Name { get ; set ; }
public float ? Weight { get ; set ; }
public int IgnoredProperty { get { return 1 ; } }
}
var guid = Guid . NewGuid ( ) ;
var dog = connection . Query < Dog > ( " select Age = @Age, Id = @Id " , new { Age = ( int ? ) null , Id = guid } ) ;
Assert . Equal ( 1 , dog . Count ( ) ) ;
Assert . Null ( dog . First ( ) . Age ) ;
Assert . Equal ( guid , dog . First ( ) . Id ) ;
Este método ejecutará SQL y devolverá una lista dinámica.
Ejemplo de uso:
var rows = connection . Query ( " select 1 A, 2 B union all select 3, 4 " ) . AsList ( ) ;
Assert . Equal ( 1 , ( int ) rows [ 0 ] . A ) ;
Assert . Equal ( 2 , ( int ) rows [ 0 ] . B ) ;
Assert . Equal ( 3 , ( int ) rows [ 1 ] . A ) ;
Assert . Equal ( 4 , ( int ) rows [ 1 ] . B ) ;
Ejemplo de uso:
var count = connection . Execute ( @"
set nocount on
create table #t(i int)
set nocount off
insert #t
select @a a union all select @b
set nocount on
drop table #t" , new { a = 1 , b = 2 } ) ;
Assert . Equal ( 2 , count ) ;
La misma firma también le permite ejecutar de manera conveniente y eficiente un comando varias veces (por ejemplo, a los datos de carga masiva)
Ejemplo de uso:
var count = connection . Execute ( @"insert MyTable(colA, colB) values (@a, @b)" ,
new [ ] { new { a = 1 , b = 1 } , new { a = 2 , b = 2 } , new { a = 3 , b = 3 } }
) ;
Assert . Equal ( 3 , count ) ; // 3 rows inserted: "1,1", "2,2" and "3,3"
Otro uso de ejemplo cuando ya tiene una colección existente:
var foos = new List < Foo >
{
{ new Foo { A = 1 , B = 1 } }
{ new Foo { A = 2 , B = 2 } }
{ new Foo { A = 3 , B = 3 } }
} ;
var count = connection . Execute ( @"insert MyTable(colA, colB) values (@a, @b)" , foos ) ;
Assert . Equal ( foos . Count , count ) ;
Esto funciona para cualquier parámetro que implementa IEnumerable<T>
para algunos T.
Una característica clave de Dapper es el rendimiento. Las siguientes métricas muestran cuánto tiempo lleva ejecutar una declaración SELECT
contra un DB (en varias configuraciones, cada una etiquetada) y asignar los datos devueltos a los objetos.
Los puntos de referencia se pueden encontrar en dapper.tests.performance (¡Contribuciones bienvenidas!) Y se pueden ejecutar a través de:
dotnet run --project . b enchmarks D apper.Tests.Performance -c Release -f net8.0 -- -f * --join
La salida de la última ejecución es:
BenchmarkDotNet v0.13.7, Windows 10 (10.0.19045.3693/22H2/2022Update)
Intel Core i7-3630QM CPU 2.40GHz (Ivy Bridge), 1 CPU, 8 logical and 4 physical cores
.NET SDK 8.0.100
[Host] : .NET 8.0.0 (8.0.23.53103), X64 RyuJIT AVX
ShortRun : .NET 8.0.0 (8.0.23.53103), X64 RyuJIT AVX
Acomodar | Método | Devolver | Significar | Stddev | Error | Gen0 | Gen1 | Gen2 | Asignado |
---|---|---|---|---|---|---|---|---|---|
Impacto de caché de dapper | EXECTEPARAMETERS_CACHE | Vacío | 96.75 EE. UU. | 0.668 EE. UU. | 1.010 EE. UU. | 0.6250 | - | - | 2184 b |
Impacto de caché de dapper | QueryFirstParameters_Cache | Vacío | 96.86 EE. UU. | 0.493 EE. UU. | 0.746 EE. UU. | 0.8750 | - | - | 2824 b |
Codificado por la mano | Sqlcommand | Correo | 119.70 EE. UU. | 0.706 EE. UU. | 1.067 EE. UU. | 1.3750 | 1.0000 | 0.1250 | 7584 b |
Codificado por la mano | De datos | dinámica | 126.64 EE. UU. | 1.239 EE. UU. | 1.873 EE. UU. | 3.0000 | - | - | 9576 b |
Sqlmarshal | Sqlcommand | Correo | 132.36 EE. UU. | 1.008 EE. UU. | 1.523 EE. UU. | 2.0000 | 1.0000 | 0.2500 | 11529 b |
Apuesto | Consulta | Correo | 133.73 EE. UU. | 1.301 EE. UU. | 2.186 EE. UU. | 1.7500 | 1.5000 | - | 11608 b |
Poderoso | Consulta | dinámica | 133.92 EE. UU. | 1.075 EE. UU. | 1.806 EE. UU. | 2.0000 | 1.7500 | - | 12710 b |
Linq a DB | Consulta | Correo | 134.24 EE. UU. | 1.068 EE. UU. | 1.614 EE. UU. | 1.7500 | 1.2500 | - | 10904 b |
RepodB | Ejecutar | Correo | 135.83 EE. UU. | 1.839 EE. UU. | 3.091 EE. UU. | 1.7500 | 1.5000 | - | 11649 B |
Apuesto | 'Consulta (amortiguada)' | Correo | 136.14 EE. UU. | 1.755 EE. UU. | 2.653 EE. UU. | 2.0000 | 1.5000 | - | 11888 b |
Poderoso | Consulta | Correo | 137.96 EE. UU. | 1.485 EE. UU. | 2.244 EE. UU. | 2.2500 | 1.2500 | - | 12201 b |
Apuesto | Consulta | dinámica | 139.04 EE. UU. | 1.507 EE. UU. | 2.279 EE. UU. | 3.5000 | - | - | 11648 b |
Poderoso | De una sola | dinámica | 139.74 EE. UU. | 2.521 EE. UU. | 3.811 EE. UU. | 2.0000 | 1.7500 | - | 12710 b |
Apuesto | 'Consulta (amortiguada)' | dinámica | 140.13 EE. UU. | 1.382 EE. UU. | 2.090 EE. UU. | 2.0000 | 1.5000 | - | 11968 b |
Servicio de servicio | Soltero | Correo | 140.76 EE. UU. | 1.147 EE. UU. | 2.192 EE. UU. | 2.5000 | 1.2500 | 0.2500 | 15248 b |
Apuesto | 'Contrib Get' | Correo | 141.09 EE. UU. | 1.394 EE. UU. | 2.108 EE. UU. | 2.0000 | 1.5000 | - | 12440 b |
Poderoso | De una sola | Correo | 141.17 EE. UU. | 1.941 nosotros | 2.935 EE. UU. | 1.7500 | 1.5000 | - | 12201 b |
Masivo | 'Consulta (dinámica)' | dinámica | 142.01 EE. UU. | 4.957 nosotros | 7.494 EE. UU. | 2.0000 | 1.5000 | - | 12342 b |
Linq a DB | 'Primero (compilado)' | Correo | 144.59 EE. UU. | 1.295 EE. UU. | 1.958 EE. UU. | 1.7500 | 1.5000 | - | 12128 b |
RepodB | Consulta | Correo | 148.31 EE. UU. | 1.742 nosotros | 2.633 EE. UU. | 2.0000 | 1.5000 | 0.5000 | 13938 b |
Norma | 'Read <> (tuples)' | Valuetuple`8 | 148.58 EE. UU. | 2.172 EE. UU. | 3.283 EE. UU. | 2.0000 | 1.7500 | - | 12745 b |
Norma | 'Read <()> (llamado tuplas)' | Valuetuple`8 | 150.60 EE. UU. | 0.658 EE. UU. | 1.106 EE. UU. | 2.2500 | 2.0000 | 1.2500 | 14562 b |
RepodB | Consulta | Correo | 152.34 EE. UU. | 2.164 EE. UU. | 3.271 EE. UU. | 2.2500 | 1.5000 | 0.2500 | 14106 B |
RepodB | Consulta | Correo | 154.15 EE. UU. | 4.108 EE. UU. | 6.210 EE. UU. | 2.2500 | 1.7500 | 0.5000 | 13930 b |
RepodB | Consulta en el lugar | Correo | 155.90 EE. UU. | 1.953 EE. UU. | 3.282 EE. UU. | 2.5000 | 0.5000 | - | 14858 b |
Impacto de caché de dapper | EXECTENOPARAMETERS_NOCACHE | Vacío | 162.35 EE. UU. | 1.584 EE. UU. | 2.394 EE. UU. | - | - | - | 760 b |
Impacto de caché de dapper | EXECTENOPARAMETERS_CACHE | Vacío | 162.42 EE. UU. | 2.740 EE. UU. | 4.142 EE. UU. | - | - | - | 760 b |
Impacto de caché de dapper | QUERYFIRSTNOPARAMETERS_CACHE | Vacío | 164.35 EE. UU. | 1.206 EE. UU. | 1.824 EE. UU. | 0.2500 | - | - | 1520 b |
Devexpress.xpo | FindObject | Correo | 165.87 EE. UU. | 1.012 EE. UU. | 1.934 EE. UU. | 8.5000 | - | - | 28099 b |
Impacto de caché de dapper | QUERYFIRSTNOPARAMETERS_NOCACHE | Vacío | 173.87 EE. UU. | 1.178 EE. UU. | 1.781 EE. UU. | 0.5000 | - | - | 1576 b |
Linq a DB | Primero | Correo | 175.21 EE. UU. | 2.292 EE. UU. | 3.851 EE. UU. | 2.0000 | 0.5000 | - | 14041 b |
EF 6 | Sqlquery | Correo | 175.36 EE. UU. | 2.259 EE. UU. | 3.415 EE. UU. | 4.0000 | 0.7500 | - | 24209 b |
Norma | 'Read <> (clase)' | Correo | 186.37 EE. UU. | 1.305 EE. UU. | 2.496 EE. UU. | 3.0000 | 0.5000 | - | 17579 b |
Devexpress.xpo | GetObjectByKey | Correo | 186.78 EE. UU. | 3.407 EE. UU. | 5.151 EE. UU. | 4.5000 | 1.0000 | - | 30114 B |
Apuesto | 'Consulta (sin serpalado)' | dinámica | 194.62 EE. UU. | 1.335 EE. UU. | 2.019 EE. UU. | 1.7500 | 1.5000 | - | 12048 b |
Apuesto | 'Consulta (sin serpalado)' | Correo | 195.01 EE. UU. | 0.888 EE. UU. | 1.343 nosotros | 2.0000 | 1.5000 | - | 12008 B |
Devexpress.xpo | Consulta | Correo | 199.46 EE. UU. | 5.500 EE. UU. | 9.243 EE. UU. | 10.0000 | - | - | 32083 b |
Belgrado | Firstordefault | Tarea`1 | 228.70 EE. UU. | 2.181 EE. UU. | 3.665 EE. UU. | 4.5000 | 0.5000 | - | 20555 b |
EF núcleo | 'Primero (compilado)' | Correo | 265.45 EE. UU. | 17.745 EE. UU. | 26.828 EE. UU. | 2.0000 | - | - | 7521 b |
Fibra | Conseguir | Correo | 276.02 EE. UU. | 8.029 EE. UU. | 12.139 nosotros | 6.5000 | 1.0000 | - | 29885 b |
Fibra | Género | Correo | 277.74 EE. UU. | 13.032 EE. UU. | 19.703 EE. UU. | 8.0000 | 1.0000 | - | 31886 b |
Fibra | Criterios | Correo | 300.22 EE. UU. | 14.908 EE. UU. | 28.504 EE. UU. | 13.0000 | 1.0000 | - | 57562 b |
EF 6 | Primero | Correo | 310.55 EE. UU. | 27.254 EE. UU. | 45.799 EE. UU. | 13.0000 | - | - | 43309 B |
EF núcleo | Primero | Correo | 317.12 EE. UU. | 1.354 EE. UU. | 2.046 EE. UU. | 3.5000 | - | - | 11306 B |
EF núcleo | Sqlquery | Correo | 322.34 EE. UU. | 23.990 EE. UU. | 40.314 EE. UU. | 5.0000 | - | - | 18195 b |
Fibra | Sql | Correo | 325.54 EE. UU. | 3.937 EE. UU. | 7.527 EE. UU. | 22.0000 | 1.0000 | - | 80007 b |
EF 6 | 'Primero (sin seguimiento)' | Correo | 331.14 EE. UU. | 27.760 EE. UU. | 46.649 nosotros | 12.0000 | 1.0000 | - | 50237 b |
EF núcleo | 'Primero (sin seguimiento)' | Correo | 337.82 EE. UU. | 27.814 EE. UU. | 46.740 EE. UU. | 3.0000 | 1.0000 | - | 17986 b |
Fibra | Linq | Correo | 604.74 EE. UU. | 5.549 EE. UU. | 10.610 EE. UU. | 10.0000 | - | - | 46061 b |
Impacto de caché de dapper | EXECTEPARAMETERS_NOCACHE | Vacío | 623.42 EE. UU. | 3.978 EE. UU. | 6.684 EE. UU. | 3.0000 | 2.0000 | - | 10001 b |
Impacto de caché de dapper | QueryFirstParameters_Nocache | Vacío | 630.77 EE. UU. | 3.027 EE. UU. | 4.576 EE. UU. | 3.0000 | 2.0000 | - | 10640 b |
Siéntase libre de enviar parches que incluyan otros ORM: al ejecutar puntos de referencia, asegúrese de compilar en el lanzamiento y no adjuntar un depurador ( CTRL + F5 ).
Alternativamente, puede preferir la suite de prueba RawDataAccessbencher de Frans Bouma o Ormbenchmark.
Los parámetros generalmente se pasan como clases anónimas. Esto le permite nombrar sus parámetros fácilmente y le brinda la capacidad de simplemente cortar y pegar fragmentos SQL y ejecutarlos en el analizador de consultas de su plataforma DB.
new { A = 1 , B = " b " } // A will be mapped to the param @A, B to the param @B
Los parámetros también se pueden construir dinámicamente utilizando la clase DynamicParameters. Esto permite construir una declaración SQL dinámica mientras usa parámetros para la seguridad y el rendimiento.
var sqlPredicates = new List < string > ( ) ;
var queryParams = new DynamicParameters ( ) ;
if ( boolExpression )
{
sqlPredicates . Add ( " column1 = @param1 " ) ;
queryParams . Add ( " param1 " , dynamicValue1 , System . Data . DbType . Guid ) ;
} else {
sqlPredicates . Add ( " column2 = @param2 " ) ;
queryParams . Add ( " param2 " , dynamicValue2 , System . Data . DbType . String ) ;
}
DynamicParameters también admite copiar múltiples parámetros de objetos existentes de diferentes tipos.
var queryParams = new DynamicParameters ( objectOfType1 ) ;
queryParams . AddDynamicParams ( objectOfType2 ) ;
Cuando un objeto que implementa la interfaz IDynamicParameters
pasada en funciones Execute
o Query
, los valores de los parámetros se extraerán a través de esta interfaz. Obviamente, la clase de objetos más probable para usar para este propósito sería la clase DynamicParameters
incorporada.
Dapper le permite pasar en IEnumerable<int>
y parametrizará automáticamente su consulta.
Por ejemplo:
connection . Query < int > ( " select * from (select 1 as Id union all select 2 union all select 3) as X where Id in @Ids " , new { Ids = new int [ ] { 1 , 2 , 3 } } ) ;
Será traducido a:
select * from ( select 1 as Id union all select 2 union all select 3 ) as X where Id in ( @Ids1 , @Ids2 , @Ids3 ) " // @Ids1 = 1 , @Ids2 = 2 , @Ids2 = 3
Dapper admite reemplazos literales para bool y tipos numéricos.
connection . Query ( " select * from User where UserTypeId = {=Admin} " , new { UserTypeId . Admin } ) ;
El reemplazo literal no se envía como un parámetro; Esto permite mejores planes y uso del índice filtrado, pero generalmente debe usarse con moderación y después de las pruebas. Esta característica es particularmente útil cuando el valor inyectado es en realidad un valor fijo (por ejemplo, una "ID de categoría" fija, "código de estado" o "región" que es específica para la consulta). Para los datos en vivo donde está considerando literales, es posible que también desee considerar y probar sugerencias de consultas específicas del proveedor como OPTIMIZE FOR UNKNOWN
con parámetros regulares.
El comportamiento predeterminado de Dapper es ejecutar su SQL y amortiguar todo el lector al regreso. Esto es ideal en la mayoría de los casos, ya que minimiza los bloqueos compartidos en el DB y reduce el tiempo de red de DB.
Sin embargo, al ejecutar consultas enormes, es posible que deba minimizar la huella de la memoria y solo cargar objetos según sea necesario. Para hacerlo, buffered: false
en el método Query
.
Dapper le permite asignar una sola fila a varios objetos. Esta es una característica clave si desea evitar consultas extrañas y asociaciones de carga ansiosas.
Ejemplo:
Considere 2 clases: Post
y User
class Post
{
public int Id { get ; set ; }
public string Title { get ; set ; }
public string Content { get ; set ; }
public User Owner { get ; set ; }
}
class User
{
public int Id { get ; set ; }
public string Name { get ; set ; }
}
Ahora digamos que queremos asignar una consulta que se une tanto en las publicaciones como a la tabla de usuarios. Hasta ahora, si necesitábamos combinar el resultado de 2 consultas, necesitaríamos un nuevo objeto para expresarlo, pero tiene más sentido en este caso colocar el objeto User
dentro del objeto Post
.
Este es el caso de uso para mapeo múltiple. Le dice a Dapper que la consulta devuelve una Post
y un objeto User
y luego le da una función que describe lo que desea hacer con cada una de las filas que contienen una Post
y un objeto User
. En nuestro caso, queremos tomar el objeto de usuario y colocarlo dentro del objeto de publicación. Entonces escribimos la función:
( post , user ) => { post . Owner = user ; return post ; }
Los 3 argumentos de tipo para el método Query
especifican qué objetos debe usar el dapper para deserializar la fila y lo que se va a devolver. Vamos a interpretar ambas filas como una combinación de Post
y User
y estamos devolviendo un objeto Post
. Por lo tanto, la declaración de tipo se convierte en
< Post , User , Post >
Todo se junta, se ve así:
var sql =
@"select * from #Posts p
left join #Users u on u.Id = p.OwnerId
Order by p.Id" ;
var data = connection . Query < Post , User , Post > ( sql , ( post , user ) => { post . Owner = user ; return post ; } ) ;
var post = data . First ( ) ;
Assert . Equal ( " Sams Post1 " , post . Content ) ;
Assert . Equal ( 1 , post . Id ) ;
Assert . Equal ( " Sam " , post . Owner . Name ) ;
Assert . Equal ( 99 , post . Owner . Id ) ;
Dapper puede dividir la fila devuelta al suponer que sus columnas de identificación se denominan Id
o id
. Si su clave principal es diferente o desea dividir la fila en un punto que no sea Id
, use el parámetro splitOn
opcional.
Dapper le permite procesar múltiples cuadrículas de resultados en una sola consulta.
Ejemplo:
var sql =
@"
select * from Customers where CustomerId = @id
select * from Orders where CustomerId = @id
select * from Returns where CustomerId = @id" ;
using ( var multi = connection . QueryMultiple ( sql , new { id = selectedId } ) )
{
var customer = multi . Read < Customer > ( ) . Single ( ) ;
var orders = multi . Read < Order > ( ) . ToList ( ) ;
var returns = multi . Read < Return > ( ) . ToList ( ) ;
.. .
}
Dapper admite plenamente los procesos almacenados:
var user = cnn . Query < User > ( " spGetUser " , new { Id = 1 } ,
commandType : CommandType . StoredProcedure ) . SingleOrDefault ( ) ;
Si quieres algo más elegante, puedes hacer:
var p = new DynamicParameters ( ) ;
p . Add ( " @a " , 11 ) ;
p . Add ( " @b " , dbType : DbType . Int32 , direction : ParameterDirection . Output ) ;
p . Add ( " @c " , dbType : DbType . Int32 , direction : ParameterDirection . ReturnValue ) ;
cnn . Execute ( " spMagicProc " , p , commandType : CommandType . StoredProcedure ) ;
int b = p . Get < int > ( " @b " ) ;
int c = p . Get < int > ( " @c " ) ;
Dapper admite Varchar Params, si está ejecutando una cláusula WHERE en una columna Varchar usando un param, asegúrese de pasarlo de esta manera:
Query < Thing > ( " select * from Thing where Name = @Name " , new { Name = new DbString { Value = " abcde " , IsFixedLength = true , Length = 10 , IsAnsi = true } } ) ;
En SQL Server es crucial usar el Unicode al consultar Unicode y ANSI al consultar no unicode.
Por lo general, querrá tratar todas las filas de una tabla determinada como el mismo tipo de datos. Sin embargo, hay algunas circunstancias en las que es útil poder analizar diferentes filas como diferentes tipos de datos. Aquí es donde IDataReader.GetRowParser
es útil.
Imagine que tiene una tabla de base de datos llamada "formas" con las columnas: Id
, Type
y Data
, y desea analizar sus filas en objetos Circle
, Square
o Triangle
en función del valor de la columna Tipo.
var shapes = new List < IShape > ( ) ;
using ( var reader = connection . ExecuteReader ( " select * from Shapes " ) )
{
// Generate a row parser for each type you expect.
// The generic type <IShape> is what the parser will return.
// The argument (typeof(*)) is the concrete type to parse.
var circleParser = reader . GetRowParser < IShape > ( typeof ( Circle ) ) ;
var squareParser = reader . GetRowParser < IShape > ( typeof ( Square ) ) ;
var triangleParser = reader . GetRowParser < IShape > ( typeof ( Triangle ) ) ;
var typeColumnIndex = reader . GetOrdinal ( " Type " ) ;
while ( reader . Read ( ) )
{
IShape shape ;
var type = ( ShapeType ) reader . GetInt32 ( typeColumnIndex ) ;
switch ( type )
{
case ShapeType . Circle :
shape = circleParser ( reader ) ;
break ;
case ShapeType . Square :
shape = squareParser ( reader ) ;
break ;
case ShapeType . Triangle :
shape = triangleParser ( reader ) ;
break ;
default :
throw new NotImplementedException ( ) ;
}
shapes . Add ( shape ) ;
}
}
Para usar variables SQL que no son de parámetros con el conector MySQL, debe agregar la siguiente opción a su cadena de conexión:
Allow User Variables=True
Asegúrese de no proporcionarle a Dapper una propiedad para mapear.
Dapper almacena información sobre cada consulta que se ejecuta, esto le permite materializar objetos rápidamente y procesar los parámetros rápidamente. La implementación actual almacena esta información en un objeto ConcurrentDictionary
. Las declaraciones que solo se usan una vez se enjuagan rutinariamente de este caché. Aún así, si está generando cadenas SQL en la marcha sin usar parámetros, es posible que pueda alcanzar problemas de memoria.
La simplicidad de Dapper significa que se eliminan muchas características con las que se envían Orms. Se preocupa por el escenario del 95% y le brinda las herramientas que necesita la mayor parte del tiempo. No intenta resolver todos los problemas.
Dapper no tiene detalles de implementación específicos de DB, funciona en todos los proveedores de ADO .NET, incluidos SQLite, SQL CE, Firebird, Oracle, Mariadb, MySQL, PostgreSQL y SQL Server.
Dapper tiene un conjunto de pruebas integral en el proyecto de prueba.
Dapper está en uso de producción en Stack Overflow.