Question

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

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

  

La classe DBNull représente une valeur inexistante. Dans une base de données, par exemple, une colonne dans une ligne d'une table peut pas contenir de données que ce soit. Autrement dit, la colonne est considéré comme ne pas exister du tout au lieu de simplement ne pas avoir une valeur. Un objet DBNull représente la colonne inexistante. En outre, COM interop utilise la classe DBNull de faire la distinction entre un variant de VT_NULL, ce qui indique une valeur nulle, et une variante de VT_EMPTY, ce qui indique une valeur non spécifiée.

Quelle est cette merde sur une « colonne non existant »? Une colonne existe, il n'a tout simplement pas de valeur pour la ligne particulière. Si elle n'existait pas, je reçois une exception en essayant d'accéder à la cellule spécifique, pas un DBNull! Je peux comprendre la nécessité de faire la différence entre VT_NULL et VT_EMPTY, mais pourquoi ne pas faire une classe COMEmpty à la place? Ce serait un ajustement beaucoup plus de plus propre dans l'ensemble du cadre .NET.

Am quelque chose que je manque? Quelqu'un peut-il faire la lumière pourquoi DBNull a été inventé et quels sont les problèmes qu'il aide à résoudre?

Était-ce utile?

La solution

Le fait est que dans certaines situations, il y a une différence entre une valeur de base de données étant nulle et une Null .NET.

Par exemple. Si vous en utilisant ExecuteScalar (qui retourne la première colonne de la première ligne du jeu de résultats) et vous obtenez un retour null qui signifie que le SQL exécuté ne renvoyaient pas de valeur. Si vous obtenez DBNull retour, cela signifie une valeur a été renvoyée par le SQL et il était NULL. Vous devez être en mesure de faire la différence.

Autres conseils

Je vais être en désaccord avec la tendance ici. Je vais aller sur le dossier:

  

Je ne suis pas d'accord que DBNull soit utile; il ajoute une confusion inutile, tout en contribuant pratiquement aucune valeur.

L'argument est souvent mis en avant que null est une référence non valide, et que DBNull est un modèle d'objet nul; n'est vrai . Par exemple:

int? x = null;

ce n'est pas une « référence non valide »; il est une valeur null. En effet des moyens null tout ce que vous voulez qu'il signifie, et franchement, je n'ai absolument aucun problème à travailler avec des valeurs qui peuvent être null (en effet, même dans SQL nous devons travailler correctement avec null - rien ne change ici). De même, le « modèle d'objet nul » n'a de sens que si vous traitez en fait comme un objet en termes de POO, mais si nous avons une valeur qui peut être « notre valeur, ou DBNull » alors il doit être object, afin que nous puissions « t accomplirez quelque chose d'utile avec elle.

Il y a tellement de mauvaises choses avec DBNull:

  • il vous oblige à travailler avec object, puisque seul object peut contenir DBNull ou une autre valeur
  • il n'y a pas de différence réelle entre « pourrait être une valeur ou DBNull » vs « pourrait être une valeur ou null »
  • l'argument selon lequel il découle de 1,1 (pré-nullables-types) est sans signification; nous pourrions utiliser null parfaitement dans 1.1
  • la plupart des API ont « est-il null? » méthodes, par exemple DBDataReader.IsDBNull ou DataRow.IsNull - ni qui ont réellement besoin DBNull d'exister en termes de l'API
  • DBNull échoue 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 il est une constante
  • la sémantique d'exécution de DBNull sont identiques à la sémantique des null; en particulier, DBNull est égale à fait DBNull - il ne pas faire le travail de représentation de la sémantique SQL
  • il force souvent des valeurs de type valeur à boxed car elle sur les utilisations 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 commande-paramètres, avec un comportement très stupide que si un paramètre a une valeur null il n'est pas envoyé ... eh bien, voici une idée: si vous ne voulez pas un paramètre envoyé - ne pas ajouter à la collection de paramètres
  • tous les ORM je peux penser fonctionne parfaitement bien sans tout le besoin ou l'utilisation de DBNull, sauf une nuisance supplémentaire quand on parle du code ADO.NET

