正如@nicholas正确指出的那样,我的原始问题有点误导,因为这个案例有点具体。
所以这是真正的问题:
我创建了带有DataGridView控件的Windows窗体应用程序和从我的生产数据库中的表生成的DataSource。
我的程序的目标是查看表,可选地编辑注释列并将表数据导出到XML文件,该模式严格定义了XSD和我无法更改的其他独立约束。
如果未定义某些值,请务必不要在XML输出文件中插入一些字段。
明确表示我不能为这些字段插入空标记。这就是我需要空值的原因。仅在给定值的位置插入XML标记。这就是我需要DBNull值而不是任何其他默认值的原因。
生成的DataSet包含在访问DBNull值时抛出异常的getter。我无法更改生成的代码,这是一条规则,您不会更改生成的代码,尤其是可能(并且会被覆盖)的代码。
我通过用“try / catch”块包围可空字段的每个赋值来解决这个问题。如果生成的getter抛出异常,我的XML对象的可空字段将保留它的默认空值,这是我预期的行为。
稍后 - 我的XML构造函数将在生成XML输出时跳过这些字段。
但仍存在一个问题:为什么它必须如此丑陋?如果我有一百个可空的字段怎么办?我是否必须写一百个“try / catch”块?对我来说,这似乎是整个Microsoft机制中的一个错误。或者也许这是一个简单而优雅的解决方案?
- 以下是原始内容,以了解第一个答案的来源:
拜托,我知道我可以检查DBNull的每个字段,但必须 是程序员的自动方式。这将是最愚蠢的事情 在整个.NET / C#中 - 必须编写“if”或“try / catch”语句 我巨大的桌子的每一列!我试着在桌子上使用“foreach” 行类型,但它没有工作。在例外情况下抛出异常 开始“foreach”的身体,似乎我甚至试图触摸DBNull, 抛出异常。如果我将整个代码块放在里面 “try / catch” - 它不会起作用,因为它会跳过后面的所有字段 第一个DBNull。
必须有一种方法可以做到这一点,而不会让几十个人变得很难看 检查我的代码。那么,行的魔术是什么呢 DBNulls?
答案 0 :(得分:0)
写一个扩展名:
public static T GetValue<T>(this IDataRecord @this, string name, T defaultValue = default(T))
{
int ordinal = @this.GetOrdinal(name));
return @this.GetValue<T>(ordinal, defaultValue);
}
public static T GetValue<T>(this IDataRecord @this, int ordinal, T defaultValue = default(T))
{
return @this.IsDBNull(ordinal) ? defaultValue : (T)@this.GetValue(ordinal);
}
像这样使用它:
connstr = @"Data Source=.\sqlexpress;Integrated Security=SSPI;Initial Catalog=Test;";
string sql = "select WidgetId, WidgetName, WidgetValue, CreatedDt, ModifiedDt from dbo.widgets";
using (connection = new SqlConnection(connstr))
{
connection.Open();
using (command = new SqlCommand(sql, connection))
using (IDataReader reader = command.ExecuteReader())
{
while (reader.Read())
{
Console.Write(reader.GetValue<int>("WidgetId").ToString());
Console.Write("\t");
Console.Write(reader.GetValue<string>("WidgetName"));
Console.Write("\t");
Console.Write(reader.GetValue<int>("WidgetValue"));
Console.Write("\t");
Console.Write(reader.GetValue<DateTime>("CreatedDt"));
Console.Write("\t");
Console.Write(reader.GetValue<DateTime>("ModifiedDt"));
Console.Write("\n");
}
}
}
结果:
1 Widget 1 0 7/17/2012 6:13:26 AM 1/1/0001 12:00:00 AM
2 Widget 2 0 7/17/2012 6:13:26 AM 1/1/0001 12:00:00 AM
3 Widget 3 0 7/17/2012 6:13:26 AM 1/1/0001 12:00:00 AM
答案 1 :(得分:0)
在从服务器检索DbNull值之前,通过修改SQL select查询来调用IsNull
(或者在Access后端Nz
的情况下),删除它们。 Definition here
string sql = "select WidgetId, IsNull(WidgetName,""), " +
"IsNull(WidgetValue,0), CreatedDt, ModifiedDt from dbo.widgets";
假设您有某种适当的默认值,或者稍后使用sentinel值来捕获空值。