首页
学习
活动
专区
圈层
工具
发布
社区首页 >专栏 >为什么越来越多 C# 开发者转投 Dapper?从环境搭建与 CRUD 实战说起

为什么越来越多 C# 开发者转投 Dapper?从环境搭建与 CRUD 实战说起

作者头像
云中小生
发布2026-07-13 17:43:12
发布2026-07-13 17:43:12
280
举报

刚入行那会儿,我跟很多人一样 EF Core 一把梭。直到有一次做个报表接口,数据量不大但联了七八张表,EF 生成的 SQL 跑了 6 秒。换成 Dapper 手写 SQL,同样的查询 0.4 秒。从那之后,我手里所有对性能有要求的项目,数据访问层全是 Dapper。

这篇文章从零开始,把 Dapper 同步写法的核心讲清楚,顺带聊聊实际项目里真正会出问题的地方。


Dapper 是什么

一句话:你把 SQL 丢给它,它把结果映射成你的实体对象。

没有状态跟踪,没有变更检测,没有延迟加载——所以它快。Stack Overflow 自己就在生产环境跑它,日请求量你想想看。


安装

Dapper 本体:

代码语言:javascript
复制
dotnet add package Dapper

然后按数据库装驱动:

  • SQL Server:Microsoft.Data.SqlClient
  • MySQL / MariaDB:MySqlConnector
  • PostgreSQL:Npgsql
  • SQLite:Microsoft.Data.Sqlite
  • Oracle:Oracle.ManagedDataAccess.Core

连接管理——这比你想象的严重得多

先说个真实的事。

去年我们一个订单服务,某天下午突然开始大面积超时,日志里全是 Timeout expired。查了半天发现新来的同事在一个定时任务里写了 new SqlConnection(connStr),没有 using,也没调 Close()。这个任务每 30 秒跑一次,每次泄漏一个连接。跑了半天,连接池 100 个连接全部占满——剩下所有接口都在排队等连接。

所以这句请记住:Dapper 不会帮你管理连接,你必须手动 using

标准写法就下面这样,别纠结,照抄:

代码语言:javascript
复制
string connectionString = "Server=.;Database=TestDB;Integrated Security=true;";
using (IDbConnection db = new SqlConnection(connectionString))
{
    db.Open();
    // 你的操作
}

另外,永远不要在类里搞一个 static SqlConnection 当全局单例用。连接池本身就是干这个的,你不需要自己缓存连接。


实体类

下面两个类后面全系列都在用:

代码语言:javascript
复制
public class User
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Email { get; set; }
    public int Age { get; set; }
    public Address Address { get; set; }
}

public class Address
{
    public int UserId { get; set; }
    public string City { get; set; }
    public string Street { get; set; }
}

User 里有个 Address 导航属性,联表映射的时候用来装结果。


查询

查多条用 Query<T>,查单条用 QueryFirstOrDefault<T>。区别很简单:

代码语言:javascript
复制
// 查列表
var users = db.Query<User>("SELECT * FROM Users WHERE Age > @Age", new { Age =  }).ToList();

// 查单条——查不到返回 null,不会抛异常,日常最常用
var user = db.QueryFirstOrDefault<User>("SELECT * FROM Users WHERE Id = @Id", new { Id =  });

Dapper 的传参靠匿名对象,new { Age = 18 } 自动变成 @Age 参数。你别手拼 SQL 字符串,拼了就是注入漏洞。

QueryFirstQueryFirstOrDefaultQuerySingleOrDefault 三个的区别:第一个查不到抛异常,第二个查不到返回 null,第三个查到多条抛异常。日常用第二个最多;按主键查的时候可以用 QuerySingleOrDefault,万一主键重复多返回一行能立刻报错,比悄悄用第一条强。


增删改

统一用 Execute(),返回受影响行数。插入更新删除全一个写法:

代码语言:javascript
复制
db.Execute("INSERT INTO Users (Name, Email, Age) VALUES (@Name, @Email, @Age)", 
    new { Name = "Bob", Email = "bob@test.com", Age =  });

db.Execute("UPDATE Users SET Name = @Name WHERE Id = @Id", 
    new { Name = "Robert", Id =  });

db.Execute("DELETE FROM Users WHERE Id = @Id", new { Id =  });

没什么花头,就这么用。


联表查询

联表的坑在于 splitOn 参数。它告诉 Dapper:从结果集的第几列开始,后面的字段映射给第二个实体。

代码语言:javascript
复制
string sql = @"SELECT u.Id, u.Name, a.City, a.Street 
               FROM Users u JOIN Addresses a ON u.Id = a.UserId";

var users = db.Query<User, Address, User>(sql,
    (user, addr) => { user.Address = addr; return user; },
    splitOn: "City"
).Distinct().ToList();

IdNameUserCityStreetAddresssplitOn 填的是 Address 的第一个字段名

新手容易在这里翻车:splitOn 拼错了,或者列的先后顺序跟代码里实体顺序对不上,查出来的数据就全 null。这个问题我见过不下五次——没有报错,就是字段全是空,半天才反应过来。


存储过程

多一行参数的事:

代码语言:javascript
复制
var user = db.Query<User>("GetUserById", new { Id =  },
    commandType: CommandType.StoredProcedure).FirstOrDefault();

事务

事务的核心就一条:几条 SQL 共用一个 IDbTransaction,全部成功才提交,一条失败全回滚。

代码语言:javascript
复制
using (IDbConnection db = new SqlConnection(connectionString))
{
    db.Open();
    using (var tran = db.BeginTransaction())
    {
        try
        {
            db.Execute("INSERT INTO Users(Name) VALUES (@Name)", 
                new { Name = "TestUser" }, transaction: tran);
            db.Execute("UPDATE Logs SET Status='Done' WHERE Id=@Id", 
                new { LogId =  }, transaction: tran);
            tran.Commit();
        }
        catch
        {
            tran.Rollback();
            throw;
        }
    }
}

注意:操作里必须传 transaction: tran,漏传的话那条 SQL 就不在事务里了,回滚回不来,数据就脏了。


第一章就到这。核心 API 这点东西其实不复杂,Dapper 的优势从来不是"功能多",而是"够用且快"。

下一篇讲异步写法。这是 Web API 逃不掉的话题,而且异步用不好比同步还危险——.Result 死锁的故事下章细说。


(点击关注,修炼不迷路👇

▌转载请注明出处,渡人渡己

🌟 感谢道友结缘! 若本文助您突破修为瓶颈,不妨【打赏灵丹】或【转发功德】,让更多道友共参.NET天道玄机。修真之路漫漫,我们以代码为符,共绘仙途!

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2026-07-09,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 .NET修仙日记 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Dapper 是什么
  • 安装
  • 连接管理——这比你想象的严重得多
  • 实体类
  • 查询
  • 增删改
  • 联表查询
  • 存储过程
  • 事务
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档