DBNull有什么意义?

Vil*_*lx- 69 .net history dbnull rationale

在.NET中有一个null引用,它在任何地方用来表示对象引用是空的,然后有DBNull数据库驱动程序(和其他几个)用来表示......几乎相同的东西.当然,这会产生很多混乱,转换例程必须被制作出来,等等.

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

DBNull类表示不存在的值.例如,在数据库中,表行中的列可能不包含任何数据.也就是说,该列被认为根本不存在而不仅仅是没有值.DBNull对象表示不存在的列.此外,COM interop使用DBNull类来区分VT_NULL变量(表示不存在的值)和VT_EMPTY变量(表示未指定的值).

什么是关于"不存在的列"的废话?存在一列,它只是没有特定行的值.如果它不存在,我会尝试访问特定的单元格,而不是DBNull!我可以理解区分VT_NULL和之间的必要性VT_EMPTY,但是为什么不做一个COMEmpty类呢?这将是整个.NET框架中更适合的.

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

Mar*_*ell 166

我不同意这里的趋势.我会记录在案:

我不同意DBNull任何有用的目的; 它增加了不必要的混淆,同时几乎没有任何价值.

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

int? x = null;
Run Code Online (Sandbox Code Playgroud)

这不是"无效的参考"; 这是一个null价值.确实null意味着你想要它意味着什么,坦率地说,使用可能的值完全没有问题null(事实上​​,即使在SQL中我们需要正确使用null- 这里没有任何变化).同样,"空对象模式"只有在OOP术语中实际将其视为对象时才有意义,但如果我们有一个可以是"我们的值,或者"的值DBNull那么它必须是object,所以我们不能做任何有用的事情.

有很多不好的事情DBNull:

  • 它迫使你使用object,因为只能object持有DBNull 其他价值
  • "可能是一个值或DBNull"与"可能是一个值或null" 之间没有真正的区别
  • 它源于1.1(可以为空的类型)的论点是没有意义的; 我们可以null在1.1中使用得很好
  • 大多数API都有"它是否为空?" 方法,例如DBDataReader.IsDBNullDataRow.IsNull- 实际上两者都不需要DBNull存在于API方面
  • DBNull在零合并方面失败; value ?? defaultValue如果值是,则不起作用DBNull
  • DBNull.Value 不能在可选参数中使用,因为它不是常量
  • 运行时语义DBNull与语义相同null; 特别是,DBNull实际上是等于DBNull- 所以它不代表 SQL语义
  • 它经常强制将值类型值加载,因为它过度使用 object
  • 如果你需要测试DBNull,你可能也只是测试过null
  • 它会给命令参数等问题带来很大的问题,如果一个参数有一个null值就不会被发送......好吧,这里有一个想法:如果你不想发送参数 - 不要将其添加到参数集合中
  • 每一个ORM我能想到的作品完全良好,没有任何需要或使用的DBNull谈话与ADO.NET代码时,除了作为一个额外的滋扰

唯一的甚至是远程我有说服力的论据曾经看到来证明存在这样的价值是DataTable在价值传递给创建一个新行时,; a null表示"使用默认值",a DBNull显式为null - 坦率地说,这个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.

  • +1,我从来没有遇到过我实际上想要将DBNull.Value与null区分开来的情况.我一直认为这是痛点,并且看到(+经验丰富)由于事实为null而浪费了很多时间!= DBNull.Value (13认同)
  • @Alex没有,没有拼写错误; 并且`DBNull`绝对不等于null; 试试`bool x = DBNull.Value.Equals(DBNull.Value); bool y = DBNull.Value.Equals(null);`.我试图在这里提出的观点是,如果你在ANSI兼容的SQL数据库中尝试,你会发现`null`不等于`null`(但同时,`null`不"不等于" `null`) (5认同)

Col*_*kay 45

关键是在某些情况下,数据库值为null和.NET Null之间存在差异.

例如.如果您使用ExecuteScalar(返回结果集中第一行的第一列)并且您返回null,则表示执行的SQL未返回任何值.如果你得到DBNull,它意味着SQL返回一个值,它是NULL.你需要能够区分它们.

  • 好吧,我想这是一个很好的例子.虽然没有足够的理由来证明制造整个混乱.`ExecuteScalar`可能已被不同地重写以解决这个特殊问题(`DBEmptyRowset`,任何人?) (16认同)
  • 改变一个`ExecuteScalar()`方法与改变所有数据库提供程序,DataSet/Tables/Rows/Columns,数据绑定控件以及其他什么不同?我会选择第一个.在一天结束时,这将使所有代码更加一致.而且简单.此外 - "ExecuteScalar"是数据提供者中使用最少的方法之一.> 90%的案例与DataReader有关.另外 - 你真的认为`bool ExecuteScalar(out object Value)`会不一致吗? (6认同)
  • 我对微软编写ADO.NET的方式感到满意.使用DBNull可以保持一致.只要列值为null,您就会得到一个DBNull.确定要处理的代码可能会比返回一个简单的null更麻烦,特别是如果您所做的只是将DBNull转换为null,但在一天结束时,一致性是关键.如果他们有不同的ExecuteScalar,因为你需要告诉那个场景中的差异,那么它会有更多的震动.当然,这只是我的意见. (2认同)

Rik*_*ous 13

DbNull代表一个没有内容的盒子; null表示盒子不存在.

  • 真?注意详细说明这个?我有点不明白.特别是,因为当你为它指定一个"null"时,变量("盒子")不会消失. (6认同)
  • 如果您将变量视为框的地址 - 那么当您为变量指定null时,您告诉变量该框不再存在.也就是说,地址不是"可访问的". (2认同)