Dapper需通过NuGet安装Dapper包并引用using Dapper;,仅扩展IDbConnection,须手动管理连接状态;参数化查询防SQL注入;多结果集用QueryMultiple()顺序读取;查单条优先用QueryFirstOrDefault()提升性能。

安装 Dapper 并确认基础引用是否到位
Dapper 不是 .NET 内置库,必须手动引入。最常用方式是通过 NuGet 安装 Pomelo.EntityFrameworkCore.MySql?错——那是 EF 的 MySQL 驱动。Dapper 本身只有一个核心包:Dapper。安装命令是:
dotnet add package Dapper
安装后,确保代码中引用了命名空间:
using Dapper;
注意:Dapper 仅扩展 IDbConnection,不提供连接管理或迁移能力。你仍需自己创建、打开、关闭 SqlConnection(或 MySqlConnection 等),否则会遇到 InvalidOperationException: Connection is not open。
常见踩坑点:
- 忘记调用
connection.Open(),直接执行Query→ 报错() - 用
using var connection = new SqlConnection(...)却没在 using 块内执行查询 → 连接已释放 - 混用 EF Core 的
DbContext.Database.GetDbConnection()后未检查连接状态 → 可能已关闭
Query 和 Execute 的参数传递与 SQL 注入防护
Query 用于 SELECT 映射结果,Execute() 用于 INSERT/UPDATE/DELETE 等无返回值操作。二者都支持动态参数,但必须用匿名对象或 DynamicParameters,不能拼接字符串。
错误写法(SQL 注入风险):
string name = "admin'; DROP TABLE Users; --";
connection.Query<user>($"SELECT * FROM Users WHERE Name = '{name}'");</user>
正确写法(参数化,安全):
var users = connection.Query<user>("SELECT * FROM Users WHERE Name = @name", new { name = "admin" });</user>
关键点:
- SQL 中的参数名(如
@name)必须和匿名对象属性名一致,大小写敏感 - 传
null值时,Dapper 自动转为DBNull.Value,无需手动处理 - 批量插入建议用
Execute("INSERT ...", listOfObjects),Dapper 会自动展开为多行参数绑定(非拼接) - 若需输出参数、表值参数或复杂类型映射,必须改用
DynamicParameters类,而非匿名对象
多结果集处理:QueryMultiple 怎么避免“Sequence contains no elements”
当一条 SQL 返回多个结果集(如存储过程里两个 SELECT),不能用 Query,得用 QueryMultiple()。它返回 GridReader,必须按顺序读取每个结果集。
典型错误:
using var reader = connection.QueryMultiple(sql); var users = reader.Read<user>().ToList(); // ✅ 第一个结果集 var roles = reader.Read<role>().ToList(); // ✅ 第二个结果集 // 忘记调用 Read() 就直接访问 reader.Read<t>() 多次 → 报错 “Sequence contains no elements”</t></role></user>
必须注意:
-
GridReader是流式读取,每个Read只能调用一次,且顺序不能乱() - 如果某结果集为空(比如条件不匹配导致没数据),
Read返回空集合,不会抛异常;但若误判为“该结果集不存在”,而跳过调用,则后续() Read会失败 - 不支持异步多结果集(
QueryMultipleAsync存在,但需确保连接支持 MARS,SQL Server 默认关,MySQL 不支持)
性能关键:何时该用 QueryFirstOrDefault 而不是 Query
查单条记录时,别用 Query —— 它先拉取全部结果再取第一个,浪费内存和网络带宽。应直接用 QueryFirstOrDefault。
对比:
// ❌ 拉回整个结果集,哪怕只有一行也全加载到内存
var user = connection.Query<user>("SELECT * FROM Users WHERE Id = @id", new { id = 123 }).FirstOrDefault();
<p>// ✅ 数据库只返回一行,Dapper 只映射一次
var user = connection.QueryFirstOrDefault<user>("SELECT * FROM Users WHERE Id = @id", new { id = 123 });</user></p></user>
适用场景:
- 主键查询、唯一索引查找、
TOP 1场景 - 明确知道最多返回一条,且希望失败时返回
null(引用类型)或默认值(值类型) - 搭配
QuerySingleOrDefault用在“必须有且仅有一条”逻辑上,查不到或查多条都会抛异常,适合校验性查询
容易被忽略的是:Dapper 的 QueryFirst/QuerySingle 系列方法底层不加 TOP 1,SQL 仍由你写。如果你写了 SELECT * 且没加限制,数据库照样返回全部匹配行,只是 Dapper 只取前一个或校验数量——所以 SQL 本身也建议加上 TOP 1 或 LIMIT 1(适配方言)来减少传输量。










