You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用Dapper为自定义Double包装结构体创建类型处理器遇注册失效问题

解决Dapper中自定义结构体MyDouble在TVP保存时的类型不支持问题

看起来你遇到的核心问题是Dapper的自定义TypeHandler默认不会自动应用到Table-Valued Parameter(TVP,即你用AddTable传入的表参数)的字段映射上,再加上你在Save方法里调用了SqlMapper.ResetTypeHandlers(),反而清除了刚注册的处理器,导致类型映射完全失效。下面给你一步步的解决方案:

1. 先修正TypeHandler的注册时机

首先删掉Save方法里的SqlMapper.ResetTypeHandlers(),这行代码会清除所有已注册的类型处理器(包括你刚加的MyDoubleTypeHandler),完全没必要每次调用Save都重置。

正确的做法是在应用启动时一次性注册TypeHandler,比如在ASP.NET Core 2.1的Startup.cs的ConfigureServices方法里:

public void ConfigureServices(IServiceCollection services)
{
    // 注册自定义类型处理器,只需要执行一次
    SqlMapper.AddTypeHandler(new MyDoubleTypeHandler());
    // 同时告诉Dapper,MyDouble对应的数据库类型是Double
    SqlMapper.AddTypeMap(typeof(MyDouble), DbType.Double);
    
    // 其他服务注册...
}

2. 适配TVP的自定义类型处理

Dapper.ParameterExtensions的AddTable方法在构建DataTable时,并不会主动使用你注册的TypeHandler来转换自定义类型。所以我们需要手动构建符合要求的DataTable,而不是依赖AddTable:

修改你的Save方法如下:

public async Task<bool> Save(List<MyObject> data) 
{
    var parameters = new DynamicParameters();
    
    // 1. 手动构建对应数据库TVP的DataTable
    var dataTable = new DataTable();
    // 这里的列名和类型要和数据库里的TVP(dbo.MyObject)完全匹配
    dataTable.Columns.Add("Prop1", typeof(double)); 

    // 2. 将MyDouble转换为double后加入DataTable
    foreach (var item in data)
    {
        // 利用你定义的显式转换,把MyDouble转成double
        dataTable.Rows.Add((double)item.Prop1);
    }

    // 3. 添加表值参数,注意指定TypeName为数据库中TVP的全名
    parameters.Add("@Data", dataTable, DbType.Object, ParameterDirection.Input);
    // 获取底层SqlParameter,设置TypeName(必须和数据库的TVP名称一致)
    var sqlParam = parameters.Get<SqlParameter>("@Data");
    sqlParam.TypeName = "dbo.MyObject";

    using (var connection = new SqlConnection(connectionString)) 
    {
        await connection.OpenAsync();
        // ExecuteAsync返回受影响的行数,根据业务需求判断返回值
        int affectedRows = await connection.ExecuteAsync("name-of-sp", parameters, commandType: CommandType.StoredProcedure);
        return affectedRows > 0;
    }
}

3. 额外检查点

  • 确认数据库中的TVP(dbo.MyObject)的Prop1列类型是float(对应.NET的double/DbType.Double),类型不匹配也会导致报错。
  • 验证你的MyDouble结构体的显式转换是否正常:(double)myDoubleInstance能正确返回内部的value值。

内容的提问来源于stack exchange,提问作者user1820686

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.11 09:12:44