74 votes

Quel est le point de DBNull?

Dans .NET il y a l' null de référence, qui est utilisé partout pour indiquer qu'un objet de référence est vide, et puis il y a l' DBNull, qui est utilisé par les pilotes de base de données (et quelques autres) pour désigner... à peu près la même chose. Naturellement, cela crée beaucoup de confusion et de routines de conversion doivent être sortis, etc.

Alors, pourquoi l'original .NET les auteurs décident de faire cela? Pour moi, il n'a pas de sens. Leur documentation n'a pas de sens:

Le DBNull classe représente une inexistant valeur. Dans une base de données, par exemple, une colonne dans une ligne d'une table peut ne pas contenir toutes sortes de données que ce soit. Qui est, la colonne est considérée ne pas exister du tout, au lieu de se contenter de ne pas avoir une valeur. Un DBNull objet représente l'inexistante de la colonne. En outre, l'interopérabilité COM utilise le DBNull classe de distinguer entre une VT_NULL variante, ce qui indique une inexistant valeur, et un VT_EMPTY variante, ce qui indique une valeur quelconque.

C'est quoi cette merde sur une colonne "n'existant pas"? Il existe une colonne, il n'a tout simplement pas avoir une valeur pour la ligne particulière. Si elle n'existait pas, j'aurais une exception en essayant d'accéder à la cellule spécifique, pas un DBNull! Je peux comprendre le besoin de différencier VT_NULL et VT_EMPTY, mais alors pourquoi ne pas faire un COMEmpty classe à la place? Ce serait beaucoup plus lisible ajustement dans l'ensemble .NET framework.

Ai-je raté quelque chose? Quelqu'un peut-il éclairer pourquoi DBNull a été inventé, et les problèmes qu'il aide à résoudre?

181voto

Marc Gravell Points 482669

Je ne suis pas daccord avec la tendance ici. Je vais aller sur le dossier:

Je ne crois pas qu' DBNull sert aucune fin utile; il s'y ajoute une confusion inutile, tout en contribuant pratiquement aucune valeur.

L'argument est souvent mis en avant que la null est une référence non valide, et qu' DBNull est un objet null; elle n'est pas vraie. Par exemple:

int? x = null;

ce n'est pas une référence non valide"; c'est un null de la valeur. En effet, null signifie que tout ce que vous voulez dire, et franchement, je n'ai absolument aucun problème à travailler avec des valeurs qui peuvent être null (en effet, même dans SQL nous avons besoin pour travailler correctement avec null - rien ne change ici). De même, la "objet nul motif" n'a de sens que si vous êtes réellement en la traitant comme un objet en programmation orientée objet, mais si nous avons une valeur qui peut être "notre valeur, ou un DBNull" ensuite, il doit être object, donc on ne peut pas être quelque chose d'utile.

Il y a beaucoup de mauvaises choses avec DBNull:

  • il vous oblige à travailler avec des object, depuis seulement object peut contenir DBNull ou une autre valeur
  • il n'y a pas de réelle différence entre "pourrait être une valeur ou DBNull" vs "pourrait être une valeur ou null"
  • l'argument qu'elle découle d'1.1 (pré-nullable-types) est vide de sens; nous pourrions utiliser null parfaitement bien dans 1.1
  • la plupart des Api ont "est-il nul?" méthodes, par exemple DBDataReader.IsDBNull ou DataRow.IsNull - qui ne requièrent DBNull existe sur le plan de l'API
  • DBNull d'échec en termes de null-coalescence; value ?? defaultValue ne fonctionne pas si la valeur est DBNull
  • DBNull.Value ne peut pas être utilisé dans les paramètres facultatifs, car ce n'est pas une constante
  • l'exécution de la sémantique de l' DBNull identiques à la sémantique de l' null; en particulier, DBNull réellement égaux DBNull - de sorte qu'il ne permet pas de faire le travail de représentation de la sémantique SQL
  • souvent les forces de la valeur des valeurs du type à être mis en boîte car il utilise object
  • si vous avez besoin de tester pour DBNull, vous pourriez aussi bien avoir testé pour seulement null
  • il provoque d'énormes problèmes pour des choses comme la commande des paramètres, avec un comportement idiot que si un paramètre a un null de la valeur il n'est pas envoyé... eh bien, en voilà une idée: si vous ne voulez pas un paramètre envoyé - ne pas ajouter à la collection de paramètres
  • tous les ORM je pense, fonctionne parfaitement bien sans aucun besoin ou de l'utilisation de DBNull, sauf comme un supplément de nuisance lorsque l'on parle à l'ADO.NET code

Le seul , même à distance argument convaincant que j'ai jamais vu pour justifier l' existence d'une telle valeur en DataTable, lors du passage en valeurs afin de créer une nouvelle ligne; un null signifie "utiliser par défaut", une DBNull est explicitement null franchement cette API pourrait avoir eu un traitement spécifique pour ce cas - imaginaire DataRow.DefaultValue par exemple serait beaucoup mieux que de l'introduction d'un DBNull.Value qui infecte de vastes portions de code pour aucune raison.

