Quel est le point de DBNull?
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?
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 seulobject
peut contenirDBNull
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 ounull
» - 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
ouDataRow.IsNull
- ni qui ont réellement besoinDBNull
d'exister en termes de l'API -
DBNull
échoue en termes de null-coalescence;value ?? defaultValue
ne fonctionne pas si la valeur estDBNull
-
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 desnull
; en particulier,DBNull
est égale à faitDBNull
- 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 seulementnull
- 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 laif(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:
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.