Dapper 的 splitOn 参数支持多个列名,用英文逗号分隔即可,比如
splitOn: "OrderId,ProductId"。这不是“多次 splitOn”,而是一次指定多个分割点,用于多级嵌套映射(如一查三:Order → Customer → Address)或一对多场景中区分不同实体的起始字段。
什么时候需要多个 splitOn
当 SQL 查询返回三张及以上表的扁平化结果(例如 JOIN 了 Order、Customer、Address),且各实体主键列名不统一(比如不是都叫
Id)时,Dapper 需要明确知道每个新对象从哪一列开始。这时就靠多个列名告诉它:“这里切一刀,开始映射下一个对象”。 第一个对象(如
Order)取
splitOn之前的所有列 第二个对象(如
Customer)从第一个
splitOn列(如
CustomerId)开始,到下一个
splitOn列前为止 第三个对象(如
Address)从第二个
splitOn列(如
AddressId)开始,取剩余所有列
正确写法示例
假设查询返回:
OrderId, OrderNo, CustomerId, CustomerName, AddressId, Street
你想映射为
Order → Customer → Address:
var result = conn.Query<Order, Customer, Address, Order>(
sql,
(order, customer, address) =>
{
order.Customer = customer;
customer.Address = address;
return order;
},
splitOn: "CustomerId,AddressId" // 关键:两个分割点
);
常见误区提醒
不要重复写多个 splitOn 参数:Dapper 只接受一个splitOn:参数,值是字符串,不是数组或多个键值对 顺序必须和泛型参数顺序一致:泛型是
<t1></t1>,那
splitOn中第一个列对应
T2起始,第二个列对应
T3起始 列名必须真实存在于 SELECT 结果中,且大小写需匹配(取决于数据库配置,建议显式别名) 如果某关联记录为空(如 Customer 为 NULL),Dapper 仍能正常映射,但你要在委托函数里判空,避免 NullReferenceException
一对多场景下不直接靠 splitOn 解决
splitOn 本身只处理“一对一”或“线性嵌套”,不能自动展开集合(如一个 Order 对应多个 OrderItem)。要做一对多,得配合
Dictionary<int order></int>手动归组,或者改用
QueryMultiple分步查——这时候 splitOn 就只用一次,甚至不用。
基本上就这些。
