C # ADO.NET: null e DbNull & # 8212; c'è una sintassi più efficiente?
Domanda
Ho un DateTime?
che sto cercando di inserire in un campo usando un DbParameter
. Sto creando il parametro in questo modo:
DbParameter datePrm = updateStmt.CreateParameter();
datePrm.ParameterName = "@change_date";
E poi voglio mettere il valore di DateTime?
in dataPrm.Value
tenendo conto di null
s.
Inizialmente pensavo di essere intelligente:
datePrm.Value = nullableDate ?? DBNull.Value;
ma ciò non riesce con l'errore
Operatore '??' non può essere applicato agli operandi di tipo "System.DateTime?" e "System.DBNull"
Quindi immagino che funzioni solo se il secondo argomento è una versione non nullable del primo argomento. Quindi ho scelto:
datePrm.Value = nullableDate.HasValue ? nullableDate.Value : DBNull.Value;
ma neanche questo funziona:
Il tipo di espressione condizionale non può essere determinato perché non esiste una conversione implicita tra 'System.DateTime' e 'System.DBNull'
Ma non voglio convertirmi tra questi tipi!
Finora l'unica cosa che posso fare al lavoro è:
if (nullableDate.HasValue)
datePrm.Value = nullableDate.Value;
else
datePrm.Value = DBNull.Value;
È davvero l'unico modo in cui posso scrivere questo? C'è un modo per ottenere un one-liner usando l'operatore ternario per lavorare?
Aggiornamento: non capisco perché ?? la versione non funziona. MSDN dice:
Il ?? l'operatore restituisce l'operando di sinistra se non è null, oppure restituisce l'operando di destra.
Questo è esattamente quello che voglio!
Aggiornamento2: Beh, alla fine era abbastanza ovvio:
datePrm.Value = nullableDate ?? (object)DBNull.Value;
Soluzione
Ah ah! Ho trovato una soluzione ancora più efficiente di @ Trebz!
datePrm.Value = nullableDate ?? (object)DBNull.Value;
Altri suggerimenti
Se si utilizza SQLServer, lo spazio dei nomi System.Data.SqlTypes
contiene alcune classi di utilità che evitano il fastidioso cast di tipi. Ad esempio invece di questo:
var val = (object) "abc" ?? DBNull.Value;
puoi scrivere questo:
var val = "abc" ?? SqlString.Null;
Funzionerebbe se lo usi
datePrm.Value = nullableDate.HasValue ? (object)nullableDate.Value : DBNull.Value;
Se stai usando C # 3.0 puoi creare un metodo di estensione per farlo facilmente:
public static class DBNullableExtensions
{
public static object ToDBValue<T>(this Nullable<T> value) where T:struct
{
return value.HasValue ? (object)value.Value : DBNull.Value;
}
}
class Program
{
static void Main(string[] args)
{
int? x = null;
Console.WriteLine( x.ToDBValue() == DBNull.Value );
}
}
Penso che l'errore nel tuo secondo tentativo sia dovuto al fatto che nullableDate.Value e DBNull.Value sono tipi diversi e l'operatore ternario deve scegliere un tipo da restituire in entrambi i casi. Non ho l'ambiente per testarlo, ma penso che dovrebbe funzionare per te:
datePrm.Value = nullableDate.HasValue ? (object)nullableDate.Value : (object)DBNull.Value;
Il modo in cui lo faccio è che ho una classe di utilità statica che passa e controlla se il valore del parametro è null, quindi ho impostato il valore per fare DBNull. Lo faccio solo prima di chiamare Execute.