使用强类型的DataSet中如何处理DBNull

时间:2021-02-08 16:05:36
转自: Abbey的小匣子

使用强类型的DataSet(Typed DataSet),结果遇到了DBNull的难题:

利用IDE生成的DataSet,遇到数据库中某个允许为NULL的字段时,其对应的Property通常为如下形式:

  public string StandardValue {
  get {
    try {
       return ((string)(this[this.tableItems.StandardValueColumn]));
      }
    catch (InvalidCastException e) {
       throw new StrongTypingException("无法获取值,因为它是 DBNull。", e);
      }
    }
   set {
      this[this.tableItems.StandardValueColumn] = value;
  }
}

结果我在使用这个相关的DataSet时,遇到了麻烦,利用DataAdapter从SQL Server 2000的一张表中读取数据时,因其中一行的StandardValue字段为DBNull,于是到上面的return就出现Cast异常。最后不得不做了如下修改:

public string StandardValue {
get {
   try {
     if (this.IsStandardValueNull())
        return string.Empty;
     else
        return ((string)(this[this.tableItems.StandardValueColumn]));
     }
    catch (InvalidCastException e) {
        throw new StrongTypingException("无法获取值,因为它是 DBNull。", e);
     }
 }
set {
      this[this.tableItems.StandardValueColumn] = value;
 }
}

这样问题虽然是得到了初步解决,但这样似乎有点危险。等待进一步思考...

20071017更新

今天又想起了这个问题,于是赶紧翻阅MSDN,又在网上查了查,才发现原来DBNull有如此丰富的处理方式

1. 使用强类型DataSet中强类型的DataRow的IsXXXXNull()方法,其中的XXXX是你设定的列名,判断某列的值是否为DBNull;使用同样的DataRow的SetXXXXNull()方法进行赋值,或者直接使用DBNull类的Value数据属性进行赋值。

2. 通过给强类型的DataSet对应的XML.xsd添加nullValue批注,可以设定当某一列的值为DBNull时,默认的行为或者值。通常情况下,利用VS.Net的IDE生成的DataSet默认的行为是抛出异常。你可以通过设置nullValue批注,实现特定目的:

特定的某个值  在遇到空字段值时,自动向DataSet中的相应成员赋与该特定值
_null        若对应引用类型,则返回空的引用;若对应int等类型,则触发异常
_throw       抛出异常
_empty       若对应string类型,则返回string.Empty;若对应引用类型,则返回一个不带参数构造出的对象;若是int等类型,则触发异常

如何添加nullValue批注,MSDN给了我们一个详尽的例子。首先是添加一个XML引用:
xmlns:codegen="urn:schemas-microsoft-com:xml-msprop"

然后编辑XSD文件,为特定字段添加所需的nullValue批注。同样有现成的MSDN范例:

<?xml version="1.0" encoding="utf-8"?>
<xs:schema id="CustomerDataSet" 
      xmlns:codegen="urn:schemas-microsoft-com:xml-msprop"
      xmlns="" 
      xmlns:xs="http://www.w3.org/2001/XMLSchema" 
      xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
  <xs:element name="CustomerDataSet" msdata:IsDataSet="true">
    <xs:complexType>
      <xs:choice maxOccurs="unbounded">
        <xs:element name="Customers" codegen:typedName="Customer" codegen:typedPlural="Customers">
          <xs:complexType>
            <xs:sequence>
              <xs:element name="CustomerID" codegen:typedName="CustomerID" type="xs:string" minOccurs="0" />
              <xs:element name="CompanyName" codegen:typedName="CompanyName" type="xs:string" minOccurs="0" />
              <xs:element name="Phone" codegen:typedName="Phone" codegen:nullValue="" type="xs:string" minOccurs="0" />
            </xs:sequence>
          </xs:complexType>
        </xs:element>
        <xs:element name="Orders" codegen:typedName="Order" codegen:typedPlural="Orders">
          <xs:complexType>
            <xs:sequence>
              <xs:element name="OrderID" codegen:typedName="OrderID" type="xs:int" minOccurs="0" />
              <xs:element name="CustomerID" codegen:typedName="CustomerID" codegen:nullValue="" type="xs:string" minOccurs="0" />
              <xs:element name="EmployeeID" codegen:typedName="EmployeeID" codegen:nullValue="0" type="xs:int" minOccurs="0" />
              <xs:element name="OrderAdapter" codegen:typedName="OrderAdapter" codegen:nullValue="1980-01-01T00:00:00" type="xs:dateTime" minOccurs="0" />
            </xs:sequence>
          </xs:complexType>
        </xs:element>
      </xs:choice>
    </xs:complexType>
    <xs:unique name="Constraint1">
      <xs:selector xpath=".//Customers" />
      <xs:field xpath="CustomerID" />
    </xs:unique>
    <xs:keyref name="CustOrders" refer="Constraint1" codegen:typedParent="Customer" codegen:typedChildren="GetOrders">
      <xs:selector xpath=".//Orders" />
      <xs:field xpath="CustomerID" />
    </xs:keyref>
  </xs:element>
</xs:schema>