在.net中有 null 参考,到处都用来表示对象引用为空,然后有 DBNull, ,数据库驱动程序(以及其他很少的)用来表示……几乎是同一件事。自然,这会造成很多混乱和conversion依的例程,等等。

那么,为什么原始.NET作者决定做到这一点呢?对我来说,这没有道理。他们的文档也没有道理:

dbnull类代表不存在的值。例如,在数据库中,表格中的一行可能不包含任何数据。也就是说,该列被认为根本不存在,而不仅仅是没有值。 dbnull对象表示不存在的列。此外,com Interop使用dbnull类来区分vt_null变体,该变体表示不存在的值和vt_empty变体,该变体表示未指定的值。

关于“不存在的列”的这个废话是什么?存在列,它只是没有特定行的值。如果不存在,我会有一个例外试图访问特定单元,而不是 DBNull呢我可以理解有必要区分 VT_NULLVT_EMPTY, ,但是那时为什么不做一个 COMEmpty 上课?在整个.NET框架中,这将是一个更整洁的。

我想念什么吗?任何人都可以阐明为什么 DBNull 被发明了,解决哪些问题?

有帮助吗?

解决方案

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

例如。如果您使用executeScalar(在结果集中返回第一行的第一列),并且您将获得无效,这意味着执行的SQL执行没有返回任何值。如果您将dbnull退回,则意味着SQL返回了一个值,而为空。您需要能够分辨出区别。

其他提示

我将不同意这里的趋势。我会记录下来:

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

通常提出的论点是 null 是无效的参考 DBNull 是一个空对象模式; 都不是真的. 。例如:

int? x = null;

这不是“无效的参考”;它是一个 null 价值。的确 null 意味着您想要的意思是什么,坦率地说,我绝对没有问题 null (的确,即使在SQL中,我们也需要正确地使用 null - 这里没有任何变化)。同样,“ null对象模式”仅在您实际上以OOP术语为对象的情况下才有意义 DBNull“那一定是 object, ,所以我们不能对此有用。

有很多坏事 DBNull:

  • 它迫使您与 object, ,因为只有 object 能把持住 DBNull 或者 另一个值
  • “可能是一个值或 DBNull“ vs”可能是一个值或 null"
  • 它源于1.1(预先撤消类型)的论点毫无意义。我们可以使用 null 在1.1中完全很好
  • 大多数API都“无效?”例如,方法 DBDataReader.IsDBNull 或者 DataRow.IsNull - 实际上都不需要 DBNull 根据API存在
  • DBNull 在无效钙化方面失败; value ?? defaultValue 如果值是 DBNull
  • DBNull.Value 不能在可选参数中使用,因为它不是常数
  • 运行时语义的语义 DBNullnull;尤其是, DBNull 实际上等于 DBNull - 所以 才不是 做代表SQL语义的工作
  • 它通常会迫使价值值,因为它过度使用 object
  • 如果您需要测试 DBNull, ,您最好仅测试 null
  • 它会给命令参数等事情带来巨大的问题,并且非常愚蠢的行为,如果参数有一个 null 值它没有发送...好吧,这是一个想法:如果您不需要发送参数 - 不要将其添加到参数集合中
  • 我能想到的每个ORM都能很好地工作 任何 需要或使用 DBNull, ,除了与ADO.NET代码交谈时作为额外的滋扰

唯一的 甚至远程 令人信服的论点我 曾经 看出是合理的 存在 这样的价值 DataTable, ,当传递值创建新行时;一个 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语言中的null表示对象/变量没有指针。

DBNULL缺少数据: 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 Server中的参数默认值和提供商的实现有关。

要查看差异,请创建一个具有默认值的参数:

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或DATABASE NULL作为参数值有两个不同的结果,因此您不能仅用其中一种代表两种情况。如果clr null是唯一的一个,那么它必须按照dbnull.value今天的方式工作。向提供商表示“我要使用默认值”的一种方法可能是完全不声明参数(当然,具有默认值的参数当然可以被描述为“可选参数”),而是在一个命令对象被缓存和重复使用的方案确实会导致删除和重新添加参数。

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

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top