Using Dapper: A Practical Guide

For projects with low traffic, I often use Entity Framework for database operations because of its rapid development speed, despite its slower performance. It saves a lot of SQL writing and makes it convenient to handle foreign keys, collections, and more. However, for websites that need to consider runtime speed, I have to use other ORM frameworks. I frequently use Dapper because of its high performance and flexible SQL writing. Below are some methods demonstrating the use of Dapper.

1. Connection String

var conn = new SqlConnection(ConfigurationManager.ConnectionStrings["SqlDiagnosticsDb"].ConnectionString);

When using Dapper, you don't need to worry about whether the connection is open; Dapper automatically checks and opens it if necessary during execution.

2. Insert

string query = "INSERT INTO Book(Name) VALUES(@name)";
conn.Execute(query, book);

If the book class has a Name property, you can write it conveniently. Alternatively, you can do:

string query = "INSERT INTO Book(Name) VALUES(@name)";
conn.Execute(query, new { @name = book.Name });

3. Update

string query = "UPDATE Book SET Name = @name WHERE Id = @id";
conn.Execute(query, book);

4. Delete

string query = "DELETE FROM Book WHERE Id = @id";
conn.Execute(query, book);
// or
conn.Execute(query, new { id = id });

5. Query

string query = "SELECT * FROM Book";
// No parameters, returns list
conn.Query<Book>(query).ToList();

// Single record
string query = "SELECT * FROM Book WHERE Id = @id";
book = conn.Query<Book>(query, new { id = id }).SingleOrDefault();

6. Using IN Clause

conn.Query<Users>("SELECT * FROM Users WHERE Id IN @ids", new { ids = new int[] { 1, 2, 3 } });

// Or using an array
conn.Query<Users>("SELECT * FROM Users WHERE Id IN @ids", new { ids = IDs.ToArray() });

Dapper requires parameterized queries for security; you cannot directly concatenate strings.

7. Batch Insert

conn.Execute(@"INSERT INTO MyTable (ColA, ColB) VALUES (@a, @b)",
    new[] { new { a = 1, b = 1 }, new { a = 2, b = 2 }, new { a = 3, b = 3 } });

Or you can pass a collection directly:

conn.Execute("INSERT INTO Users (Name) VALUES (@Name)", users);

Here, users is a collection of User objects; all data will be inserted in one go.

8. Multi-Table Query (One-to-Many)

string query = "SELECT * FROM Book b LEFT JOIN BookReview br ON br.BookId = b.Id WHERE b.Id = @id";
Book lookup = null;
var book = conn.Query<Book, BookReview, Book>(query,
    (book, bookReview) =>
    {
        if (lookup == null || lookup.Id != book.Id)
            lookup = book;
        if (bookReview != null)
            lookup.Reviews.Add(bookReview);
        return lookup;
    },
    new { id = id }).Distinct().SingleOrDefault();
return book;

Multi-table joins can be tricky. Here's another example:

var sql = @"SELECT * FROM Posts p JOIN Users u ON u.Id = p.OwnerId ORDER BY p.Id";
var data = conn.Query<Post, User, Post>(sql, (post, user) => { post.Owner = user; return post; }, splitOn: "Id");

The splitOn parameter specifies the field where the mapping splits. Dapper maps all fields before the first Id (case-insensitive) to the first type, and from Id onward to the second type.

9. Three-Table Query (with Collecsion)

public partial class UserInfo
{
    public UserInfo()
    {
        this.Person = new HashSet<Person>();
        this.MyTYC = new HashSet<MyTYC>();
    }
    public int Id { get; set; }
    public string Name { get; set; }
    public DateTime? CreateTime { get; set; }
    public Movies Movies { get; set; }
    public virtual ICollection<MyTYC> MyTYC { get; set; }
}

public class Movies
{
    public int ID { get; set; }
    public string Title { get; set; }
    public string ReleaseDate { get; set; }
    public string Genre { get; set; }
    public string Price { get; set; }
    public UserInfo UserInfo { get; set; }
}

public partial class MyTYC
{
    public int Id { get; set; }
    public string Name { get; set; }
}

string sql = @"SELECT * FROM UserInfo u
               INNER JOIN Movies m ON u.Id = m.ID
               INNER JOIN MyTYC t ON u.Id = t.Id";
var data = conn.Query<UserInfo, Movies, MyTYC, UserInfo>(sql,
    (u, m, t) => { u.Movies = m; u.MyTYC.Add(t); return u; });

Notice how the single object (Movies) and collection (MyTYC) are handled.

10. Multiple Result Sets

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();
}

Another example:

class Program
{
    protected static SqlConnection GetConnection()
    {
        var connection = new SqlConnection("Data Source=.;Initial Catalog=TestDB;Integrated Security=True");
        connection.Open();
        return connection;
    }

    static void Main(string[] args)
    {
        var sql = @"INSERT INTO [dbo].[Student] ([Name]) VALUES ('A1'); SELECT @@IDENTITY as A;
                     INSERT INTO [dbo].[Student] ([Name]) VALUES ('B1'); SELECT @@IDENTITY as A;
                     INSERT INTO [dbo].[Student] ([Name]) VALUES ('C1'); SELECT @@IDENTITY as A";

        using (SqlConnection connection = GetConnection())
        {
            List<int> ilist = new List<int>();
            var multi = connection.QueryMultiple(sql);

            while (!multi.IsConsumed)
            {
                var result = multi.Read().ToList()[0].A;
                if (result != null)
                {
                    ilist.Add(Convert.ToInt32(result));
                }
            }

            foreach (var item in ilist)
            {
                Console.WriteLine(item.ToString());
            }
        }
        Console.ReadLine();
    }
}

11. Managing Connection State

If you need to perform multiple operations, you can open the connection once and close it at the end:

conn.Open();
// Multiple Dapper operations...
conn.Close();

Tags: Dapper ORM sql C# database

Posted on Thu, 27 Aug 2026 16:48:40 +0000 by jtbaker