La seule même à distance argument convaincant J'ai jamais vu pour justifier la existence d'une telle valeur est exprimée en DataTable, lors du passage en les valeurs pour créer une nouvelle ligne; un moyen de null « utiliser la valeur par défaut », un DBNull est explicitement une valeur nulle - franchement cette API aurait eu un traitement spécifique pour ce cas - un DataRow.DefaultValue imaginaire par exemple serait beaucoup mieux que l'introduction d'un DBNull.Value qui contamine de vastes pans entiers de code pour ne raison.

De même, le scénario est ExecuteScalar ... ténu; si vous exécutez une méthode scalaire, vous attendre un résultat. Dans le scénario où il n'y a pas de lignes, retour null ne semble pas trop terrible. Si vous absolument besoin de désambiguïser entre « aucune ligne » et « un seul nul retour », il y a l'API lecteur.

Ce navire a navigué depuis longtemps, et il est beaucoup trop tard pour y remédier. Mais! S'il vous plaît faire pas pense que tout le monde convient quec'est une chose « évidente ». De nombreux développeurs font pas voir la valeur dans cette ride étrange sur la BCL.

Je me demande en fait, si tout cela découle de deux choses:

  • avoir à utiliser le mot Nothing au lieu de quelque chose qui implique « null » dans VB
  • être en mesure de nous la syntaxe if(value is DBNull) qui "ressemble SQL", plutôt que la if(value==null) oh-so-délicat

Résumé:

Avoir 3 options (null, DBNull, ou une valeur réelle) est utile que s'il y a un exemple authentique où vous devez lever l'ambiguité entre 3 différents cas. Je dois encore voir une occasion où je dois représenter deux différents états « nuls », donc DBNull est redondant entièrement, étant donné que null existe déjà et a beaucoup mieux prise en charge linguistique et l'exécution.

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

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

DBNull les données manquantes: http://msdn.microsoft. com / fr-fr / bibliothèque / system.dbnull.value.aspx

Les effets des données manquantes sur les statistiques:

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

Il y a quelques différences entre un nul CLR et un DBNull. Tout d'abord, null dans des bases de données relationnelles a différentes « équivaut à » sémantique: nul n'est pas égal à zéro. CLR nul est égal à zéro.

Mais je soupçonne que la raison principale est de faire avec le paramètre de manière valeurs par défaut dans le serveur SQL travail et la mise en œuvre du fournisseur.

Pour voir la différence, créez 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]

Code DAL bien structuré devrait séparer la création de commande d'utilisation (pour activer en utilisant la même commande plusieurs fois, par exemple pour appeler une procédure stockée plusieurs fois de manière efficace). Ecrivez une méthode qui renvoie un SqlCommand représentant la procédure ci-dessus:

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

Si vous appelez la commande maintenant sans régler le paramètre @s ou définissez sa valeur (CLR) null, il utilisera la valeur par défaut « bonjour ». Si d'autre part vous définissez la valeur du paramètre à DBNull.Value, il utilisera et que l'écho DBNull.Value.

Comme il y a deux résultats différents en utilisant null CLR ou base de données null en tant que valeur de paramètre, vous ne pouvez pas représenter les deux cas avec un seul d'entre eux. Si nul CLR devait être le seul, il faudrait travailler la façon dont DBNull.Value fait aujourd'hui. Une façon d'indiquer au fournisseur « Je veux utiliser la valeur par défaut » pourrait alors être de ne pas déclarer le paramètre du tout (un paramètre avec une valeur par défaut bien sûr est logique de décrire comme un « paramètre optionnel »), mais dans un scénario dans lequel l'objet de commande est mise en mémoire cache et réutilisé cela ne conduit à la suppression et re-ajoutant le paramètre.

Je ne suis pas sûr si je pense que DBNull était une bonne idée ou non, mais beaucoup de gens ne connaissent pas les choses que je l'ai mentionné ici, donc je me suis dit qu'il vaut mentionner.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top