DBNull有什么意义?

在.NET中有空引用,它被用在任何地方都表示一个对象引用是空的,然后是DBNull ,它被数据库驱动程序(和其他几个)用来表示…几乎相同的东西。 当然,这造成了很多混乱,转换程序必须被搅动等等。

那么为什么最初的.NET作者决定做这个? 对我来说没有意义。 他们的文档也没有意义:

DBNull类表示一个不存在的值。 例如,在一个数据库中,一行表中的一列可能不包含任何数据。 也就是说,列被认为根本不存在,而不仅仅是没有价值。 DBNull对象表示不存在的列。 此外,COM互操作使用DBNull类来区分指示不存在的值的VT_NULL变体和指示未指定值的VT_EMPTY变体。

关于“不存在专栏”的这个废话是什么? 列存在,它只是没有一个特定的行的值。 如果它不存在,我会得到一个exception,试图访问特定的单元格,而不是DBNull ! 我可以理解需要区分VT_NULLVT_EMPTY ,但是为什么不COMEmpty类呢? 这将是整个.NET框架中的一个更好的select。

我错过了什么吗? 任何人都可以解释一下为什么DBNull是被发明的,它有什么问题可以帮助解决?

重点是在某些情况下,数据库值为空和.NET空值是有区别的。

例如。 如果使用ExecuteScalar(它将返回结果集中第一行的第一列),并且返回null,这意味着执行的SQL没有返回任何值。 如果返回DBNull,则意味着SQL返回了一个值,它是NULL。 你需要能够分辨差异。

我不同意这里的趋势。 我会logging下来:

我不同意DBNull服务于任何有用的目的; 它增加了不必要的混淆,而几乎没有任何价值。

经常提出这样一个观点,即null是一个无效的引用,而DBNull是一个空对象模式; 这两个都不是真的 例如:

 int? x = null; 

这不是一个“无效的参考”; 它是一个null值。 事实上, null意味着任何你想要的意思,坦率地说,我完全没有问题,使用可能为null (甚至在SQL中,我们需要正确使用null – 这里没有任何更改)。 同样,“空对象模式”只有在你将它当作OOP术语中的一个对象时才有意义,但是如果我们有一个可以是“我们的价值,或者DBNull ”的价值,那么它就一定是object ,所以我们可以不要做任何有用的事情。

DBNull有很多不好的地方:

  • 它强制你使用object ,因为只有object可以保存DBNull 其他值
  • “可能是一个值或DBNull ”vs“可能是一个值或null ”之间没有真正的区别
  • 它源于1.1(前可空types)的论点是没有意义的; 我们可以在1.1中完全使用null
  • 大多数API都有“是空的吗?” 方法,例如DBDataReader.IsDBNullDataRow.IsNull – 其中的任何一个实际上都不需要DBNull就API存在
  • DBNull在空合并方面失败; value ?? defaultValue 如果值为DBNullvalue ?? defaultValue不起作用
  • DBNull.Value不能在可选参数中使用,因为它不是常量
  • DBNull的运行时语义与null的语义相同; 特别是DBNull实际上等于DBNull – 所以它不能完成表示SQL语义的工作
  • 由于过度使用object ,往往会强制将值types值加框
  • 如果你需要testingDBNull ,那么你也可以testing一下null
  • 它会导致大量的问题,如命令参数,一个非常愚蠢的行为,如果一个参数有一个null值它不会被发送…好吧,这里有一个想法:如果你不想要一个参数发送 – 将其添加到参数集合中
  • 每个我能想到的ORM都可以很好地工作,而不需要使用DBNull ,除非在讨论ADO.NET代码

曾经见过的唯一certificate存在这样一个值的非常引人注目的论据是在DataTable ,当传入值来创build一个新行时, null意味着“使用默认值”, DBNull显式为空 – 坦率地说,这个API可能有一个特定的待遇,这种情况下 – 例如一个假想的DataRow.DefaultValue会比引入一个DBNull.Value感染大片的代码没有理由。

同样, ExecuteScalar情况是最好的; 如果你正在执行一个标量方法,你会得到一个结果。 在没有行的情况下,返回null看起来不太可怕。 如果您绝对需要在“无行”和“返回一个空值”之间消除歧义,那么就是阅读器API。

这艘船已经航行很久了,修理它已经太晚了。 但! 请不要以为大家都同意这是一个“明显”的事情。 许多开发商在BCL这个奇怪的折痕看不到价值。

我真的不知道这一切是否源于两件事情:

  • 必须使用单词Nothing而不是VB中涉及“null”的内容
  • 能够使我们的if(value is DBNull)语法,“看起来就像SQL”,而不是如此棘手if(value==null)

概要:

有3个选项( nullDBNull或实际值)只有在需要在3个不同的情况下消除歧义的真实例子时才有用。 我还没有看到我需要表示两个不同的“空”状态的情况,所以DBNull是完全多余的,因为null已经存在,并且具有更好的语言和运行时支持。

DbNull表示没有内容的框; null表示框的不存在。

您使用DBNull丢失数据。 .NET语言中的空值意味着没有指针指向对象/variables。

DBNull缺less数据: http : //msdn.microsoft.com/en-us/library/system.dbnull.value.aspx

统计数据丢失的影响:

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

CLR null和DBNull之间有一些区别。 首先,关系数据库中的null具有不同的“等价”语义:null不等于null。 CLR null等于null。

但我怀疑主要的原因是在SQL服务器和提供者的实现方式参数的默认值的工作方式。

要查看其差异,请创build一个参数具有缺省值的过程:

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

结构良好的DAL代码应该将命令创build与使用分开(以便多次使用相同的命令,例如高效地调用存储过程)。 编写一个返回代表上述过程的SqlCommand的方法:

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

如果您现在调用该命令而不设置@s参数,或者将其值设置为(CLR)null,则将使用默认值“hello”。 另一方面,如果将参数值设置为DBNull.Value,则将使用该值并回显DbNull.Value。

由于使用CLR null或database null作为参数值有两个不同的结果,因此不能仅使用其中的一个来表示两种情况。 如果CLR null是唯一的,那么它必须按照DBNull.Value今天的方式工作。 一种向提供者表明“我想使用默认值”的方法可能是根本不声明参数(当然,默认值的参数对于描述为“可选参数”是有意义的),但是在命令对象被caching和重用的场景会导致删除和重新添加参数。

我不确定我是否认为DBNull是一个好主意,但是很多人都不知道我在这里提到的东西,所以我觉得值得一提。