如何处理所有DBNull而不是每次都检查它们(使用生成的DataSet)?

时间:2012-08-26 13:08:18

标签: c# .net dbnull

正如@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?

2 个答案:

答案 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值来捕获空值。