DBNull有什么意义?
在.NET中有空引用,它被用在任何地方都表示一个对象引用是空的,然后是DBNull
,它被数据库驱动程序(和其他几个)用来表示…几乎相同的东西。 当然,这造成了很多混乱,转换程序必须被搅动等等。
那么为什么最初的.NET作者决定做这个? 对我来说没有意义。 他们的文档也没有意义:
DBNull类表示一个不存在的值。 例如,在一个数据库中,一行表中的一列可能不包含任何数据。 也就是说,列被认为根本不存在,而不仅仅是没有价值。 DBNull对象表示不存在的列。 此外,COM互操作使用DBNull类来区分指示不存在的值的VT_NULL变体和指示未指定值的VT_EMPTY变体。
关于“不存在专栏”的这个废话是什么? 列存在,它只是没有一个特定的行的值。 如果它不存在,我会得到一个exception,试图访问特定的单元格,而不是DBNull
! 我可以理解需要区分VT_NULL
和VT_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.IsDBNull
或DataRow.IsNull
– 其中的任何一个实际上都不需要DBNull
就API存在 -
DBNull
在空合并方面失败;value ?? defaultValue
如果值为DBNull
则value ?? defaultValue
不起作用 -
DBNull.Value
不能在可选参数中使用,因为它不是常量 -
DBNull
的运行时语义与null
的语义相同; 特别是DBNull
实际上等于DBNull
– 所以它不能完成表示SQL语义的工作 - 由于过度使用
object
,往往会强制将值types值加框 - 如果你需要testing
DBNull
,那么你也可以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个选项( null
, DBNull
或实际值)只有在需要在3个不同的情况下消除歧义的真实例子时才有用。 我还没有看到我需要表示两个不同的“空”状态的情况,所以DBNull
是完全多余的,因为null
已经存在,并且具有更好的语言和运行时支持。
DbNull
表示没有内容的框; null
表示框的不存在。
您使用DBNull丢失数据。 .NET语言中的空值意味着没有指针指向对象/variables。
DBNull缺less数据: http : //msdn.microsoft.com/en-us/library/system.dbnull.value.aspx
统计数据丢失的影响:
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是一个好主意,但是很多人都不知道我在这里提到的东西,所以我觉得值得一提。