强类型数据表/数据集中的可空类型 - 解决方法?

时间:2010-07-29 21:55:04

标签: c# dataset extension-methods nullable strongly-typed-dataset

强类型DataTable支持“可空”字段类型,但设计器不允许您将设置更改为任何值类型字段的“允许空值”。 (即:字符串类型允许为空,但int不允许)。

解决方法是在您想要获取Myfield时调用IsMyFieldNull()。如果在包含null的情况下访问MyField,则会抛出一个eception。

这是一个巨大的麻烦,除了在显示null时可能导致应用程序崩溃时导致许多运行时错误。多年来我一直向微软抱怨这一点,但是每个新版本的visual studio仍然不允许使用可空的值类型。

我的问题:任何人都知道可以用来解决这个主要缺点的花哨的扩展方法吗?

7 个答案:

答案 0 :(得分:7)

如果您使用的是.Net 3.5或更高版本,这些扩展程序可能对您有用: http://msdn.microsoft.com/en-us/library/system.data.datarowextensions.field.aspx

根据文档,它完全支持可空类型。它允许您使用

之类的结构
MyRow.Field<int?>("MyField") 

如果您将其分配给正确类型的现有变量或从现有变量分配,编译器可以自动推断出类型,您可以省略类型说明符,使其缩短为

int? myVar = MyRow.Field("MyField");
MyRow.Field("MyField") = myVar;

仍然不完美,但比在任何地方使用IsMyFieldNull()等更容易辨认。

哦,如果你想在拼写错误的列名方面做得更安全,你可以使用像

这样的东西
MyRow.Field(MyTable.MyFieldColumn)

不要忘记添加对 System.Data.DataSetExtensions 的引用。

答案 1 :(得分:2)

在VS 2008中,您只需在nullvalue属性中输入“0”即可 如果您使用的是vs2005,则必须使用XML编辑器。 您必须将msprop:nullValue="0"作为属性添加到列中。

答案 2 :(得分:1)

我同意允许可以为空的类型是一个很好的功能。

如果将列上的“NullValue”属性设置为“-1”而不是“(抛出异常)”,则当列为空而不是抛出异常时,属性将返回-1。您仍然必须将列设置为允许空值。

或者,您始终可以将数据类型设置为“System.Object”,并允许nulls = true。您可以访问该列的值,而无需使用“IsMyFieldNull()”方法。当列为null时,列的值将为“System.DbNull.Value”。如果您不喜欢使用“System.DbNull.Value”,则可以将“NullValue”属性设置为“(Nothing)”而不是“(抛出异常)”,然后将该对象与空引用进行比较。

答案 3 :(得分:0)

你可以这样做: 将AllowDbNull设置为true,如果未设置; DefaultValue保持打开状态; NullValue保持打开(抛出异常)。然后从代码中想要设置为null的列时,可以使用内置方法Set_Column_Null()。 看看我的例子:

if (entry.PosX.HasValue)
    newRow.PosX = entry.PosX.Value;
else
    newRow.SetPosXNull(); 

答案 4 :(得分:0)

我必须为此找到解决办法。我需要更改为ASP.NET 2.0编写的网页旧代码。该页面使用菜单控件Telerik RadMenu。此组件要求根元素具有适当的DBNull值(对于parentID)。 因此,当我编译旧代码时,RadMenu组件给了我很多问题。关于约束的第一个例外,然后它不明白哪个元素是根元素,整个事情看起来很糟糕。

但我解决了这个问题,这对我有用。

在Table Adapter设计器的ParentID列的Properties页面中,我使用了:   - AllowDBNull:true   - DefaultValue:-1(-1是该列通常不会发生的值) NullValue-property留在“Throw Exception”,因为我无法改变。

在使用表适配器值的代码中,我使用了这个构造(VB.NET代码,而不是C#,因为这个问题被标记了):

Dim MenuBarTable As DAL.Page.MenuBarDataTable 'The Table Adapter
MenuBarTable = PageObj.GetMenuBar()  'The generated Get function 
MenuBarTable.ParentIDColumn.AllowDBNull = True 

    For Each row As Page.MenuBarRow In MenuBarTable.Rows
        If row.IsParentIDNull() Then 
            row.SetParentIDNull() 
        End If
    Next

为表适配器生成的代码为每个应该允许DBNULL的列生成两个函数。它们意味着在处理NULL时使用,但它是微软的一个笨拙的解决方案。幕后发生的事情是表适配器将从Get函数输出列的DefaultValue而不是NULL。我称之为“模拟NULL”或“假NULL”。

函数IsParentIDNull()实际上将检查该行是否包含此“假NULL”,例如列的DefaultValue,当它的时候,我正在使用SetParentIDNull()函数插入一个正确的DBNull。

这个解决方案对我有用,但不是很优雅,也不是非常有效,但我希望它对其他人有帮助。

答案 5 :(得分:-1)

我不确定为什么var x = !IsMyFieldNull() ? MyField : null(或类似的)是如此头疼。

我想你可以在SqlDataReader周围编写一个包装器,以便在将数据读入DataTable时以某种方式捕获这些空值,或者为查询编写等效的.TryParse():这样的东西很好并封装如下: / p>

var x = myDataTable.TryParse(myField);

其中.TryParse是一个类似于:

的扩展方法
public static TryParse(DataRow myField)
{
    if(!myField == DbNull) //Or similar
       return myField.Value;
}

正如你所看到的,这基本上是伪代码粗略的,但你明白了。编写一次代码,然后将其称为扩展方法。

答案 6 :(得分:-2)

在.net 3.0中引入了可空类型,这些可以与数据集一起使用。你可以像这样声明一个可以为空的int int? myNullableInt = null 以下是MSDN文章的链接:Nullable Types C#

就个人而言,我首先要避开数据库中的空值(如果你有这样做的话)。 NULL实际上允许“未定义”或“未知”状态。很少有这个问题,例如,包含Surname的字符串字段通常会设置为可空,而默认为“”将是一个更好的选择。将空值放入数据库会使事情变得不必要Null Values In Databases,此外它会将空值传播到代码中,您必须努力避免空引用异常。

不幸的是,互联网上写了很多关于数据库的不好的东西(例如过度使用null就好了)。这些观点通常是那些真正不理解它们背后的理论的人,另一个经典的例子是没有关系的DB,“因为它在代码中处理这些更灵活/更快”。这意味着开发人员必须重新编写现有的[数据库层]功能,数据库不可避免地能够更有效地处理并具有更高的可靠性。我说不可避免,因为当然,正在进行重写的开发人员正在重新实现Oracle / Microsoft / Whoever让大型团队花费大量时间优化等等的东西。但是每隔一段时间,你就会看到有人提倡这样做一个设计。这个家伙真正了解数据库,DBDebunkings他花了很多时间试图揭穿大量无意义的句子,使关系数据库远离其理论根源。

相关问题