Valore restituito Nullable su un argomento generico

c# dapper generics nullable

Domanda

Sto cercando di salvare un modello nel database usando Dapper. Ho impostato i parametri con un parametro di input / output che è un int con un valore di chiave primaria esistente utilizzato per un aggiornamento.

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

È invocato in questo modo:

this.Address.AddressId = await repository.SaveAsync<int>(graph);

Quando valuto i parametri, vedo i miei parametri di input / output su di esso.

Parametri dinamici

Tuttavia quando provo a eseguire questa riga nel mio salvataggio:

TKey returnedId = parameters.Get<TKey>(key.ResolvedName);

Mi viene data la seguente eccezione:

Eccezione: Caught: "Tentativo di trasmettere un DBNull a un tipo non annullabile! Si noti che i parametri out / return non avranno valori aggiornati fino al completamento del flusso di dati (dopo 'foreach' per Query (..., buffered: false), o dopo che GridReader è stato eliminato per QueryMultiple) "(System.ApplicationException) È stata rilevata un'eccezione System.ApplicationException:" Tentativo di eseguire il cast di un DBNull su un tipo non annullabile! Tenere presente che i parametri out / return non avranno valori aggiornati fino al flusso di dati completa (dopo 'foreach' per Query (..., buffered: false), o dopo che GridReader è stato eliminato per QueryMultiple) "Ora: 7/21/2015 10:19:48 PM Discussione: [7200]

Suppongo che questo sia un problema con il tipo generico che non è annullabile in questo caso, in quanto è un numero intero. È perché Dapper restituisce sempre un valore nullo? Ho appena assegnato all'OUTPUT sulla stored procedure un valore costante per ora per assicurarmi che l'uscita sia assegnata a qualcosa.

Come posso aggirare il dapper restituendo un valore nullo, è l'unico modo per aggirare il mio passaggio in int? come il tipo generico?

Aggiornare

Sono stato in grado di risolverlo usando questo approccio. SO non mi permette di postarlo come risposta ancora. Quando il limite di tempo è scaduto, posterò una risposta, a meno che qualcun altro non abbia delle idee migliori.

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

return (TKey)returnedId;

Risposta accettata

Se DBNull è un valore valido e dovrebbe significare qualcosa di diverso da predefinito (TKey) (es: default (int) = 0) e se TKey sarà sempre un tipo di valore, quindi vincolare TKey come struct in questo modo:

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

Quindi prendi la chiave in questo modo:

TKey? returnedId = parameters.Get<TKey?>(key.ResolvedName);

Il tipo restituito di SaveAsync rifletterà che la chiave potrebbe essere nullo. Se la chiave non deve mai essere nullo e se DBNull deve essere impostato come predefinito (TKey), utilizzare semplicemente quanto segue:

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


Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow
È legale questo KB? Sì, impara il perché
Autorizzato sotto: CC-BY-SA with attribution
Non affiliato con Stack Overflow
È legale questo KB? Sì, impara il perché