E 'possibile a fondersi corda e DBNull in C #?
-
20-09-2019 - |
Domanda
Sto scrivendo un C # di routine per chiamare un proc memorizzato. Nella lista dei parametri che sto passando, è possibile che uno dei valori possono essere legalmente nullo. Così ho pensato di utilizzare una linea come questa:
cmd.Parameters.Add(new SqlParameter("@theParam", theParam ?? DBNull.Value));
Purtroppo, questo restituisce il seguente errore:
CS0019: Operatore '??' non può essere applicato a operandi di tipo 'stringa' e 'System.DBNull'
Ora, questo sembra abbastanza chiaro, ma non capisco la logica dietro di esso. Perché questo non funziona? (E spesso, quando non capisco il motivo per cui qualcosa non funziona, non è che non può il lavoro ... è che io sto facendo male.)
Devo veramente di allungare questo fuori in un più istruzione if-then?
Modifica (Per inciso, a coloro che suggerisce di utilizzare solo "null" così com'è, non funziona ho inizialmente pensato che nulla sarebbe auto-tradotto in DBNull troppo, ma a quanto pare. non lo fa. (Chi lo sapeva?))
Soluzione
Non come questo, no. I tipi devono corrispondere. Lo stesso vale per il ternario.
Ora, da "match", non significa che devono essere gli stessi. Ma essi devono essere compatibili assegnazione. In sostanza:. Nello stesso albero di ereditarietà
Un modo per aggirare il problema è quello di lanciare la stringa di opporsi:
var result = (object)stringVar ?? DBNull.Value;
Ma non mi piace questo, perché significa che stai contando più sul costruttore SqlParameter per ottenere i tipi di destra. Invece, mi piace fare in questo modo:
cmd.Parameters.Add("@theParam", SqlDbTypes.VarChar, 50).Value = theParam;
// ... assign other parameters as well, don't worry about nulls yet
// all parameters assigned: check for any nulls
foreach (var p in cmd.Parameters)
{
if (p.Value == null) p.Value = DBNull.Value;
}
Si noti anche che ho dichiarato in modo esplicito il tipo di parametro.
Altri suggerimenti
new SqlParameter("@theParam", (object)theParam ?? DBNull.Value)
Il ?? operatore restituisce l'operando di sinistra, se non è nullo, altrimenti la funzione restituisce l'operando a destra. Ma nel tuo caso sono diversi tipi, in modo che non funziona.
L'operatore Null Coalesce solo con i dati dello stesso tipo. Non è possibile inviare NULL al SqlParamater come questo farà Sql Server dice che non è stato specificato il parametro.
È possibile utilizzare
new SqlParameter("@theParam", (object)theParam ?? (object)DBNull.Value)
In alternativa è possibile creare una funzione che restituiscono DBNull quando viene trovato nulla, come
public static object GetDataValue(object o)
{
if (o == null || String.Empty.Equals(o))
return DBNull.Value;
else
return o;
}
E poi chiamare
new SqlParameter("@theParam", GetDataValue(theParam))
Il motivo non è possibile utilizzare l'operatore nulla si fondono è che deve restituire un tipo e si stanno fornendo più di un tipo. theParam
è una stringa. DbNull.Value
è un riferimento a un'istanza statica di tipo System.DBNull . Questo è ciò che la sua attuazione assomiglia;
public static readonly DBNull Value = new DBNull();
//the instantiation is actually in the
//static constructor but that isn't important for this example
Quindi, se si dovesse avere un metodo NullCoalesce, quale sarebbe il suo tipo di ritorno sarà? Non può essere sia System.String e System.DBNull, deve essere uno o l'altro, o un tipo genitore comune.
Quindi, che porta a questo tipo di codice;
cmd.Parameters.Add(
new SqlParameter("@theParam", (object)theParam ?? (object)DBNull.Value)
);
Nel vostro proc memorizzato quando si dichiara la variabile in entrata, l'ha impostato la var uguale a null e quindi non si passa in dal codice csharp, sarà poi prendere il valore di default da SQL
@theParam as varchar(50) = null
e poi nel vostro csharp
if (theParam != null)
cmd.Parameters.Add(new SqlParameter("@theParam", theParam));
Questo è come io di solito passare l'opzione e / o valori di default ai miei stored procedure
Sono abbastanza sicuro che solo di passaggio un null per i risultati SqlParameter costruttore in esso viene inviato come un DBNull.Value ... potrei sbagliarmi, dato che io uso le EnterpriseLibraries per l'accesso DB, ma sono abbastanza sicuro che l'invio di un nulla va bene lì.
cmd.Parameters.Add (new SqlParameter ( "@ theParam", (theParam == null) DBNull.Value:? TheParam));
Utilizzare questa sintassi:
(theParam come oggetto) ?? (DBNull.Value come oggetto)
In questo caso le due parti del operatore ?? sono dello stesso tipo.
Non è sicuro che la risposta alla tua domanda specifica, ma come su questo?
string.IsNullOrEmpty(theParam) ? DBNull.Value : theParam
o se vuoto è ok
(theParam == null) ? DBNull.Value : theParam