Quelle est la différence entre null et System.DBNull.Value?

92

Existe-t-il une différence entre null et System.DBNull.Value? Si oui, qu'est ce que c'est?

J'ai remarqué ce comportement maintenant -

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

Alors que je récupère des données de la base de données à l'aide d'un datareader sql, bien qu'aucune valeur ne soit if(rdr["Id"] != null)renvoyée trueet que j'ai finalement jeté une exception pour convertir un null en entier.

Mais, ceci si j'utilise des if (rdr["Id"] != System.DBNull.Value)retours false.

Quelle est la différence entre null et System.DBNull.Value?

Pavanred
la source
Eh bien, ils ne sont pas liés. L'une est une instance statique d'une classe dans System.Data, et l'autre est une valeur spéciale signifiant l'absence de référent. Ils n'ont rien à faire ensemble. Pouvez-vous expliquer ce qui vous trouble? Votre vraie question est-elle "pourquoi faire DataRowset se DataReadersmettre à l' DBNull.Valueintérieur d'eux-mêmes au lieu de null?"
mqp
Eh bien, ce n'était pas au début, mais après avoir appris de ce que vous avez dit, je suis curieux. Pouvez-vous me dire pourquoi DataRows et DataReaders mettent DBNull.Value en eux-mêmes au lieu de null?
pavanred
Je ne suis pas sûr moi-même. Voici une réponse: stackoverflow.com/questions/4488727/what-is-the-point-of-dbnull/ ... Il est également possible qu'avant que les types de valeurs nullables n'existent en C #, cela aurait été plus compliqué à gérer null.
mqp
1
J'avais une réponse ici, mais j'ai réalisé que c'était plus approprié pour stackoverflow.com/questions/4488727/what-is-the-point-of-dbnull - alors je l'ai déplacée
Marc Gravell

Réponses:

116

Eh bien, ce nulln'est pas une instance d'aucun type. C'est plutôt une référence invalide.

Cependant, System.DbNull.Valueest une référence valide à une instance de System.DbNull( System.DbNullest un singleton et System.DbNull.Valuevous donne une référence à l'instance unique de cette classe) qui représente des valeurs * inexistantes dans la base de données.

* Nous dirions normalement null, mais je ne veux pas confondre le problème.

Il y a donc une grande différence conceptuelle entre les deux. Le mot-clé nullreprésente une référence non valide. La classe System.DbNullreprésente une valeur inexistante dans un champ de base de données. En général, nous devrions essayer d'éviter d'utiliser la même chose (dans ce cas null) pour représenter deux concepts très différents (dans ce cas une référence invalide versus une valeur inexistante dans un champ de base de données).

Gardez à l'esprit que c'est pourquoi beaucoup de gens préconisent l'utilisation du modèle d'objet nul en général, ce qui est exactement ce dont System.DbNullest un exemple.

Jason
la source
43
+1 Un exemple pratique: si vous utilisez IDbCommand.ExecuteScalar(), il peut renvoyer null (aucun enregistrement retourné) ou DbNull(la première colonne du premier enregistrement est une «valeur inexistante»). Sans DbNullvous ne pourriez pas distinguer l'un de l'autre.
C.Evenhuis
Je recommanderais fortement d'utiliser un langage qui interdit l'utilisation de Null, et ce, à un coût supplémentaire absolument nul. la vie est trop courte pour "motif d'objet nul"
nicolas
3
Une référence nulle est parfaitement valide. ☺
IllidanS4 veut que Monica revienne le
@ C.Evenhuis Eh bien, il y a un autre conseil courant: une fonction ne doit renvoyer qu'un seul type de valeur. C'est pourquoi les gens préfèrent un code TypeScript bien typé. "Quel est le statut de l'exécution" diffère de "Quel est le résultat du calcul". C'est à dire. ils auraient pu décider d'implémenter cette fonction d'une autre manière (peut-être un paramètre out, ou un objet similaire aux objs de réponse de requête HTTP). Bien sûr, c'est une complication pas vraiment souhaitée, mais s'ils l'avaient fait, peut-être que null pourrait être utilisé à la place de DbNull.
klenium
21

De la documentation de la classe DBNull :

Ne confondez pas la notion de null dans un langage de programmation orienté objet avec un objet DBNull. Dans un langage de programmation orienté objet, null signifie l'absence de référence à un objet. DBNull représente une variante non initialisée ou une colonne de base de données inexistante.

Heinzi
la source
11

DBNull.Value est ennuyeux d'avoir à gérer.

J'utilise des méthodes statiques qui vérifient si c'est DBNull, puis renvoie la valeur.

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

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

En outre, lors de l'insertion de valeurs dans un DataRow, vous ne pouvez pas utiliser "null", vous devez utiliser DBNull.Value.

Avoir deux représentations de «nul» est une mauvaise conception sans avantage apparent.

Répugnance
la source
2
Le sentiment de dégoût que nous partageons re: votre dernière déclaration n'est éclipsée que par l'ironie de se présenter ici pour lire ceci et de découvrir que votre nom d'utilisateur est "
haineux
5

DBNull.Value est ce que les fournisseurs de base de données .NET renvoient pour représenter une entrée nulle dans la base de données. DBNull.Value n'est pas null et comparissons à null pour les valeurs de colonne extraites d'une ligne de base de données ne fonctionnera pas, vous devez toujours comparer à DBNull.Value.

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

James Michael Hare
la source
ps Vous devez également utiliser DBNull.Value pour transmettre un paramètre nul à la base de données, sinon il peut être interprété car le paramètre n'a pas été transmis.
James Michael Hare
1
DBNull n'est pas "ce que la base de données renvoie" - c'est simplement la manière dont ADO.NET choisit de l'interpréter; personnellement je ne suis pas sûr que cette interprétation soit très précieuse
Marc Gravell
@MarcGravell Oui, Marc, vous avez raison. Je l'ai mal formulé. ASP.NET traduit la valeur de la colonne null de la base de données en DBNull.Value
James Michael Hare
3

DataRow a une méthode appelée IsNull()que vous pouvez utiliser pour tester la colonne si elle a une valeur nulle - en ce qui concerne la valeur nulle telle qu'elle est vue par la base de données.

DataRow["col"]==nullsera toujours false.

utilisation

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

au lieu.

Daniel Mošmondor
la source
3

Null est similaire au pointeur zéro en C ++ . C'est donc une référence qui ne pointe vers aucune valeur .

DBNull.Valueest complètement différent et est une constante qui est renvoyée lorsqu'une valeur de champ contient NULL.

Aliostad
la source