.NET Core中如何将存储过程返回结果映射到含嵌套集合的实体对象
实现方案指导
方案选择建议
你仅需要获取第一条地址的场景下,两种返回方式都可实现,优先推荐多结果集方案:
- 无数据冗余:单结果集需要关联两张表查询,员工基础信息会存在重复冗余,多结果集分别返回对应数据更轻量化
- 扩展性更强:后续如果需要返回该员工的全部地址,仅需调整存储过程去掉地址查询的TOP 1限制即可,上层代码改动极小
推荐实现:多结果集方案
1. 存储过程编写
CREATE PROCEDURE GetEmployeeDetails @employeeid INT AS BEGIN SET NOCOUNT ON; -- 第一个结果集:返回员工基础信息 SELECT Name, 【其余Employee类对应字段】 FROM Employee WHERE Id = @employeeid; -- 第二个结果集:返回第一条关联地址 SELECT TOP 1 【Address类对应所有字段】 FROM Address WHERE EmployeeId = @employeeid; END
2. C# 映射代码调整
你原代码使用的ExecuteQueryFirstOrDefaultAsync仅能读取单结果集,无法获取地址数据,需要改用Dapper的QueryMultipleAsync读取多结果集:
public async Task<Employee> GetEmployeeDetails(int employeeid) { var parameters = new DynamicParameters(); parameters.Add("@employeeid", employeeid); using (IDbConnection con = await GetConnectionAsync(ConfigHandler.GetConnectionString(Constants.DefaultConnectionString))) { using var multiResult = await con.QueryMultipleAsync( "GetEmployeeDetails", parameters, commandType: CommandType.StoredProcedure ); // 读取第一个结果集的员工信息 var emp = await multiResult.ReadFirstOrDefaultAsync<Employee>(); if (emp != null) { emp.Addr = new List<Address>(); // 读取第二个结果集的地址信息 var firstAddr = await multiResult.ReadFirstOrDefaultAsync<Address>(); if (firstAddr != null) { emp.Addr.Add(firstAddr); } } // 无需手动调用con.Close(),using块会自动释放连接资源 return emp; } }
可选实现:单结果集方案
如果偏好单结果集实现,可以使用Dapper的多映射功能完成类匹配:
1. 存储过程编写
CREATE PROCEDURE GetEmployeeDetails @employeeid INT AS BEGIN SET NOCOUNT ON; SELECT TOP 1 e.Name, -- 其余Employee对应字段 a.Id, a.Street, -- 其余Address对应字段 FROM Employee e LEFT JOIN Address a ON e.Id = a.EmployeeId WHERE e.Id = @employeeid; END
2. C# 映射代码
public async Task<Employee> GetEmployeeDetails(int employeeid) { var parameters = new DynamicParameters(); parameters.Add("@employeeid", employeeid); using (IDbConnection con = await GetConnectionAsync(ConfigHandler.GetConnectionString(Constants.DefaultConnectionString))) { var empResult = await con.QueryAsync<Employee, Address, Employee>( "GetEmployeeDetails", (emp, addr) => { emp.Addr = new List<Address>(); if(addr != null) emp.Addr.Add(addr); return emp; }, parameters, splitOn: "Id", // 此处填Address表的主键字段名,Dapper会按该字段拆分两类的映射 commandType: CommandType.StoredProcedure ); return empResult.FirstOrDefault(); } }
注意事项
- 存储过程返回的字段名需要和C#类的属性名一一对应,若字段名不匹配可以在SQL中使用
AS别名对齐 - 确认地址表的关联外键为
EmployeeId,若实际名称不同需要同步调整SQL语句中的关联条件
内容的提问来源于stack exchange,提问作者Ang_Dev
相关产品推荐
相关产品推荐

