2009-10-09 6 views
10

Estoy escribiendo una rutina C# para llamar a un proceso almacenado. En la lista de parámetros que estoy ingresando, es posible que uno de los valores pueda ser legalmente nulo. Así que pensé que haría uso de una línea como esta:¿Es posible unir string y DBNull en C#?

cmd.Parameters.Add(new SqlParameter("@theParam", theParam ?? DBNull.Value)); 

Desafortunadamente, esto devuelve el siguiente error:

CS0019: Operator '??' cannot be applied to operands of type 'string' and 'System.DBNull'

Ahora, esto parece bastante clara, pero no entiendo la razón de ser eso. ¿Por qué esto no funcionaría? (Y a menudo, cuando yo no entiendo por qué algo no está funcionando, no es que no puede trabajo ... es que estoy haciendo mal.)

es lo que realmente tiene que estirar esto en una declaración if-then más larga?

EDIT:.. (Dicho sea de paso, a aquellos que sugieren usar sólo "nula" tal como está, no funciona que originalmente figuraba nula sería traducida-AUTO en DBNull también, pero al parecer no lo hace (¿Quién sabía?)

Respuesta

16

No es así, no. Los tipos tienen que coincidir. Lo mismo es cierto para el ternario.

Ahora, por "coincidencia", no me refiero a que tienen que ser iguales. Pero tienen que ser compatibles con la asignación. Básicamente: en el mismo árbol de herencia.

Una forma de evitar esto es para emitir su cadena de objetar:

var result = (object)stringVar ?? DBNull.Value; 

Pero no me gusta esto, porque significa que usted está confiando más en el constructor SqlParameter para obtener sus tipos derecha . En su lugar, me gusta hacerlo de esta manera:

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

Nótese también que he declarado explícitamente el tipo de parámetro.

+0

Para información, los Comandos creados por un CommandBuilder tienen un conjunto de los parámetros construidos para ti Sin embargo, surge el mismo problema en el sentido de que no puede esperar pasar nulo a uno de los parámetros en el ParameterCollection generado. usted todavía tiene que hacer lo descrito arriba. – rohancragg

+0

Buena solución simple :-) – IrishChieftain

+0

También puede crear un método de extensión para hacer esto. –

0

Estoy bastante seguro de que pasar un nulo al constructor SqlParameter hace que se envíe como DBNull.Value ... Puedo estar equivocado, ya que utilizo EnterpriseLibraries para acceder a bases de datos, pero estoy bastante seguro de que enviar un nulo está bien allí.

+2

Sí, estás equivocado, -1. Si intenta pasar el nulo, el servidor SQL emitirá el error "el parámetro ... no existe". – erikkallen

+0

Erich, supongo que tiene razón en este caso, ya que he observado el comportamiento que describe muchas veces en VB.NET. Aparte del hecho de que esto es C#, no sé qué otras circunstancias son diferentes que le permitan funcionar para mí y no para erikkallen o Beska. –

+0

Ah, suelo usar la clase SqlHelper y acabo de encontrar esta línea dentro: If (p.Direction = ParameterDirection.InputOutput OrElse p.Direction = ParameterDirection.Input) AndAlso p.Value Is Nothing Then p.Value = DBNull .Value End If ... Es por eso que funciona. –

-1

No estoy seguro de la respuesta específica a su pregunta, pero ¿qué tal esto?

string.IsNullOrEmpty(theParam) ? DBNull.Value : theParam 

o si está en blanco es bien

(theParam == null) ? DBNull.Value : theParam 
+1

Nopennary requiere que los tipos coincidan también. –

+0

D'oh! ¡Eso me enseñará a post-before-test! – n8wrl

5
new SqlParameter("@theParam", (object)theParam ?? DBNull.Value) 
+0

Ni siquiera necesita convertir ambos en nulos. Usualmente hago un nuevo SqlParameter ("@ theParam", (object) theParam ?? DBNull.Value) – erikkallen

3

El ?? el operador devuelve el operando de la izquierda si no es nulo, o bien devuelve el operando derecho. Pero en tu caso son tipos diferentes, entonces no funciona.

+0

(edición sin consecuencias hecha para que me permita votar esta respuesta.) – Beska

0

cmd.Parameters.Add (nuevo SqlParameter ("@ theParam", (theParam == null)? DBNull.Value: theParam));

2

La razón por la que no puede usar el operador de fusión nula es porque tiene que devolver un tipo y está proporcionando más de un tipo. theParam es una cadena. DbNull.Value es una referencia a una instancia estática del tipo System.DbNull. Así es como se ve su implementación;

public static readonly DBNull Value = new DBNull(); 
//the instantiation is actually in the 
//static constructor but that isn't important for this example 

Así que si usted fuera a tener un método NullCoalesce, ¿cuál sería su tipo de retorno sea? No puede ser System.String y System.DbNull, tiene que ser uno o el otro, o un tipo padre común.

Lo que conduce a este tipo de código;

cmd.Parameters.Add(
    new SqlParameter("@theParam", (object)theParam ?? (object)DBNull.Value) 
); 
2

El operador nulo Coalesce solo con datos del mismo tipo. No puede enviar NULL al SqlParamater ya que esto hará que el Servidor SQL diga que no especificó el parámetro.

Puede utilizar

new SqlParameter("@theParam", (object)theParam ?? (object)DBNull.Value) 

O puede crear una función que volver DBNull cuando se encuentra nula, como

public static object GetDataValue(object o) 
{ 
    if (o == null || String.Empty.Equals(o)) 
     return DBNull.Value; 
    else 
     return o; 
} 

y luego llamar

new SqlParameter("@theParam", GetDataValue(theParam)) 
+4

Sí, el método GetDataValue es cómo manejé esto en el pasado. Realmente desearía que hubiera un comportamiento incorporado para esto. Al igual que una propiedad que podría especificar en las clases ADO.NET, eso sustituiría a DBNULL.Value (o algo que especifique) cuando obtiene un valor nulo. – LoveMeSomeCode

+0

Sí, a mí también me gustaría poder especificar null y dejar que se asigne a DBNull automáticamente. –

+0

@LoveMe: ¡Cuente conmigo para que esto se deba manejar de forma predeterminada! –

0

Utilice esta sintaxis:

(theParam como objeto) ?? (DBNull.Value como objeto)

En este caso, ¿ambas partes del operador? son del mismo tipo

+0

1) Solo necesita lanzar un lado, ambos son excesivos; 2) Usar 'as' a menos que proceda a verificar el valor de retorno del elenco (es decir, como interruptor de tipo) es una mala idea: un reparto normal comunica el intento más claro. –

1

En el procedimiento almacenado cuando se declare la variable de entrada, tiene que establecer el var igual a null y luego no pase de su código de CSharp, será luego recoger el valor predeterminado de SQL

@theParam as varchar(50) = null 

y luego en su CSharp

if (theParam != null) 
    cmd.Parameters.Add(new SqlParameter("@theParam", theParam)); 

Esta es la forma generalmente paso opción y/o valores por defecto en mis procedimientos almacenados

+0

Creo que quiso decir "! =", Arregló su muestra. –

+0

sí, gracias. Lo noté mientras intentaba hacer funcionar el bloque de código y olvidé volver atrás y editar. –