泛型参数的可空返回值

Joh*_*ger 5 c# generics nullable dapper

我试图使用Dapper将模型保存到数据库.我使用输入/输出参数设置参数,该参数是int用于更新的现有主键值.

public async Task<TKey> SaveAsync<TKey>(IGraph builder, IDataContext context = null)
{
    var parameters = this.GetParametersFromDefinition(builder, DefinitionDirection.In);

    // See if we have a key defined. If not, we assume this is a new insert.
    // Otherwise we pull the key out and assume it's an update.
    PropertyDefinition key = builder.GetKey();

    if (key != null)
    {
        parameters.Add(key.ResolvedName, key.PropertyValue, null, ParameterDirection.InputOutput);
    }
    else
    {
        throw new InvalidOperationException("The data graph did not have a primary key defined for it.");
    }

    await this.ExecuteProcedure(parameters, builder, context);

    object returnedId = parameters.Get<TKey>(key.ResolvedName);
    return returnedId == null ? default(TKey) : (TKey)returnedId;
}

private Task ExecuteProcedure(DynamicParameters parameters, IGraph builder, IDataContext context = null)
{
    ProcedureDefinition mapping = builder.GetProcedureForOperation(ProcedureOperationType.Insert);
    if (string.IsNullOrEmpty(mapping.StoredProcedure))
    {
        throw new InvalidOperationException("No stored procedure mapped to the builder.");
    }

    // Query the database
    return this.SetupConnection(
        context,
        (connection, transaction) => connection.ExecuteAsync(
            mapping.StoredProcedure,
            parameters,
            commandType: CommandType.StoredProcedure,
            transaction: transaction));
}
Run Code Online (Sandbox Code Playgroud)

它被调用如下:

this.Address.AddressId = await repository.SaveAsync<int>(graph);
Run Code Online (Sandbox Code Playgroud)

当我评估参数时,我会看到我的输入/输出参数.

动态参数

但是,当我尝试在保存中执行此行时:

TKey returnedId = parameters.Get<TKey>(key.ResolvedName);
Run Code Online (Sandbox Code Playgroud)

我被给予以下例外:

例外:Caught:"尝试将DBNull转换为非可空类型!注意out/return参数在数据流完成之前不会有更新的值(在查询的'foreach'之后(...,buffered:false),或者在为QueryMultiple处理GridReader之后)"(System.ApplicationException)捕获到System.ApplicationException:"尝试将DBNull转换为非可空类型!注意out/return参数在数据流之前不会有更新的值完成(在查询的'foreach'之后(...,缓冲:false),或者在为QueryMultiple处理GridReader之后)"时间:2015年7月21日下午10:19:48线程:[7200]

我假设这是一个泛型类型在这种情况下不可为空的问题,因为它是一个整数.这是因为Dapper总是返回一个可空的?我刚刚在存储过程中为OUTPUT分配了一个常量值,以确保为输出分配了一些东西.

我如何解决dapper返回一个可空的问题,是唯一的方法,我int?作为泛型类型传入它?

更新

我能够使用这种方法解决它.所以我不会发布它作为答案.当时间限制到期时,我会发一个答案,除非别人有更好的想法.

object returnedId = parameters.Get<TKey>(key.ResolvedName);
if (returnedId == null)
{
    return default(TKey);
}

return (TKey)returnedId;
Run Code Online (Sandbox Code Playgroud)

Tyr*_*son 1

如果 DBNull 是一个有效值并且应该表示除 default(TKey) 之外的其他值(例如:default(int) = 0),并且如果 TKey 始终是值类型,则将 TKey 约束为结构体,如下所示:

public async Task<TKey?> SaveAsync<TKey>(IGraph builder, IDataContext context = null) where TKey : struct
{
    ...
}
Run Code Online (Sandbox Code Playgroud)

然后像这样获取密钥:

TKey? returnedId = parameters.Get<TKey?>(key.ResolvedName);
Run Code Online (Sandbox Code Playgroud)

SaveAsync 的返回类型将反映该键可能为 null。如果键永远不应该为 null,并且 DBNull 应默认为 default(TKey),则只需使用以下内容:

public async Task<TKey?> SaveAsync<TKey>(IGraph builder, IDataContext context = null) where TKey : struct
{
    ...
    return parameters.Get<TKey?>(key.ResolvedName).GetValueOrDefault();
}
Run Code Online (Sandbox Code Playgroud)