Dapper怎么处理只写属性 Dapper Write-Only Property映射

来源:这里教程网 时间:2026-02-21 17:35:08 作者:

Dapper 默认不支持只写属性(即只有

set
、没有
get
的属性)的映射,因为它在反序列化时需要通过属性的
set
方法赋值,但同时也依赖反射获取属性元数据——而标准 .NET 反射对纯只写属性的支持有限,尤其在旧版 Dapper(如 2.0 之前)中会直接跳过这类属性,导致映射失败或静默忽略。

只写属性为什么通常映射不了

Dapper 在执行查询后,使用

PropertyInfo.SetValue()
给目标对象赋值,这一步本身能接受只写属性。但问题出在前期:它会先调用
PropertyInfo.CanRead
判断是否为可读属性,默认过滤掉
CanRead == false
的属性。所以即使你写了
set
,只要没
get
,Dapper 就不会把它纳入映射字段列表。

绕过限制的实用方法

改用带 get 的属性:最简单可靠的方式。哪怕
get
返回默认值或 throw,只要存在且可访问,Dapper 就能识别。例如:
public string Name { get => throw new NotSupportedException(); set { _name = value; } }
用 SQL 别名 + 匿名对象中转:先查到匿名类型或
Dictionary<string object></string>
,再手动给只写属性赋值。适合少量字段或初始化场景。
自定义
ITypeMap
实现
:重写
GetMember(string columnName)
,主动返回只写属性的
PropertyInfo
,并确保
CanRead
不作为硬性过滤条件。需继承
SqlMapper.ITypeMap
并注册:
SqlMapper.SetTypeMap(typeof(MyDto), new MyCustomTypeMap());
避免只写属性用于查询映射:设计上建议 DTO 或实体只暴露需要读取的属性;只写逻辑(如密码哈希、审计时间戳)更适合放在插入/更新时由业务层控制,而非依赖查询结果自动填充。

插入/更新时的只写属性处理

对于

Insert
Update
操作,Dapper 仅用
PropertyInfo.GetValue()
提取参数值,这时只写属性因无法
GetValue
会报错或传 null。所以只写属性不应出现在 Insert/Update 的参数对象中。正确做法是:

用专门的 InputModel(全读写)接收前端或业务输入 在服务层转换时,把只写逻辑(如生成创建时间、加密字段)显式赋值 保持数据库操作对象干净、可映射

基本上就这些。Dapper 的设计哲学偏向“约定优于配置”,对非常规结构支持有限,只写属性属于边缘场景,优先调整模型设计比硬扛映射更可持续。

相关推荐