Dapper 能显著提升数据库执行效率,但需手动管理连接、SQL 和映射;必须显式打开连接、严格匹配参数名、事务中所有操作均需传 transaction 参数,批量操作应使用数据库原生方案而非循环执行。

直接说结论:Dapper 能显著提升数据库执行效率,但前提是别把它当“全自动ORM”用——它不管理连接、不生成 SQL、不跟踪对象,所有性能红利都来自你手动写的那条 SQL 和你控制的那一次映射。写错参数名、漏掉 connection.Open()、在事务里忘传 transaction 参数,它不会报错提示,只会静默失败或抛出底层异常。
Connection 必须显式打开,否则 Query/Execute 直接炸
Dapper 所有扩展方法(Query<t></t>、Execute、QueryMultiple)都只扩展 IDbConnection,不接管生命周期。常见错误:
- 用
new SqlConnection(...)后没调.Open()就直接Query<user>()</user>→ 报InvalidOperationException: Connection is not open - 写
using var conn = new SqlConnection(...),但把Query写在using块外 → 连接已释放,运行时报ObjectDisposedException - 从 EF Core 的
DbContext.Database.GetDbConnection()拿连接,但没检查conn.State == ConnectionState.Open→ 可能已关闭,尤其跨作用域后
正确做法:始终在 using 块内完成全部操作,并显式 .Open()(即使连接字符串含 Pooling=true,首次仍需打开):
using var conn = new SqlConnection(connStr);
conn.Open(); // 别省
var users = conn.Query<user>("SELECT * FROM Users WHERE Id = @id", new { id = 123 });
</user>
参数必须严格匹配,大小写敏感且不能拼错
Dapper 不做参数校验,SQL 里写 @Name,匿名对象里却传 new { name = "x" },就会报 InvalidOperationException: The parameterized query expects parameter '@Name'。这不是 SQL Server 的错,是 Dapper 绑定失败。
- SQL 中参数名(如
@UserId)和匿名对象属性名必须完全一致,包括大小写 - 传
null值时,Dapper 自动转为DBNull.Value,无需手动处理 - 避免用
IDictionary<string object></string>传参——键名大小写易错,且无编译期检查 - 哪怕值是固定字符串(如
"Active"),也必须参数化:WHERE Status = @status,而不是"WHERE Status = 'Active'"
事务必须显式传参,Query 和 Execute 都不自动感知
SqlTransaction 对象创建后,Dapper 不会自动绑定到后续所有调用。如果你只对 Execute 传了 transaction: tx,但 Query 没传,那这条查询就在事务外执行,可能读到脏数据或破坏一致性。
- 所有 Dapper 调用(包括
Query)参与事务,必须显式加transaction: tx参数 - 别依赖
conn.BeginTransaction()后的“隐式上下文”,Dapper 完全不维护这个 - 批量操作 + 校验场景(如导入后查总数)必须统一传同一个
tx,否则事务失效
示例:
using var tx = conn.BeginTransaction();
try
{
conn.Execute("INSERT INTO Logs (...) VALUES (...)", logs, transaction: tx);
var count = conn.QuerySingle<int>("SELECT COUNT(*) FROM Logs", transaction: tx);
if (count != logs.Count) throw new InvalidOperationException("Import mismatch");
tx.Commit();
}
catch
{
tx.Rollback();
throw;
}
</int>
批量更新不能靠循环 Execute,得推给数据库做
Execute 本质就是执行一条 SQL 命令。用 foreach 循环调 Execute("UPDATE ... WHERE Id = @id", item),等于发 N 次网络请求,性能极差,且事务开销大。
- SQL Server 推荐用表值参数(TVP):建好
TYPE,C# 构造DataTable,用DynamicParameters传入,SQL 写成UPDATE t SET ... FROM t INNER JOIN @updates u ON ... - MySQL/PostgreSQL 用
INSERT ... ON DUPLICATE KEY UPDATE或UPSERT+VALUES ROW(), ROW()...语法 - 别拼接多条语句用分号隔开(如
"UPDATE...; UPDATE..."),多数驱动不支持,会报Incorrect syntax near ';'
真正影响效率的从来不是 Dapper 本身,而是你让数据库干了多少活、网络往返了多少次。这点最容易被忽略——以为装了 Dapper 就万事大吉,结果慢还是慢。











