¿Cuál es la diferencia entre null y System.DBNull.Value?

92

¿Hay alguna diferencia entre null y System.DBNull.Value? ¿Y si si, que?

Noté este comportamiento ahora -

while (rdr.Read())
{
    if (rdr["Id"] != null) //if (rdr["Id"] != System.DBNull.Value)  
    {
        int x = Convert.ToInt32(rdr["Id"]);
    }
}

Mientras que recuperar datos de la base de datos utilizando un datareader SQL, aunque no hay valor devuelto if(rdr["Id"] != null)devuelto truey, finalmente, lanzó una excepción para la fundición de un nulo como entero.

Pero, esto si utilizo if (rdr["Id"] != System.DBNull.Value)devoluciones false.

¿Cuál es la diferencia entre null y System.DBNull.Value?

pavimentado
fuente
Bueno, no están relacionados. Uno es una instancia estática de una clase en System.Data, y el otro es un valor especial que significa la falta de un referente. No tienen nada que ver el uno con el otro. ¿Puedes explicar en qué estás confundido? Su verdadera pregunta es "¿por qué hacer DataRowsy DataReadersponer DBNull.Valuedentro de sí mismos en lugar de null?"
mqp
Bueno, no lo fue inicialmente, pero después de aprender de lo que dijiste, tengo curiosidad. ¿Podría decirme por qué DataRows y DataReaders ponen DBNull.Value en sí mismos en lugar de null?
pavanred
Yo mismo no estoy seguro. Aquí hay una respuesta: stackoverflow.com/questions/4488727/what-is-the-point-of-dbnull/… También es posible que antes de que existieran los tipos de valores que aceptan valores NULL en C #, hubiera sido más complicado lidiar con ellos null.
mqp
1
Tenía una respuesta aquí, pero me di cuenta de que era más adecuada para stackoverflow.com/questions/4488727/what-is-the-point-of-dbnull , así que la moví
Marc Gravell

Respuestas:

118

Bueno, nullno es una instancia de ningún tipo. Más bien, es una referencia inválida.

Sin embargo, System.DbNull.Valuees una referencia válida a una instancia de System.DbNull( System.DbNulles un singleton y System.DbNull.Valuele da una referencia a la instancia única de esa clase) que representa valores inexistentes * en la base de datos.

* Normalmente diríamos null, pero no quiero confundir el problema.

Entonces, hay una gran diferencia conceptual entre los dos. La palabra clave nullrepresenta una referencia no válida. La clase System.DbNullrepresenta un valor inexistente en un campo de base de datos. En general, deberíamos intentar evitar usar lo mismo (en este caso null) para representar dos conceptos muy diferentes (en este caso una referencia inválida versus un valor inexistente en un campo de base de datos).

Tenga en cuenta que esta es la razón por la que mucha gente aboga por el uso del patrón de objeto nulo en general, que es exactamente de lo que System.DbNulles un ejemplo.

jason
fuente
43
+1 Un ejemplo práctico: si lo usa IDbCommand.ExecuteScalar(), puede devolver nulo (no se devuelven registros) o DbNull(la primera columna del primer registro es un 'valor inexistente'). Sin DbNullusted no podría distinguir uno del otro.
C.Evenhuis
Recomendaría encarecidamente utilizar un lenguaje que prohíba el uso de Null, y lo hace a un costo adicional absolutamente 0. la vida es demasiado corta para el "patrón de objeto nulo"
nicolas
3
Una referencia nula es perfectamente válida. ☺
IllidanS4 apoya a Monica el
@ C.Evenhuis Bueno, hay otro consejo común: una función debe devolver solo un tipo de valor. Es por eso que la gente prefiere un código TypeScript bien escrito. "Cuál es el estado de la ejecución" difiere de "Cuál es el resultado computacional". Es decir. podrían haber decidido implementar esta función de alguna otra manera (tal vez un parámetro de salida, o un objeto similar a los objs de respuesta de solicitud HTTP). Claro, esta es una complicación no deseada, pero si lo hubieran hecho, tal vez se podría usar null en lugar de DbNull.
klenium
21

De la documentación de la clase DBNull :

No confunda la noción de nulo en un lenguaje de programación orientado a objetos con un objeto DBNull. En un lenguaje de programación orientado a objetos, nulo significa la ausencia de una referencia a un objeto. DBNull representa una variante no inicializada o una columna de base de datos inexistente.

Heinzi
fuente
11

Es molesto tener que lidiar con DBNull.Value.

Utilizo métodos estáticos que comprueban si es DBNull y luego devuelven el valor.

SqlDataReader r = ...;
String firstName = getString(r[COL_Firstname]);

private static String getString(Object o) {
   if (o == DBNull.Value) return null;
   return (String) o;
}

Además, al insertar valores en un DataRow, no puede usar "nulo", debe usar DBNull.Value.

Tener dos representaciones de "nulo" es un mal diseño sin beneficio aparente.

Aversión
fuente
2
El sentimiento de disgusto que compartimos con respecto a: su última declaración es superada solo por la ironía de aparecer aquí para leer esto y descubrir que su nombre de usuario es "repugnante"
Iofacture
5

DBNull.Value es lo que devuelven los proveedores de la base de datos .NET para representar una entrada nula en la base de datos. DBNull.Value no es nulo y las comparaciones con nulo para los valores de columna recuperados de una fila de la base de datos no funcionarán, siempre debe comparar con DBNull.Value.

http://msdn.microsoft.com/en-us/library/system.dbnull.value.aspx

James Michael Hare
fuente
ps También debe usar DBNull.Value para pasar un parámetro nulo a la base de datos, de lo contrario, se puede interpretar como que el parámetro no se pasó.
James Michael Hare
1
DBNull no es "lo que devuelve la base de datos", es simplemente cómo ADO.NET elige interpretarlo; personalmente no estoy seguro de que esta interpretación sea muy valiosa
Marc Gravell
@MarcGravell Sí, Marc, tienes razón. Lo expresé incorrectamente. ASP.NET traduce el valor de la columna nula de la base de datos a DBNull.Value
James Michael Hare
3

DataRow tiene un método que se llama IsNull()que puede usar para probar la columna si tiene un valor nulo, con respecto al nulo tal como lo ve la base de datos.

DataRow["col"]==nullsiempre lo será false.

utilizar

DataRow r;
if (r.IsNull("col")) ...

en lugar.

Daniel Mošmondor
fuente
3

Null es similar al puntero cero en C ++ . Entonces es una referencia que no apunta a ningún valor .

DBNull.Valuees completamente diferente y es una constante que se devuelve cuando un valor de campo contiene NULL.

Aliostad
fuente