Dapper Use For Net

Dapper.Net by example

When the team behind StackOverflow released the mini-ORM Dapper, we were enthousiastic. An ORM with performance in mind!

Microsoft’s Entity Framework is still lagging behind and feels (is) like a beast. NHibernate is a beast as well, but is usally fast with second-level caching. For simple applications or scheduled tasks, it just too much. And for poorly designed legacy databases, it works against you. When you just need to write SQL queries and want to map the results to objects, a mini ORM suffices.

StackOverflow is one of the most responsive sites I know, so its ORM performance’s is proven. Dapper’s documentation however is somewhat sparse.

Basic usage

Download the single file SqlMapper.cs and dump it in your project.
Put using Dapper in your file with queries, because Dapper extends the normal IDbConnection interface (which is somewhat of a bad practice imho).
Use your favorite way (Dependency Injection of course) of providing a IDbConnection connection named conn,just as you normally would when using a ADO.NET. Basically like so:

using (var conn = new SqlConnection(myConnectionString)) {
    conn.Open();
    ....
}

A list of objects

Select a list of accounts from a certain webshop.

1
2
3
4
5
IEnumerable<Account> resultList = conn.Query<Account>(@"
                    SELECT *
                    FROM Account
                    WHERE shopId = @ShopId",
new {  ShopId = shopId });

The Account object is for example.

1
2
3
4
5
6
7
public class Account {
  public int? Id {get;set;}
  public string Name {get;set;}
  public string Address {get;set;}
  public string Country {get;set;}
  public int ShopId {get; set;}
}

Note that eventhough we use SELECT *, not all fields have to be present as class properties.

A single object

1
2
3
4
5
Account result = conn.Query<Account>(@"
                    SELECT *
                    FROM Account
                    WHERE Id = @Id",
   new {  Id = Id }).FirstOrDefault();

A dynamic object

If you’re too lazy to type out a class, you can use a dynamic object.

1
2
3
4
5
6
7
dynamic account = conn.Query<dynamic>(@"
                    SELECT Name, Address, Country
                    FROM Account
            WHERE Id = @Id", new { Id = Id }).FirstOrDefault();
Console.WriteLine(account.Name);
Console.WriteLine(account.Address);
Console.WriteLine(account.Country);

Nice! Probably somewhat slower than if you type out the class.

A list of objects with single child object (multimap)

Imagine we want the Shop data with the Accounts as well. It is a legacy database, so the Shop’s Id is named ShopId instead of Id. This can be overcome with the ‘splitOn’ option.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
public class Account {
  public int? Id {get;set;}
  public string Name {get;set;}
  public string Address {get;set;}
  public string Country {get;set;}
  public int ShopId {get; set;}
  public Shop Shop {get;set;}
}
public class Shop {
  public int? ShopId {get;set;}
  public string Name {get;set;}
  public string Url {get;set;}
}
 
var resultList = conn.Query<Account, Shop, Account>(@"
                    SELECT a.Name, a.Address, a.Country, a.ShopId
                            s.ShopId, s.Name, s.Url
                    FROM Account a
                    INNER JOIN Shop s ON s.ShopId = a.ShopId                   
                    ", (a, s) => {
                         a.Shop = s;
                         return a;
                     },
                     splitOn: "ShopId"
                     ).AsQueryable();

A parent object with its child objects

And the other way around: find the shop with all its accounts. It’s a little more complicated, as each row is given as (Shop s, Account a), but Shop s is a new object every time. So we have to remember one shop to add all accounts to.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public class Shop {
  public int? Id {get;set;}
  public string Name {get;set;}
  public string Url {get;set;}
  public IList<Account> Accounts {get;set;}
}
 
public class Account {
  public int? Id {get;set;}
  public string Name {get;set;}
  public string Address {get;set;}
  public string Country {get;set;}
  public int ShopId {get;set;}
}
 
var lookup = new Dictionary<int, Shop>()
conn.Query<Shop, Account, Shop>(@"
                    SELECT s.*, a.*
                    FROM Shop s
                    INNER JOIN Account a ON s.ShopId = a.ShopId                   
                    ", (s, a) => {
                         Shop shop;
                         if (!lookup.TryGetValue(s.Id, out shop)) {
                             lookup.Add(s.Id, shop = s);
                         }
                         if (shop.Accounts == null)
                             shop.Accounts = new List<Account>();
                         shop.Accounts.Add(a);
                         return shop;
                     },
                     ).AsQueryable();
 
var resultList = lookup.Values;

I got this dapper test ParentChildIdentityAssociations: https://code.google.com/p/dapper-dot-net/source/browse/Tests/Tests.cs#1343

Insert and update

Insert and update is not part of the default Dapper file. However, these is an extension for these functions — which usually are the most tedious to maintain, so it is more than welcome.

Mark you identifier with [KeyAttribute]

1
2
3
4
5
6
7
8
public class Account {
  [KeyAttribute]
  public int? Id {get;set;}
  public string Name {get;set;}
  public string Address {get;set;}
  public string Country {get;set;}
  public int ShopId {get; set;}
}

And then you can create a simple Persist function:

1
2
3
4
5
6
7
8
public void Persist(IDbConnection conn, Account acc) {
    if (acc.Id == null) {
        SqlMapperExtensions.Insert(conn, acc);
    }
    else {
        SqlMapperExtensions.Update(conn, acc);
    }
}
posted @   hellohello-tom  阅读(528)  评论(0编辑  收藏  举报
编辑推荐:
· 开发者必知的日志记录最佳实践
· SQL Server 2025 AI相关能力初探
· Linux系列:如何用 C#调用 C方法造成内存泄露
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
点击右上角即可分享
微信分享提示