Настраиваемый обработчик типов Dapper с динамическими параметрами - PullRequest
3 голосов
/ 14 июля 2020

Я использую Dapper в своем проекте Web-API (. NET Core 3.1) и пытаюсь вставить запись в базу данных (SQL Server 2017) + вернуть созданный идентификатор. У меня есть этот объект ...

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

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

, а ответственный метод выглядит так:

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

Я выполняю хранимую процедуру spDetailGroup_Insert, которая ожидает указанный выше объект в JSON формат NVARCHAR(MAX) и имеет идентификатор в качестве выходного параметра. Я написал обработчик, который должен сериализовать объект при использовании в качестве параметра (я думал):

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

В конструкторе класса я использую SqlMapper.AddTypeHandler(new TypeHandler<CreateDetailGroupDto>());, чтобы добавить TypeHandler для DTO. Однако ... при запуске методов Create объект не преобразуется в JSON, даже если метод SetValue в обработчике успешно выполняется. Я знаю, что это довольно конкретный c, но есть ли у кого-нибудь идеи, что здесь может происходить?

Изменить: Похоже, что добавление одной строки в метод SetValue для указания DbType, похоже, решает проблему:

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

1 Ответ

2 голосов
/ 14 июля 2020

На основе реализации DynamicParameters DbType по умолчанию имеет значение null, поэтому я предполагаю, что вам не хватает спецификации DbType в 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;
}

Правильное сопоставление nvarchar (max) должен быть DbType.String согласно этой документации .

...