Mastering Dapper in .NET Core: Advanced Techniques and Tips

Zuraiz Ahmed Shehzad
4 min readMar 28, 2023

--

Hey there techies, In last blog we had discussed fundamentals of Dapper if you haven’t read it yet click here. Now it’s time to dive into some advanced concepts of Dapper in .NET Core! Don’t worry, I’ll keep it engaging. Let’s get started!

Multi-Mapping

One of the coolest features of Dapper is its ability to map a single SQL query to multiple objects. This is called multi-mapping. Let’s say we have a database with a “users” table and a “posts” table, and we want to retrieve all the users and their associated posts. With Dapper’s multi-mapping feature, we can do this in one SQL query and map each row to a User object and a Post object.

Here’s an example:

var sql = "SELECT * FROM Users LEFT JOIN Posts ON Users.Id = Posts.UserId";
var result = await connection.QueryAsync<User, Post, User>(
sql,
(user, post) =>
{
user.Posts.Add(post);
return user;
},
splitOn: "PostId"
);

This SQL query returns multiple rows, each with user and post information. The splitOn parameter tells Dapper how to split the results and map them to separate objects. In this case, we're splitting on the "PostId" column.

Query Caching

Dapper’s query caching feature can be a huge performance boost for applications that frequently retrieve the same data. With query caching, Dapper stores the results of a query in memory so that subsequent calls don’t need to hit the database.

Here’s an example of how to use query caching with Dapper:

var cacheKey = "GetAllUsers";
var cachedResult = cache.Get<IEnumerable<User>>(cacheKey);

if (cachedResult != null)
{
return cachedResult;
}

var sql = "SELECT * FROM Users";
var result = await connection.QueryAsync<User>(sql);

cache.Set(cacheKey, result);

return result;

This code first checks if the results are already in the cache. If they are, it returns the cached results. Otherwise, it executes the SQL query and caches the results before returning them.

Bulk Inserts

Dapper’s bulk insert feature is great for inserting large amounts of data into a database quickly. It allows us to insert multiple rows in a single SQL statement.

Here’s an example:

var sql = "INSERT INTO Users (Name, Email) VALUES (@Name, @Email)";
var users = new List<User>
{
new User { Name = "Alice", Email = "alice@example.com" },
new User { Name = "Bob", Email = "bob@example.com" },
new User { Name = "Charlie", Email = "charlie@example.com" }
};

var result = await connection.ExecuteAsync(sql, users);

This code inserts three new users into the “users” table using a single SQL statement. We pass in a list of User objects and Dapper maps the properties to the SQL parameters automatically.

Stored Procedures

Stored procedures are precompiled SQL code that can be called from .NET code. They can be a powerful tool for improving performance and security in database applications.

Here’s an example of how to call a stored procedure with Dapper:

var sql = "EXECUTE dbo.GetUsers @id = @Id";
var parameters = new { Id = 1 };

var result = await connection.QueryAsync<User>(sql, parameters, commandType: CommandType.StoredProcedure);

This code calls a stored procedure called “GetUsers” with a parameter of 1. Dapper automatically maps the results to User objects.

Async Queries

Dapper fully supports asynchronous programming, which can improve performance and responsiveness in your application. You can use the QueryAsync and ExecuteAsync methods to execute queries asynchronously.

Here’s an example:

var sql = "SELECT * FROM Users WHERE Email = @Email";
var parameters = new { Email = "john@example.com" };

var result = await connection.QueryAsync<User>(sql, parameters);

Transaction Management

Dapper makes it easy to manage database transactions in your .NET Core application. You can use the BeginTransaction and Commit methods to start and commit a transaction.

using (var transaction = connection.BeginTransaction())
{
try
{
var sql1 = "INSERT INTO Users (Name, Email) VALUES (@Name, @Email)";
var user = new User { Name = "John", Email = "john@example.com" };
await connection.ExecuteAsync(sql1, user, transaction);

var sql2 = "UPDATE Orders SET UserId = @UserId WHERE Status = 'Pending'";
var parameters = new { UserId = user.Id };
await connection.ExecuteAsync(sql2, parameters, transaction);

transaction.Commit();
}
catch
{
transaction.Rollback();
throw;
}
}

In this code, we use a transaction to insert a new user into the “users” table and update the “orders” table with the new user ID. If an exception is thrown during either query, the transaction is rolled back.

Final Thoughts

Alright, folks, that’s a wrap on this blog post! I hope you had as much fun reading it as I had writing it. We covered some advanced concepts of Dapper in .NET Core that will definitely take your database access game to the next level.

By implementing mapping, stored procedures, asynchronous queries, dynamic parameters, and transaction management, you can optimize your application’s performance and efficiency like never before. With its user-friendly API and lightweight design, Dapper is the perfect ORM for any .NET Core developer looking to simplify their database access process.

So, what are you waiting for? Get cracking on your next project and give Dapper a try. I promise you won’t be disappointed, happy coding!

Before You Leave

  • Follow Me on Medium for tech savvy content. 😄
  • Connect with me on LinkedIn to talk about exciting world of software engineering. 🔗
  • Check out all of my coolest work on Medium. 👐

Checkout my other blogs on Dapper:

--

--

Zuraiz Ahmed Shehzad

Software engineer with a passion for cloud computing and system design. Committed to creating user-friendly solutions. Let's innovate together.