C # ADO.NET: nulls y DbNull - ¿hay sintaxis más eficiente?
Pregunta
Tengo un DateTime?
que estoy tratando de insertar en un campo usando un DbParameter
. Estoy creando el parámetro así:
DbParameter datePrm = updateStmt.CreateParameter();
datePrm.ParameterName = "@change_date";
Y luego quiero poner el valor de DateTime?
en el dataPrm.Value
mientras se tienen en cuenta null
s.
Al principio pensé que sería inteligente:
datePrm.Value = nullableDate ?? DBNull.Value;
pero eso falla con el error
Operador '??' no se puede aplicar a los operandos de tipo 'System.DateTime?' y 'System.DBNull'
Supongo que eso solo funciona si el segundo argumento es una versión no anulable del primer argumento. Entonces fui por:
datePrm.Value = nullableDate.HasValue ? nullableDate.Value : DBNull.Value;
pero eso tampoco funciona:
El tipo de expresión condicional no se puede determinar porque no hay una conversión implícita entre 'System.DateTime' y 'System.DBNull'
¡Pero no quiero convertir entre esos tipos!
Hasta ahora, lo único que puedo hacer para trabajar es:
if (nullableDate.HasValue)
datePrm.Value = nullableDate.Value;
else
datePrm.Value = DBNull.Value;
¿Es esa realmente la única forma en que puedo escribir esto? ¿Hay alguna manera de conseguir que funcione una sola línea utilizando el operador ternario?
Actualización: ¿Realmente no entiendo por qué? La versión no funciona. MSDN dice:
El ?? el operador devuelve el operando de la izquierda si no es nulo, o si no devuelve el operando de la derecha.
¡Eso es exactamente lo que quiero!
Update2: Bueno, al final resultó bastante obvio:
datePrm.Value = nullableDate ?? (object)DBNull.Value;
Solución
Ah ha! ¡Encontré una solución aún más eficiente que la de @ Trebz!
datePrm.Value = nullableDate ?? (object)DBNull.Value;
Otros consejos
Si está utilizando SQLServer, el espacio de nombres System.Data.SqlTypes
contiene algunas clases de utilidad que evitan la conversión de tipo molesto. Por ejemplo, en lugar de esto:
var val = (object) "abc" ?? DBNull.Value;
puedes escribir esto:
var val = "abc" ?? SqlString.Null;
Funcionaría si usas
datePrm.Value = nullableDate.HasValue ? (object)nullableDate.Value : DBNull.Value;
Si está utilizando C # 3.0, puede crear un método de extensión para hacer esto fácilmente:
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 );
}
}
Creo que el error en su segundo intento se debe a que nullableDate.Value y DBNull.Value son tipos diferentes y el operador ternario debe elegir un tipo para devolver en ambos casos. No tengo el entorno para probar esto, pero creo que debería funcionar para usted:
datePrm.Value = nullableDate.HasValue ? (object)nullableDate.Value : (object)DBNull.Value;
La forma en que lo hago, es que tengo una clase de utilidad estática que simplemente pasa y comprueba si el valor del parámetro es nulo, luego establezco el valor para hacer DBNull. Solo hago eso antes de llamar al Ejecutar.