使用强类型的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>