简体   繁体   中英

Dapper custom TypeHandler with DynamicParameters

I'm using Dapper in my Web-API project (.NET Core 3.1) and I'm trying to insert a record into a database (SQL Server 2017) + return the created id.

I have this object...

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

    public List<CreateDetailDto> Details { get; set; }
}

and the responsible method looks like this:

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;
}

I'm executing the stored procedure spDetailGroup_Insert which expects the object above in JSON format NVARCHAR(MAX) and has the id as an output paramater.

I wrote a handler which is supposed to serialize an object when used as a paramter (I thought):

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);
    }
}

In the constructor of the class i use SqlMapper.AddTypeHandler(new TypeHandler<CreateDetailGroupDto>()); to add the TypeHandler for the DTO. However... when the Create methods is run, the object is not converted to JSON, even though the SetValue method in the Handler is successfully executed.

I know this is pretty specific but does anyone have an idea what might be happening here?

Edit:
It appears that adding one line in the SetValue method to specify the DbType, seems to fix the issue:

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

Based on the implementation of DynamicParameters the DbType defaults to null, so i guess you are missing the DbType-specification in the Add-Method:

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;
}

The correct mapping of nvarchar(max) should be DbType.String accoring to this documentation .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM