在.NET中有null
引用,它在任何地方用于表示对象引用为空,然后有DBNull
,数据库驱动程序使用它(和其他几个)表示......几乎是一样的东西。当然,这会产生很多混乱,转换程序也必须被淘汰等等。
那么为什么最初的.NET作者决定这样做呢?对我来说没有任何意义。他们的文档也没有意义:
DBNull类表示不存在的值。例如,在数据库中,表行中的列可能不包含任何数据。也就是说,该列被认为根本不存在而不仅仅是没有值。 DBNull对象表示不存在的列。此外,COM interop使用DBNull类来区分VT_NULL变量(表示不存在的值)和VT_EMPTY变量(表示未指定的值)。
关于“不存在的列”的废话是什么?存在一列,它只是没有特定行的值。如果它不存在,我会尝试访问特定的单元格,而不是DBNull
!我可以理解需要区分VT_NULL
和VT_EMPTY
,但为什么不改为成为COMEmpty
类呢?在整个.NET框架中,这将更加适合。
我错过了什么吗?任何人都可以解释为什么发明DBNull
以及它有助于解决哪些问题?
答案 0 :(得分:164)
我不同意这里的趋势。我会记录在案:
我不同意
DBNull
有任何有用的目的;它增加了不必要的混淆,同时几乎没有任何价值。
经常提出这样的论点:null
是一个无效的引用,而DBNull
是一个空的对象模式; 既不是真的。例如:
int? x = null;
这不是“无效的参考”;它是null
值。确实null
意味着你想要它意味着什么,坦率地说,使用可能null
的值完全没有问题(事实上,即使在SQL中我们需要正确使用null
- 这里什么都没改变。同样,“空对象模式”只有在OOP术语中实际将其视为对象时才有意义,但如果我们的值可以是“我们的值,或DBNull
”那么它必须是{ {1}},所以我们不能对它做任何有用的事情。
object
有很多不好的事情:
DBNull
,因为只有object
可以保留object
或其他值DBNull
”与“可能是值或DBNull
”null
null
或DBDataReader.IsDBNull
- 这些方法实际上都不需要DataRow.IsNull
存在于API DBNull
在空合并方面失败;如果值为DBNull
value ?? defaultValue
无效
DBNull
不能在可选参数中使用,因为它不是常量DBNull.Value
的运行时语义与DBNull
的语义相同;特别是,null
实际上等于DBNull
- 所以它不完成表示SQL语义的工作DBNull
object
,您可能只测试了DBNull
null
则不会被发送......好吧,这里有一个想法:如果你不这样做想要发送参数 - 不要将它添加到参数集合 null
的情况下都能很好地工作,除非在与ADO.NET代码交谈时造成额外的麻烦唯一甚至远程引人注目的论据,我曾经认为可以证明这种价值的存在是DBNull
,传递值时创建一个新行; DataTable
表示“使用默认值”,null
明确为空 - 坦率地说,此API可能已针对此案例进行了特定处理 - 例如假想DBNull
会更好而不是引入一个无条件感染大量代码的DataRow.DefaultValue
。
同样,DBNull.Value
场景充其量也是微不足道的;如果您正在执行标量方法,则期望结果。在没有行的情况下,返回ExecuteScalar
似乎并不太可怕。如果你绝对需要消除“无行”和“返回一个单独”之间的歧义,那就是阅读器API。
这艘船很久以前就已经航行了,修理它已经太晚了。但!请不认为每个人都同意这是一个“显而易见”的事情。很多开发人员不看到BCL这个奇怪的皱纹中的价值。
我真的想知道所有这些都源于两件事:
null
而不是VB中涉及“null”的内容Nothing
语法,而不是非常棘手的if(value is DBNull)
要点:
有3个选项(if(value==null)
,null
或实际值)仅在有真实示例需要消除3种不同情况之间的歧义时才有用。我还没有看到我需要表示两个不同的“空”状态的情况,因此DBNull
完全是冗余的,因为DBNull
已经存在并且具有更好的语言和运行时支持。
答案 1 :(得分:45)
关键是在某些情况下,数据库值为null和.NET Null之间存在差异。
例如。如果您使用ExecuteScalar(返回结果集中第一行的第一列)并且您返回null,则表示执行的SQL未返回任何值。如果你得到DBNull,它意味着SQL返回一个值,它是NULL。你需要能够分辨出来。
答案 2 :(得分:13)
DbNull
表示没有内容的框; null
表示该盒子不存在。
答案 3 :(得分:1)
您使用DBNull来丢失数据。 .NET语言中的Null意味着没有对象/变量的指针。
DBNull缺少数据:http://msdn.microsoft.com/en-us/library/system.dbnull.value.aspx
缺少数据对统计数据的影响:
答案 4 :(得分:0)
CLR null和DBNull之间存在一些差异。首先,关系数据库中的null具有不同的“等于”语义:null不等于null。 CLR null IS等于null。
但我怀疑主要原因是参数默认值在SQL服务器中的工作方式以及提供程序的实现方式。
要查看差异,请使用具有默认值的参数创建过程:
CREATE PROC [Echo] @s varchar(MAX) = 'hello'
AS
SELECT @s [Echo]
结构良好的DAL代码应该将命令创建与使用分开(以允许多次使用相同的命令,例如,有效地多次调用存储过程)。编写一个返回表示上述过程的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或数据库null作为参数值有两个不同的结果,因此不能仅使用其中一个表示两种情况。如果CLR null是唯一的那个,它必须以DBNull.Value今天的方式工作。向提供者指示“我想使用默认值”的一种方法可能是根本不声明参数(具有默认值的参数当然有意义地描述为“可选参数”),但是在在缓存和重用命令对象的情况下,这会导致删除并重新添加参数。
我不确定我是否认为DBNull是个好主意,但很多人都不知道我在这里提到的事情,所以我觉得值得一提。
答案 5 :(得分:0)
要回答您的问题,您必须考虑为什么DBNull甚至存在?
在狭窄的用例中,DBNull是必需的。否则,事实并非如此。大多数人从不需要DBNull。我绝对不允许将它们输入我设计的数据存储中。我总是有一个值,因此我的数据永远不会是“
在一种情况下,您可能需要DBNull ...如果您使用某些SQL统计功能(例如:中位数,平均值)..他们特别对待DBNull。.请看一下这些文档..某些功能不会在统计信息的总计数中包括一个DBNull ...例如:(87总和/ 127总和)(87总和/ 117总和)..区别在于这些列值中有10个是DBNull ...您可以看到这会改变统计结果。
我不需要使用DBNull设计数据库。如果我需要统计结果,我会为该项目明确发明或添加一列,例如“ UserDidProvideValue”,因为该项目不存在,因此需要某种特殊处理(例如,我的总数为117,即为标记字段的总和) UserDidProvideValue = true)...哈哈哈哈-在我下一世作为宇宙的统治者时-决不会允许DBNull逃离SQL领域...整个编程世界现在担负着检查所有事情的重担...何时您是否曾经有一个移动应用程序或台式机应用程序或网站需要一个“空”整数? -从来没有...