Dapper如何自定义类型映射 Dapper Custom Type Handlers教程

Dapper自定义类型映射核心是实现ITypeHandler或继承TypeHandler并全局注册;需重写SetValue和Parse方法,推荐用TypeHandler保障类型安全,注册须在启动早期且唯一,Dapper自动匹配无需额外标注。

用Dapper做自定义类型映射,核心就一条路:实现 ITypeHandler 或继承更方便的 TypeHandler,再注册到全局处理器缓存里。不复杂但容易忽略细节。

写一个TypeHandler类

必须实现两个方法:把C#值塞进数据库参数(SetValue),以及把数据库返回值转回C#对象(Parse)。推荐继承泛型抽象类 TypeHandler,它自带类型安全,避免运行时类型转换错误。

  • System.Text.Json 处理 JSON 字段示例:

public class JsonTypeHandler : SqlMapper.TypeHandler
{
  private readonly JsonSerializerOptions _options = new() { PropertyNameCaseInsensitive = true };

  public override void SetValue(IDbDataParameter parameter, T value)
  {
    parameter.DbType = DbType.String;
    parameter.Value = JsonSerializer.Serialize(value, _options) ?? string.Empty;
  }

  public override T Parse(object value)
  {
    if (value == null || value is DBNull) return default;
    return JsonSerializer.Deserialize(value.ToString(), _options) ?? default;
  }
}

注册处理器

注册必须在应用启动早期完成,比如 Program.cs 的最开头,或 DI 容器初始化阶段。重复注册不会报错,但建议只注册一次。

  • 全局注册(对所有 Product 类型生效):
    SqlMapper.AddTypeHandler(new JsonTypeHandler());
  • 检查是否注册成功:
    bool has = SqlMapper.HasTypeHandler(typeof(Product)); // true
  • 支持可空类型自动适配 —— 注册 JsonTypeHandler 后,Product? 也能用

实际使用时无需额外标注

Dapper 会自动匹配已注册的处理器。只要实体属性类型和注册的泛型类型一致,插入、查询都透明生效。

  • 例如实体中有 public Product Details { get; set; },数据库对应字段是 NVARCHAR(MAX),Dapper 就会调用你写的 JsonTypeHandler
  • 不需要加特性(如 [SqlMapper.TypeHandler]),也不用手动指定映射规则
  • 若同时存在多个同类型处理器,后注册的会覆盖前面的

常见类型适配场景

除了 JSON,以下类型也常需自定义处理:

  • 枚举存字符串:数据库存 "Active",不是 1 —— 写 TypeHandlerParse 里用 Enum.Parse(value.ToString())
  • DateTime 格式化存储:字段是 VARCHAR 存 "2025-12-10 18:00" —— SetValue 转字符串,ParseDateTime.TryParseExact
  • PostgreSQL 的 JSONB:只需在 SetValue 中设 parameter.DbType = DbType.Object,并确保驱动支持

基本上就这些。关键不在代码多寡,而在注册时机和类型匹配是否准确。