Dapper Net
Dapper Net
Dapper Net
NET
#dapper
Table of Contents
About 1
Remarks 2
What is Dapper? 2
Common Tasks 2
Versions 2
Examples 2
Using Dapper in C# 3
Syntax 5
Parameters 5
Examples 5
Remarks 7
Examples 7
Bulk Copy 7
Examples 9
Basic Usage 9
Examples 11
Execute a command that returns no results 11
Stored Procedures 11
Simple usage 11
Examples 13
null vs DBNull 13
Chapter 7: Multimapping 14
Syntax 14
Parameters 14
Examples 15
One-to-many mapping 16
Custom Mappings 19
Syntax 21
Parameters 21
Examples 21
Parameters 22
Remarks 22
Examples 22
Stored Procedures 23
Value Inlining 24
List Expansions 24
Examples 27
Syntax 29
Examples 29
Using a Transaction 29
Speed up inserts 30
Remarks 31
Examples 31
Installing a TypeHandler 31
Examples 32
Examples 33
Configuration required 33
Credits 35
About
You can share this PDF with anyone you feel could benefit from it, downloaded the latest version
from: dapper-net
It is an unofficial and free Dapper.NET ebook created for educational purposes. All the content is
extracted from Stack Overflow Documentation, which is written by many hardworking individuals at
Stack Overflow. It is neither affiliated with Stack Overflow nor official Dapper.NET.
The content is released under Creative Commons BY-SA, and the list of contributors to each
chapter are provided in the credits section at the end of this book. Images may be copyright of
their respective owners unless otherwise specified. All trademarks and registered trademarks are
the property of their respective company owners.
Use the content presented in this book at your own risk; it is not guaranteed to be correct nor
accurate, please send your feedback and corrections to [email protected]
https://riptutorial.com/ 1
Chapter 1: Getting started with Dapper.NET
Remarks
What is Dapper?
Dapper is a micro-ORM for .Net that extends your IDbConnection, simplifying query setup,
execution, and result-reading.
Common Tasks
• Basic Querying
• Executing Commands
Versions
1.42.0 2015-05-06
1.40.0 2015-04-03
1.30.0 2014-08-14
1.20.0 2014-05-08
1.10.0 2012-06-27
1.0.0 2011-04-14
Examples
Install Dapper from Nuget
https://riptutorial.com/ 2
Tools > NuGet Package Manager > Manage Packages for Solution... (Visual Studio 2015)
Or run this command in a Nuget Power Shell instance to install the latest stable version
Install-Package Dapper
Using Dapper in C#
using System.Data;
using System.Linq;
using Dapper;
class Program
{
static void Main()
{
using (IDbConnection db = new
SqlConnection("Server=myServer;Trusted_Connection=true"))
{
db.Open();
var result = db.Query<string>("SELECT 'Hello World'").Single();
Console.WriteLine(result);
}
}
}
LINQPad is great for testing database queries and includes NuGet integration. To use Dapper in
LINQPad press F4 to open the Query Properties and then select Add NuGet. Search for dapper
dot net and select Add To Query. You will also want to click Add namespaces and highlight
Dapper to include the Extension Methods in your LINQPad query.
https://riptutorial.com/ 3
Once Dapper is enabled you can change the Language drop down to C# Program, map query
results to C# classes, and use the .Dump() method to inspect the results:
void Main()
{
using (IDbConnection db = new SqlConnection("Server=myServer;Trusted_Connection=true")){
db.Open();
var scalar = db.Query<string>("SELECT GETDATE()").SingleOrDefault();
scalar.Dump("This is a string scalar result:");
The results when executing the program would look like this:
https://riptutorial.com/ 4
Chapter 2: Basic Querying
Syntax
• public static IEnumerable<T> Query<T>(this IDbConnection cnn, string sql, object param =
null, SqlTransaction transaction = null, bool buffered = true)
• public static IEnumerable<dynamic> Query (this IDbConnection cnn, string sql, object param
= null, SqlTransaction transaction = null, bool buffered = true)
Parameters
Parameter Details
Whether or not to buffer reading the results of the query. This is an optional
parameter with the default being true. When buffered is true, the results are
buffered into a List<T> and then returned as an IEnumerable<T> that is safe for
multiple enumeration. When buffered is false, the sql connection is held open
until you finish reading allowing you to process a single row at time in memory.
Multiple enumerations will spawn additional connections to the database. While
buffered
buffered false is highly efficient for reducing memory usage if you only maintain
very small fragments of the records returned it has a sizeable performance
overhead compared to eagerly materializing the result set. Lastly if you have
numerous concurrent unbuffered sql connections you need to consider
connection pool starvation causing requests to block until connections become
available.
Examples
Querying for a static type
https://riptutorial.com/ 5
public float? Weight { get; set; }
//
IDBConnection db = /* ... */;
You can also query dynamically if you leave off the generic type.
var query = "Select * from Cats where Color = :Color and Age > :Age";
var dynamicParameters = new DynamicParameters();
dynamicParameters.Add("Color", color);
dynamicParameters.Add("Age", age);
using (var connection = new SqlConnection(/* Your Connection String Here */))
{
IEnumerable<dynamic> results = connection.Query(query, dynamicParameters);
}
https://riptutorial.com/ 6
Chapter 3: Bulk inserts
Remarks
The WriteToServer and WriteToServerAsync have overloads that accept IDataReader (seen in the
examples), DataTable, and DataRow arrays (DataRow[]) as the source of the data for the Bulk
Copy.
Examples
Async Bulk Copy
This sample uses a ToDataReader method described here Creating a Generic List DataReader for
SqlBulkCopy.
Bulk Copy
This sample uses a ToDataReader method described here Creating a Generic List DataReader for
SqlBulkCopy.
https://riptutorial.com/ 7
public class Widget
{
public int WidgetId {get;set;}
public string Name {get;set;}
public int Quantity {get;set;}
}
https://riptutorial.com/ 8
Chapter 4: Dynamic Parameters
Examples
Basic Usage
It isn't always possible to neatly package all the parameters up in a single object / call. To help
with more complicated scenarios, dapper allows the param parameter to be an IDynamicParameters
instance. If you do this, your custom AddParameters method is called at the appropriate time and
handed the command to append to. In most cases, however, it is sufficient to use the pre-existing
DynamicParameters type:
This shows:
Note that due to how RDBMS protocols work, it is usually only reliable to obtain updated
parameter values after any data (from a Query or QueryMultiple` operation) has been fully
consumed (for example, on SQL Server, updated parameter values are at the end of the TDS
stream).
https://riptutorial.com/ 9
var p = new DynamicParameters(template);
https://riptutorial.com/ 10
Chapter 5: Executing Commands
Examples
Execute a command that returns no results
IDBConnection db = /* ... */
var id = /* ... */
Stored Procedures
Simple usage
Dapper fully supports stored procs:
conn.Execute("spMagicProc", p,
commandType: CommandType.StoredProcedure);
var b = p.Get<int>("@b");
var c = p.Get<int>("@c");
https://riptutorial.com/ 11
CREATE TYPE [dbo].[myUDTT] AS TABLE([i1] [int] NOT NULL);
GO
CREATE PROCEDURE myProc(@data dbo.myUDTT readonly) AS
SELECT i1 FROM @data;
GO
/*
-- optionally grant permissions as needed, depending on the user you execute this with.
-- Especially the GRANT EXECUTE ON TYPE is often overlooked and can cause problems if omitted.
GRANT EXECUTE ON TYPE::[dbo].[myUDTT] TO [user];
GRANT EXECUTE ON dbo.myProc TO [user];
GO
*/
To call that procedure from within c#, you need to do the following:
https://riptutorial.com/ 12
Chapter 6: Handling Nulls
Examples
null vs DBNull
In ADO.NET, correctly handling null is a constant source of confusion. The key point in dapper is
that you don't have to; it deals with it all internally.
It just works:
https://riptutorial.com/ 13
Chapter 7: Multimapping
Syntax
• public static IEnumerable<TReturn> Query<TFirst, TSecond, TReturn>( this IDbConnection cnn,
string sql, Func<TFirst, TSecond, TReturn> map, object param = null, IDbTransaction
transaction = null, bool buffered = true, string splitOn = "Id", int? commandTimeout =
null, CommandType? commandType = null)
• public static IEnumerable<TReturn> Query<TFirst, TSecond, TThird, TFourth, TFifth, TSixth,
TSeventh, TReturn>(this IDbConnection cnn, string sql, Func<TFirst, TSecond, TThird,
TFourth, TFifth, TSixth, TSeventh, TReturn> map, object param = null, IDbTransaction
transaction = null, bool buffered = true, string splitOn = "Id", int? commandTimeout =
null, CommandType? commandType = null)
• public static IEnumerable<TReturn> Query<TReturn>(this IDbConnection cnn, string sql,
Type[] types, Func<object[], TReturn> map, object param = null, IDbTransaction transaction
= null, bool buffered = true, string splitOn = "Id", int? commandTimeout = null,
CommandType? commandType = null)
Parameters
Parameter Details
The Field we should split and read the second object from (default: id).
splitOn
This can be a comma delimited list when more than 1 type is contained
https://riptutorial.com/ 14
Parameter Details
in a record.
Examples
Simple multi-table mapping
Let's say we have a query of the remaining horsemen that needs to populate a Person class.
We can populate the person class as well as the Residence property with an instance of Country
using an overload Query<> that takes a Func<> that can be used to compose the returned instance.
The Func<> can take up to 7 input types with the final generic argument always being the return
type.
var sql = @"SELECT 'Daniel Dennett' AS Name, 1942 AS Born, 'United States of America' AS
Residence
UNION ALL SELECT 'Sam Harris' AS Name, 1967 AS Born, 'United States of America' AS Residence
UNION ALL SELECT 'Richard Dawkins' AS Name, 1941 AS Born, 'United Kingdom' AS Residence";
https://riptutorial.com/ 15
splitOn: "Residence");
Note the use of the splitOn: "Residence" argument which is the 1st column of the next
class type to be populated (in this case Country). Dapper will automatically look for a
column called Id to split on but if it does not find one and splitOn is not provided a
System.ArgumentException will be thrown with a helpful message. So although it is
optional you will usually have to supply a splitOn value.
One-to-many mapping
Let's look at a more complex example that contains a one-to-many relationship. Our query will
now contain multiple rows containing duplicate data and we will need to handle this. We do this
with a lookup in a closure.
https://riptutorial.com/ 16
public int CountryId { get; set; }
public string CountryName { get; set; }
}
The dictionaryremainingHorsemen will be populated with fully materialized instances of the person
objects. For each row of the query result the mapped values of instances of the types defined in
the lambda arguments are passed in and it is up to you how to handle this.
//country
if(personEntity.Residience == null)
{
if (country == null)
{
country = new Country { CountryName = "" };
}
personEntity.Residience = country;
}
//books
if(personEntity.Books == null)
{
personEntity.Books = new List<Book>();
}
if (book != null)
{
if (!personEntity.Books.Any(x => x.BookId == book.BookId))
https://riptutorial.com/ 17
{
personEntity.Books.Add(book);
}
}
return personEntity;
},
splitOn: "CountryId,BookId");
Note how the splitOn argument is a comma delimited list of the first columns of the
next type.
Sometimes the number of types you are mapping exceeds the 7 provided by the Func<> that does
the construction.
Instead of using the Query<> with the generic type argument inputs, we will provide the types to
map to as an array, followed by the mapping function. Other than the initial manual setting and
casting of the values, the rest of the function does not change.
//person
Person personEntity;
//trip
if (!remainingHorsemen.TryGetValue(person.Id, out personEntity))
{
remainingHorsemen.Add(person.Id, personEntity = person);
https://riptutorial.com/ 18
}
//country
if(personEntity.Residience == null)
{
if (country == null)
{
country = new Country { CountryName = "" };
}
personEntity.Residience = country;
}
//books
if(personEntity.Books == null)
{
personEntity.Books = new List<Book>();
}
if (book != null)
{
if (!personEntity.Books.Any(x => x.BookId == book.BookId))
{
personEntity.Books.Add(book);
}
}
return personEntity;
},
splitOn: "CountryId,BookId");
Custom Mappings
If the query column names do not match your classes you can setup mappings for types. This
example demonstrates mapping using System.Data.Linq.Mapping.ColumnAttributeas well as a
custom mapping.
The mappings only need to be setup once per type so set them on application startup
or somewhere else that they are only initialized once.
Assuming the same query as the One-to-many example again and the classes refactored toward
better names like so:
[System.Data.Linq.Mapping.Column(Name = "CountryName")]
https://riptutorial.com/ 19
public string Name { get; set; }
}
Note how Book doesn't rely on ColumnAttribute but we would need to maintain the if
statement
Now place this mapping code somewhere in your application where it is only executed once:
Dapper.SqlMapper.SetTypeMap(
typeof(Country),
new CustomPropertyTypeMap(
typeof(Country),
(type, columnName) =>
type.GetProperties().FirstOrDefault(prop =>
prop.GetCustomAttributes(false)
.OfType<System.Data.Linq.Mapping.ColumnAttribute>()
.Any(attr => attr.Name == columnName)))
);
if (columnName == "BookName")
{
return type.GetProperty("Name");
}
Then the query is executed using any of the previous Query<> examples.
https://riptutorial.com/ 20
Chapter 8: Multiple Results
Syntax
• public static SqlMapper.GridReader QueryMultiple(this IDbConnection cnn, string sql, object
param = null, IDbTransaction transaction = null, int? commandTimeout = null,
CommandType? commandType = null)
• public static SqlMapper.GridReader QueryMultiple(this IDbConnection cnn,
CommandDefinition command)
Parameters
Parameter Details
Examples
Base Multiple Results Example
To fetch multiple grids in a single query, the QueryMultiple method is used. This then allows you to
retrieve each grid sequentially through successive calls against the GridReader returned.
https://riptutorial.com/ 21
Chapter 9: Parameter Syntax Reference
Parameters
Parameter Details
(optional) Whether to pre-consume the data into a list (the default), versus
buffered
exposing an open IEnumerable over the live reader
Remarks
The syntax for expressing parameters varies between RDBMS. All the examples above use SQL
Server syntax, i.e. @foo; however, ?foo and :foo should also work fine.
Examples
Basic Parameterized SQL
Dapper makes it easy to follow best practice by way of fully parameterized SQL.
https://riptutorial.com/ 22
Parameters are important, so dapper makes it easy to get it right. You just express your
parameters in the normal way for your RDBMS (usually @foo, ?foo or :foo) and give dapper an
object that has a member called foo. The most common way of doing this is with an anonymous
type:
int id = 123;
string name = "abc";
connection.Execute("insert [KeyLookup](Id, Name) values(@id, @name)",
new { id, name });
And... that's it. Dapper will add the required parameters and everything should work.
Dapper uses the command-text to determine which members of the object to add - it won't usually
add unnecessary things like Description, IsActive, CreationDate because the command we've
issued clearly doesn't involve them - although there are cases when it might do that, for example if
your command contains:
Stored Procedures
Parameters to stored procedures work exactly the same, except that dapper cannot attempt to
determine what should/should-not be included - everything available is treated as a parameter. For
that reason, anonymous types are usually preferred:
https://riptutorial.com/ 23
Value Inlining
Sometimes the convenience of a parameter (in terms of maintenance and expressiveness), may
be outweighed by its cost in performance to treat it as a parameter. For example, when page size
is fixed by a configuration setting. Or a status value is matched to an enum value. Consider:
The only real parameter here is customerId - the other two are pseudo-parameters that won't
actually change. Often the RDBMS can do a better job if it detects these as constants. Dapper has
a special syntax for this - {=name} instead of @name - which only applies to numeric types. (This
minimizes any attack surface from SQL injection). An example is as follows:
Dapper replaces values with literals before issuing the SQL, so the RDBMS actually sees
something like:
select top 10 *
from Orders
where CustomerId = @customerId
and Status = 3
This is particularly useful when allowing RDBMS systems to not just make better decisions, but to
open up query plans that actual parameters prevent. For example, if a column predicate is against
a parameter, then a filtered index with specific values on that columns cannot be used. This is
because the next query may have a parameter apart from one of those specified values.
With literal values, the query optimizer is able to make use of the filtered indexes since it knows
the value cannot change in future queries.
List Expansions
A common scenario in database queries is IN (...) where the list here is generated at runtime.
Most RDBMS lack a good metaphor for this - and there is no universal cross-RDBMS solution for
this. Instead, dapper provides some gentle automatic command expansion. All that is requires is a
supplied parameter value that is IEnumerable. A command involving @foo is expanded to
(@foo0,@foo1,@foo2,@foo3) (for a sequence of 4 items). The most common usage of this would be
IN:
https://riptutorial.com/ 24
var orders = connection.Query<Order>(@"
select *
from Orders
where Id in @orderIds", new { orderIds });
This then automatically expands to issue appropriate SQL for the multi-row fetch:
select *
from Orders
where Id in (@orderIds0, @orderIds1, @orderIds2, @orderIds3)
with the parameters @orderIds0 etc being added as values taken from the arrray. Note that the fact
that it isn't valid SQL originally is intentional, to ensure that this feature is not used mistakenly.
This feature also works correctly with the OPTIMIZE FOR / UNKNOWN query-hint in SQL Server; if you
use:
Sometimes, you want to do the same thing multiple times. Dapper supports this on the Execute
method if the outermost parameter (which is usually a single anonymous type, or a domain model
instance) is actually provided as an IEnumerable sequence. For example:
Here, dapper is just doing a simple loop on our data, essentially the same as if we had done:
This usage becomes particularly interesting when combined with the async API on a connection
that is explicitly configured to all "Multiple Active Result Sets" - in this usage, dapper will
automatically pipeline the operations, so you aren't paying the latency cost per row. This requires
a slightly more complicated usage,
await connection.ExecuteAsync(
new CommandDefinition(
"update Orders set Total=@Total where Id=@Id",
https://riptutorial.com/ 25
orders, flags: CommandFlags.Pipelined))
Note, however, that you might also wish to investigate table valued parameters.
Some ADO.NET providers (most notably: OleDB) do not support named parameters; parameters
are instead specified only by position, with the ? place-holder. Dapper would not know what
member to use for these, so dapper allows an alternative syntax, ?foo?; this would be the same as
@foo or :foo in other SQL variants, except that dapper will replace the parameter token completely
with ? before executing the query.
This works in combination with other features such as list expansion, so the following is valid:
The .region and .users members are used accordingly, and the SQL issued is (for example, with 3
users):
Note, however, that dapper does not allow the same parameter to be used multiple times when
using this feature; this is to prevent having to add the same parameter value (which could be
large) multiple times. If you need to refer to the same value multiple times, consider declaring a
variable, for example:
declare @id int = ?id?; // now we can use @id multiple times in the SQL
If variables are not available, you can use duplicate member names in the parameters - this will
also make it obvious that the value is being sent multiple times:
int id = 42;
connection.Execute("... where ParentId = $id0$ ... SomethingElse = $id1$ ...",
new { id0 = id, id1 = id });
https://riptutorial.com/ 26
Chapter 10: Temp Tables
Examples
Temp Table that exists while the connection remains open
When the temp table is created by itself, it will remain while the connection is open.
await conn.ExecuteAsync(@"
update w
set Quantity = w.Quantity - tw.Quantity
from Widgets w
join #tmpWidget tw on w.WidgetId = tw.WidgetId");
}
}
The point about temporary tables is that they're limited to the scope of the connection. Dapper will
automatically open and close a connection if it's not already opened. That means that any temp
table will be lost directly after creating it, if the connection passed to Dapper has not been opened.
// this will throw an error because the #tmpWidget table no longer exists
await conn.ExecuteAsync(@"insert into #tmpWidget(WidgetId) VALUES (1);");
https://riptutorial.com/ 27
return await conn.QueryAsync<int>(@"SELECT * FROM #tmpWidget;");
}
}
https://riptutorial.com/ 28
Chapter 11: Transactions
Syntax
• conn.Execute(sql, transaction: tran); // specify the parameter by name
• conn.Execute(sql, parameters, tran);
• conn.Query(sql, transaction: tran);
• conn.Query(sql, parameters, tran);
• await conn.ExecuteAsync(sql, transaction: tran); // Async
• await conn.ExecuteAsync(sql, parameters, tran);
• await conn.QueryAsync(sql, transaction: tran);
• await conn.QueryAsync(sql, parameters, tran);
Examples
Using a Transaction
// pass the transaction along to the Query, Execute, or the related Async
methods.
conn.Execute(sql, parameters, tran);
https://riptutorial.com/ 29
Speed up inserts
Wrapping a group of inserts in a transaction will speed them up according to this StackOverflow
Question/Answer.
You can use this technique, or you can use Bulk Copy to speed up a series of related operations
to perform.
https://riptutorial.com/ 30
Chapter 12: Type Handlers
Remarks
Type Handlers allow database types to be converted to .Net custom types.
Examples
Converting varchar to IHtmlString
Installing a TypeHandler
The above type handler can be installed into SqlMapper using the AddTypeHandler method.
SqlMapper.AddTypeHandler<IHtmlString>(new IHtmlStringTypeHandler());
SqlMapper.AddTypeHandler(new IHtmlStringTypeHandler());
https://riptutorial.com/ 31
Chapter 13: Using Async
Examples
Calling a Stored Procedure
https://riptutorial.com/ 32
Chapter 14: Using DbGeography and
DbGeometry
Examples
Configuration required
1. install the required Microsoft.SqlServer.Types assembly; they are not installed by default, and
are available from Microsoft here as "Microsoft® System CLR Types for Microsoft® SQL
Server® 2012" - note that there are separate installers for x86 and x64.
2. install Dapper.EntityFramework (or the strong-named equivalent); this could be done via the
IDE's "Manage NuGet Packages..." UI, or (at the Package Manager Console):
install-package Dapper.EntityFramework
3. add the required assembly binding redirects; this is because Microsoft ships v11 of the
assemblies, but Entity Framework asks for v10; you can add the following to app.config or
web.config under the <configuration> element:
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="Microsoft.SqlServer.Types"
publicKeyToken="89845dcd8080cc91" />
<bindingRedirect oldVersion="10.0.0.0" newVersion="11.0.0.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
4. tell "dapper" about the new type handlers available, by adding (somewhere in your startup,
before it tries using the database):
Dapper.EntityFramework.Handlers.Register();
Once the type handlers are registered, everything should work automatically, and you should be
able to use these types as either parameters or return values:
https://riptutorial.com/ 33
"declare @geos table(geo geography); insert @geos(geo) values(@val); select * from @geos",
new { val = orig });
https://riptutorial.com/ 34
Credits
S.
Chapters Contributors
No
Getting started with Adam Lear, balpha, Community, Eliza, Greg Bray, Jarrod Dixon,
1
Dapper.NET Kevin Montrose, Matt McCabe, Nick, Rob, Shog9
Executing
5 Adam Lear, Jarrod Dixon, Sklivvz, takrl
Commands
Parameter Syntax
9 4444, Marc Gravell, Nick Craver
Reference
11 Transactions jhamm
Using DbGeography
14 Marc Gravell
and DbGeometry
https://riptutorial.com/ 35