Qual é a diferença entre null e System.DBNull.Value?

92

Existe alguma diferença entre null e System.DBNull.Value? Se sim, o que é?

Percebi esse comportamento agora -

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

Enquanto eu recupero dados do banco de dados usando um datareader sql, nenhum valor foi if(rdr["Id"] != null)retornado truee, eventualmente, lançou uma exceção para converter um nulo como inteiro.

Mas, isso se eu usar if (rdr["Id"] != System.DBNull.Value)retornos false.

Qual é a diferença entre null e System.DBNull.Value?

pavanhado
fonte
Bem, eles não estão relacionados. Um é uma instância estática de uma classe em System.Datae o outro é um valor especial que significa a falta de um referente. Eles não têm nada a ver um com o outro. Você pode explicar sobre o que está confuso? A sua verdadeira pergunta é "por que fazer DataRowse DataReaderscolocar DBNull.Valuedentro de si em vez de null?"
mqp de
Bem, não foi inicialmente, mas depois de aprender com o que você disse, estou curioso. Você poderia me dizer por que DataRows e DataReaders colocam DBNull.Value neles em vez de nulos?
pavanred de
Eu mesmo não tenho certeza. Aqui está uma resposta: stackoverflow.com/questions/4488727/what-is-the-point-of-dbnull/… Também é possível que antes que os tipos de valor anuláveis ​​existissem no C #, teria sido mais complicado lidar com ele null.
mqp de
1
Eu tinha uma resposta aqui, mas percebi que era mais adequado para stackoverflow.com/questions/4488727/what-is-the-point-of-dbnull - então mudei
Marc Gravell

Respostas:

116

Bem, null não é uma instância de qualquer tipo. Em vez disso, é uma referência inválida.

No entanto, System.DbNull.Valueé uma referência válida a uma instância de System.DbNull( System.DbNullé um singleton e System.DbNull.Valuefornece uma referência à única instância dessa classe) que representa valores * inexistentes no banco de dados.

* Normalmente diríamos null, mas não quero confundir a questão.

Portanto, há uma grande diferença conceitual entre os dois. A palavra-chave nullrepresenta uma referência inválida. A classe System.DbNullrepresenta um valor inexistente em um campo do banco de dados. Em geral, devemos tentar evitar o uso da mesma coisa (neste caso null) para representar dois conceitos muito diferentes (neste caso, uma referência inválida versus um valor inexistente em um campo do banco de dados).

Tenha em mente que é por isso que muitas pessoas defendem o uso do padrão de objeto nulo em geral, que é exatamente o que System.DbNullé um exemplo.

Jason
fonte
43
+1 Um exemplo prático: se você usar IDbCommand.ExecuteScalar(), pode retornar nulo (nenhum registro retornado) ou DbNull(a primeira coluna no primeiro registro é um 'valor inexistente'). Sem DbNullvocê não seria capaz de distinguir um do outro.
C.Evenhuis
Eu recomendo fortemente o uso de uma linguagem que proíba o uso de nulo, e o faz com absolutamente nenhum custo extra. a vida é muito curta para um "padrão de objeto nulo"
nicolas
3
Uma referência nula é perfeitamente válida. ☺
IllidanS4 quer Monica de volta em
@ C.Evenhuis Bem, há outro conselho comum: uma função deve retornar apenas um tipo de valor. É por isso que as pessoas preferem um código TypeScript bem digitado. "Qual é o status da execução" difere de "Qual é o resultado computacional". Ou seja, eles poderiam ter decidido implementar essa função de outra forma (talvez um parâmetro de saída ou um objeto semelhante a objs de resposta de solicitação de HTTP). Claro, esta é uma complicação não desejada, mas se eles tivessem feito isso, talvez null pudesse ser usado em vez de DbNull.
klenium
21

Da documentação da classe DBNull :

Não confunda a noção de nulo em uma linguagem de programação orientada a objetos com um objeto DBNull. Em uma linguagem de programação orientada a objetos, null significa a ausência de uma referência a um objeto. DBNull representa uma variante não inicializada ou uma coluna de banco de dados inexistente.

Heinzi
fonte
11

DBNull.Value é chato de ter que lidar.

Eu uso métodos estáticos que verificam se é DBNull e retornam o valor.

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

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

Além disso, ao inserir valores em um DataRow, você não pode usar "null", você deve usar DBNull.Value.

Ter duas representações de "nulo" é um projeto ruim sem benefício aparente.

Repugnância
fonte
2
O sentimento de repulsa que compartilhamos re: sua última declaração é superada apenas pela ironia de aparecer aqui para ler isso e descobrir que seu nome de usuário é "repugnante"
Iofacture
5

DBNull.Value é o que os provedores de banco de dados .NET retornam para representar uma entrada nula no banco de dados. DBNull.Value não é nulo e as comparações com nulo para valores de coluna recuperados de uma linha de banco de dados não funcionarão, você deve sempre comparar com DBNull.Value.

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

James Michael Hare
fonte
ps Você também deve usar DBNull.Value para passar um parâmetro nulo para o banco de dados, caso contrário, ele pode ser interpretado como o parâmetro não foi passado.
James Michael Hare de
1
DBNull não é "o que o banco de dados retorna" - é simplesmente como o ADO.NET escolhe interpretá-lo; pessoalmente, não tenho certeza se esta interpretação é muito valiosa
Marc Gravell
@MarcGravell Sim, Marc, você está correto. Eu disse isso incorretamente. ASP.NET traduz o valor da coluna nula do banco de dados em DBNull.Value
James Michael Hare,
3

DataRow tem um método chamado IsNull()que você pode usar para testar a coluna se ela tiver um valor nulo - em relação ao nulo visto pelo banco de dados.

DataRow["col"]==nullsempre será false.

usar

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

em vez de.

Daniel Mošmondor
fonte
3

Nulo é semelhante ao ponteiro zero em C ++ . Portanto, é uma referência que não aponta para nenhum valor .

DBNull.Valueé completamente diferente e é uma constante que é retornada quando um valor de campo contém NULL.

Aliostad
fonte