Dapper如何处理数据库返回的DBNull Dapper DBNull.Value转换方法

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

Dapper 默认会将数据库中的

DBNull.Value
映射为对应 .NET 类型的默认值(如
null
0
false
),但这种隐式转换容易掩盖空值问题,尤其在可空类型(
int?
DateTime?
)或自定义逻辑中需要显式区分
NULL
和默认值时。关键不是“怎么转”,而是“怎么安全地识别和处理”。

理解 Dapper 对 DBNull 的默认行为

Dapper 在填充实体时,对字段值做如下判断:

如果数据库列值是
DBNull.Value
,且目标属性是引用类型(如
string
MyClass
),则赋值为
null
如果是值类型(如
int
DateTime
),且未声明为可空(
int?
),Dapper 会尝试调用该类型的默认构造(如
default(int) → 0
),**不抛异常**
如果是可空值类型(
int?
DateTime?
),
DBNull.Value
会被正确映射为
null

手动检查 DBNull 的几种实用方式

当需要在映射前/后精确控制空值逻辑(比如记录日志、触发业务规则、统一转成特定默认值),推荐以下方法:

使用查询时的 SQL COALESCE 或 CASE:在数据库层处理,例如
SELECT COALESCE(Price, 0) AS Price FROM Product
,让 Dapper 始终收到非 null 值
用 Query 配合 Func 自定义映射:在回调中手动判断
reader.IsDBNull(index)
,再决定赋值逻辑
在实体属性的 setter 中拦截:配合私有 backing field,setter 内检查传入值是否为
DBNull.Value
(需搭配
[SqlMapper.TypeHandler]
或自定义映射器)

推荐:用 TypeHandler 统一处理 DBNull(适合全局策略)

若项目中大量存在某类字段(如所有

decimal
字段都应转为
0m
而非
null
),可注册自定义
TypeHandler<decimal></decimal>

SqlMapper.AddTypeHandler(new DecimalTypeHandler());
// 实现示例:
public class DecimalTypeHandler : SqlMapper.TypeHandler<decimal>
{
    public override void SetValue(IDbDataParameter parameter, decimal value) => 
        parameter.Value = value;
    public override decimal Parse(object value) => 
        value == DBNull.Value ? 0m : Convert.ToDecimal(value);
}

这样所有

decimal
列都会按你的规则解析,无需改实体或 SQL。

避免踩坑的注意事项

几个常见误区要避开:

不要在实体中把值类型写成非可空却期望它接收
NULL
—— Dapper 不会报错,但语义丢失(比如
int Age
收到
NULL
变成
0
,无法区分“年龄未知”和“年龄为 0”)
别依赖
== null
判断数据库 NULL —— 对非可空类型永远为 false;应优先用可空类型 + 显式 null 检查
使用
QuerySingleOrDefault<t>()</t>
时注意:若查询无结果返回
default(T)
,这和
DBNull
是两回事,别混淆

基本上就这些。核心是:用可空类型承接可能为 NULL 的列,必要时用 TypeHandler 或 SQL 层统一兜底。不复杂但容易忽略细节。

相关推荐

热文推荐