在C#的ORM工具中,Dapper以轻量、高效的特点被广泛使用,其多结果集功能支持在一次数据库查询中返回多个结果集,避免多次发起数据库请求,适合需要同时获取多张关联表数据的场景。

Dapper多结果集的核心原理
Dapper的QueryMultiple方法用于执行返回多个结果集的SQL语句,该方法会返回一个SqlMapper.GridReader对象,通过这个对象可以依次读取每个结果集的内容,每个结果集可以映射到不同的实体类型。
使用前的准备工作
首先需要安装Dapper的NuGet包,在项目中通过包管理器控制台执行以下命令:
Install-Package Dapper
假设我们有两张关联的数据库表,结构如下:
| 用户表(Users) | 订单表(Orders) |
|---|---|
| Id int 主键 | Id int 主键 |
| UserName nvarchar(50) | UserId int 外键 |
| Age int | OrderNo nvarchar(50) |
| CreateTime datetime | TotalAmount decimal |
对应的C#实体类定义如下:
public class User
{
public int Id { get; set; }
public string UserName { get; set; }
public int Age { get; set; }
public DateTime CreateTime { get; set; }
}
public class Order
{
public int Id { get; set; }
public int UserId { get; set; }
public string OrderNo { get; set; }
public decimal TotalAmount { get; set; }
}
多结果集功能完整示例
1. 基础多结果集查询示例
下面的示例演示了一次查询同时获取所有用户和所有订单的两个结果集:
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using Dapper;
class Program
{
static void Main()
{
// 数据库连接字符串,实际使用时替换为自己的数据库地址
string connectionString = "Server=127.0.0.1;Database=TestDB;User Id=sa;Password=123456;";
using (var connection = new SqlConnection(connectionString))
{
// 打开数据库连接
connection.Open();
// 执行返回多结果集的SQL语句,这里用分号分隔两个查询
string sql = @"
SELECT Id, UserName, Age, CreateTime FROM Users;
SELECT Id, UserId, OrderNo, TotalAmount FROM Orders;
";
// 调用QueryMultiple方法获取GridReader对象
using (var gridReader = connection.QueryMultiple(sql))
{
// 读取第一个结果集,映射到User集合
IEnumerable<User> userList = gridReader.Read<User>();
// 读取第二个结果集,映射到Order集合
IEnumerable<Order> orderList = gridReader.Read<Order>();
// 输出用户信息
Console.WriteLine("用户列表:");
foreach (var user in userList)
{
Console.WriteLine($"Id:{user.Id}, 用户名:{user.UserName}, 年龄:{user.Age}");
}
// 输出订单信息
Console.WriteLine("n订单列表:");
foreach (var order in orderList)
{
Console.WriteLine($"Id:{order.Id}, 用户Id:{order.UserId}, 订单号:{order.OrderNo}, 总金额:{order.TotalAmount}");
}
}
}
}
}
2. 带参数的多结果集查询示例
如果需要根据条件查询多结果集,可以在SQL中添加参数,示例如下:
using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using Dapper;
class Program
{
static void Main()
{
string connectionString = "Server=127.0.0.1;Database=TestDB;User Id=sa;Password=123456;";
int targetUserId = 1;
using (var connection = new SqlConnection(connectionString))
{
connection.Open();
// 带参数的多结果集查询SQL,查询指定用户的信息和其对应的订单
string sql = @"
SELECT Id, UserName, Age, CreateTime FROM Users WHERE Id = @UserId;
SELECT Id, UserId, OrderNo, TotalAmount FROM Orders WHERE UserId = @UserId;
";
// 传入参数执行查询
using (var gridReader = connection.QueryMultiple(sql, new { UserId = targetUserId }))
{
// 读取第一个结果集,这里只查询单个用户,用ReadFirstOrDefault
User targetUser = gridReader.ReadFirstOrDefault<User>();
// 读取第二个结果集,查询该用户的所有订单
IEnumerable<Order> userOrders = gridReader.Read<Order>();
if (targetUser != null)
{
Console.WriteLine($"查询到的用户:{targetUser.UserName}");
Console.WriteLine("该用户的订单:");
foreach (var order in userOrders)
{
Console.WriteLine($"订单号:{order.OrderNo}, 总金额:{order.TotalAmount}");
}
}
else
{
Console.WriteLine("未找到指定用户");
}
}
}
}
}
使用注意事项
- 调用
QueryMultiple后,必须按照SQL中结果集返回的顺序依次调用Read方法,顺序错乱会导致读取到错误的数据或者抛出异常。 GridReader对象使用完毕后需要及时释放,建议使用using语句包裹,避免数据库连接占用。- 如果某个结果集可能为空,读取时可以使用
ReadOrDefault或者ReadFirstOrDefault等方法,避免空引用异常。 - 多结果集的SQL语句需要数据库支持,比如SQL Server、MySQL等主流数据库都支持用分号分隔多个查询语句返回多结果集。
多结果集功能适合数据关联性强的查询场景,不要滥用,避免单次查询返回过多冗余数据影响性能。