Dapper一对一映射需写对SQL、选准splitOn列、写好组装委托;SQL须用别名避免同名列冲突,splitOn填关联对象首列名(如"UserId"),委托中手动赋值并处理null。
用Dapper做一对一映射,核心就三点:写对SQL、选对
列、写好组装委托。它不自动推断关系,但控制清晰、性能高,适合明确知道数据结构的场景。
SQL要包含两个表的字段,并注意列名不冲突
必须把主表和关联表的所有需要字段都查出来,推荐用表别名避免同名列覆盖(比如两个表都有
):
示例SQL:
这样能确保Dapper按列顺序准确切分数据段。如果不用别名,且两表都有
,Dapper可能误判分割点。
splitOn参数指定关联对象的起始列
不是写外键名,而是写“第二个对象字段在结果集里第一次出现的列名”。上例中
对象从
列开始,所以设为
:
如果SQL里写的是
且没别名,那
填
(但容易和
混淆)
如果用了
,就填
——更安全、更明确
大小写敏感,必须和SQL中AS后的名称完全一致
用委托函数把子对象挂到父对象属性上
Query方法返回的是主对象类型,嵌套对象靠你自己在委托里赋值:
关键细节:
和
都是Dapper根据
自动创建的实例
时
可能是
,建议在赋值前判断:
或保留null并用空合并操作符访问:
返回类型写
,表示最终列表是
实体类得有可写属性,且类型匹配
比如
类里要有
,不能是只读属性或私有字段。Dapper只映射public set属性,且不支持自动构造嵌套对象(不会调用
)。
如果
属性类型和SQL中映射的
不一致(比如写成了
),运行时会抛异常,不是静默失败。
基本上就这些。不复杂但容易忽略别名和splitOn的对应关系。
splitOnIdSELECT p.Id AS PostId, p.Content, u.Id AS UserId, u.Name AS UserName
FROM Posts p
LEFT JOIN Users u ON u.Id = p.OwnerIdIdsplitOnUserUserId"UserId"u.IdsplitOn"Id"p.Idu.Id AS UserId"UserId"var posts = connection.Query(sql,
(post, user) => {
post.Owner = user;
return post;
},
splitOn: "UserId"
); postusersplitOnLEFT JOINusernullpost.Owner = user ?? new User();post.Owner?.NamePostIEnumerablePostpublic User Owner { get; set; }new User()OwnerUserobject