Dapper 的
QueryMultiple方法用于执行一条 SQL 语句(通常是存储过程或含多个
SELECT的批处理),并一次性获取多个结果集,比多次调用
Query更高效、更节省数据库连接资源。
基本用法:用 QueryMultiple 获取多个结果集
调用
QueryMultiple后返回一个
SqlMapper.GridReader对象,它支持按顺序读取每个结果集,每次调用
Read<t>()</t>就消耗一个结果集。
示例:查询用户列表 + 订单总数 + 最新3个订单
string sql = @"
SELECT * FROM Users WHERE Status = @status;
SELECT COUNT(*) FROM Orders WHERE UserId IN (SELECT Id FROM Users WHERE Status = @status);
SELECT TOP 3 * FROM Orders ORDER BY CreatedTime DESC;";
<p>using var conn = new SqlConnection(connStr);
var multi = conn.QueryMultiple(sql, new { status = "Active" });</p><p>var users = multi.Read<User>().ToList(); // 第一个结果集 → User 列表
var orderCount = multi.ReadSingle<int>(); // 第二个结果集 → 单个 int 值
var recentOrders = multi.Read<Order>().ToList(); // 第三个结果集 → Order 列表
常见场景:配合存储过程使用
SQL Server 存储过程中用多个
SELECT返回不同结构的数据时,
QueryMultiple是最佳选择。 确保每个
SELECT的列名和类型与目标 .NET 类型匹配(Dapper 按列名映射) 避免在存储过程中使用
SET NOCOUNT ON—— 它会干扰 Dapper 解析结果集(除非你明确知道影响并做了适配) 如果某结果集为空,
Read<t>()</t>仍会返回空集合(如
IEnumerable<t></t>),不会报错
注意点:顺序必须严格匹配,不能跳过或乱序
GridReader是“游标式”读取,结果集按 SQL 中
SELECT出现的顺序依次消费,且不可回退、不可重复读。 调用
Read<t>()</t>一次,就向前推进一个结果集;跳过某个结果集会导致后续读取错位 不要对同一个
GridReader多次调用
Read<t>()</t>读同一结果集(第二次会返回空) 如果只想读前两个结果集,第三个不关心,也建议显式调用
multi.Read<object>()</object>或
multi.Skip()(Dapper v2+ 支持)来“跳过”,避免潜在异常
进阶技巧:泛型 ReadSingle / ReadFirstOrDefault / Skip
除了
Read<t>()</t>,
GridReader还提供常用快捷方法:
ReadSingle<t>()</t>:读取单值结果(如
SELECT COUNT(*))
ReadFirstOrDefault<t>()</t>:读第一个对象,无数据时返回
default(T)
Skip()(Dapper ≥ 2.0):跳过当前结果集,适合忽略中间某个结果
IsConsumed属性可检查是否所有结果集已被读完
基本上就这些。QueryMultiple 不复杂但容易忽略顺序和生命周期管理,用对了能显著简化多结果集场景的代码。
