带有 DynamicParameters 的 Dapper 自定义 TypeHandler

Jen*_*ens 5 c# dapper

我在我的 Web-API 项目(.NET Core 3.1)中使用 Dapper,并尝试将记录插入数据库(SQL Server 2017)+返回创建的 id。

我有这个对象...

public class CreateDetailGroupDto
{
    public string Name { get; set; }

    public List<CreateDetailDto> Details { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

负责的方法如下所示:

public async Task<int> Create(CreateDetailGroupDto detailGroup)
{
    using var cnn = Connection;

    var parameter = new DynamicParameters();
    parameter.Add("detailGroup", detailGroup);
    parameter.Add("id", dbType: DbType.Int32, direction: ParameterDirection.Output);

    await cnn.ExecuteAsync("spDetailGroup_Insert", param: parameter, commandType: CommandType.StoredProcedure);

    int id = parameter.Get<int>("id");

    return id;
}
Run Code Online (Sandbox Code Playgroud)

我正在执行存储过程,spDetailGroup_Insert该过程需要 JSON 格式的上述对象NVARCHAR(MAX),并​​将 id 作为输出参数。

我编写了一个处理程序,该处理程序应该在用作参数时序列化对象(我认为):

public class TypeHandler<T> : SqlMapper.TypeHandler<T>
{
    public override T Parse(object value)
    {
        return JsonConvert.DeserializeObject<T>(value.ToString());
    }

    public override void SetValue(IDbDataParameter parameter, T value)
    {
        parameter.Value = JsonConvert.SerializeObject(value);
    }
}
Run Code Online (Sandbox Code Playgroud)

在类的构造函数中,我使用SqlMapper.AddTypeHandler(new TypeHandler<CreateDetailGroupDto>());为 DTO 添加 TypeHandler。但是...当Create方法运行时,即使SetValueHandler 中的方法成功执行,对象也不会转换为 JSON。

我知道这是非常具体的,但有人知道这里可能发生什么吗?

编辑:
看来在 SetValue 方法中添加一行来指定 DbType 似乎可以解决该问题:

public override void SetValue(IDbDataParameter parameter, T value)
{
    parameter.DbType = DbType.String;
    parameter.Value = JsonConvert.SerializeObject(value);
}
Run Code Online (Sandbox Code Playgroud)

小智 4

基于DynamicParameters 的实现, DbType 默认为 null,所以我猜您在 Add-Method 中缺少 DbType 规范:

public async Task<int> Create(CreateDetailGroupDto detailGroup)
{
    using var cnn = Connection;

    var parameter = new DynamicParameters();
    parameter.Add("detailGroup", detailGroup, DbType.String);
    parameter.Add("id", dbType: DbType.Int32, direction: ParameterDirection.Output);

    await cnn.ExecuteAsync("spDetailGroup_Insert", param: parameter, commandType: CommandType.StoredProcedure);

    int id = parameter.Get<int>("id");

    return id;
}
Run Code Online (Sandbox Code Playgroud)

根据本文档,nvarchar(max) 的正确映射应该是 DbType.String 。