De même, l' ExecuteScalar scénario est... au mieux précaire; si vous exécutez un scalaire méthode, vous attendre à un résultat. Dans le scénario où il n'y a pas de lignes, de revenir null ne semble pas trop terrible. Si vous avez absolument besoin de lever l'ambiguïté entre "pas de lignes" et "une seule valeur null est retournée", il y a le lecteur de l'API.

Ce navire a navigué il y a longtemps, et il est beaucoup trop tard pour le corriger. Mais! S'il vous plaît ne pas penser que tout le monde est d'accord que c'est une "évidence" de la chose. Beaucoup de développeurs ne pas voir la valeur dans ce drôle de pli sur la BCL.

En fait je me demande si tout cela provient de deux choses:

  • avoir à utiliser le mot - Nothing au lieu de quelque chose avec la valeur "null" dans VB
  • être en mesure de nous l' if(value is DBNull) de la syntaxe qui "ressemble à SQL", plutôt que de oh-so-tricky if(value==null)

Résumé:

Avoir 3 options (null, DBNull, ou une valeur réelle) n'est utile que s'il existe un véritable exemple où vous avez besoin de lever l'ambiguïté entre les 3 cas différents. Je n'ai pas encore vu une occasion où j'ai besoin de représenter les deux "null" états, de sorte qu' DBNull est entièrement redondant étant donné qu' null existe déjà et a beaucoup mieux la langue et à l'exécution.

48voto

Colin Mackay Points 9303

Le fait est que dans certaines situations, il existe une différence entre une valeur de base de données nulle et un null .NET.

Par exemple. Si vous utilisez ExecuteScalar (qui renvoie la première colonne de la première ligne du jeu de résultats) et que vous obtenez une valeur null, cela signifie que le code SQL exécuté n'a renvoyé aucune valeur. Si vous récupérez DBNull, cela signifie qu'une valeur a été renvoyée par le code SQL et que sa valeur était NULL. Vous devez être capable de faire la différence.

15voto

Rikalous Points 2996

DbNull représente une boîte sans contenu; null indique la non-existence de la boîte.

0voto

jvdbogae Points 812

Vous utilisez DBNull pour les données manquantes. Null dans le langage .NET signifie qu'il n'y a pas de pointeur pour un objet / une variable.

Données manquantes DBNull: http://msdn.microsoft.com/en-us/library/system.dbnull.value.aspx

Les effets des données manquantes sur les statistiques:

http://en.wikipedia.org/wiki/Missing_values

0voto

The Dag Points 812

Il y a quelques différences entre un CLR nulle et une DBNull. Tout d'abord, la valeur null dans les bases de données relationnelles a différents "équivaut à" la sémantique: null n'est pas égal à null. CLR null EST égal à null.

Mais je soupçonne que la raison principale est la façon par laquelle le paramètre valeurs par défaut dans SQL server et la mise en œuvre du fournisseur.

Pour voir la différence, créer une procédure avec un paramètre qui a une valeur par défaut:

CREATE PROC [Echo] @s varchar(MAX) = 'hello'
AS
    SELECT @s [Echo]

Bien structuré DAL code qui doit séparer de création de commande de l'utilisation (pour permettre à l'aide de la même commande plusieurs fois, par exemple pour appeler une procédure stockée à de nombreuses reprises de manière efficace). Écrire une méthode qui retourne un SqlCommand représentant la procédure ci-dessus:

SqlCommand GetEchoProc()
{
    var cmd = new SqlCommand("Echo");
    cmd.Parameters.Add("@s", SqlDbType.VarChar);
    return cmd;
}

Maintenant, si vous invoquez la commande sans paramètre de la @s paramètre, ou de définir sa valeur (CLR) est null, il utilisera par défaut la valeur "bonjour". En revanche, si vous définissez la valeur du paramètre DBNull.Valeur, il sera utilisé et de l'écho DbNull.De la valeur.

Puisqu'il y a deux résultats différents à l'aide de CLR null ou à la base de la valeur null comme valeur de paramètre, vous ne pouvez pas représenter les deux cas avec un seul d'entre eux. Si CLR null devait être le seul, qu'il faudrait travailler à la manière dont DBNull.Valeur d'aujourd'hui. Un moyen d'indiquer au fournisseur "je veux utiliser la valeur par défaut" pourrait alors être de ne pas déclarer le paramètre (un paramètre avec une valeur par défaut bien sûr de sens que pour décrire comme un "paramètre facultatif"), mais dans un scénario où la commande objet est mis en cache et réutilisés, ce qui a suscité la suppression et re-ajout du paramètre.

Je ne suis pas sûr si je pense que DBNull était une bonne idée ou pas, mais beaucoup de gens ne sont pas conscients des choses que j'ai mentionnées ici, donc j'ai pensé qu'il vaut la peine de mentionner.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X