检查DataRow是否包含特定列的最佳实践

75

目前,当我遍历DataRow实例时,我会这样做。

foreach(DataRow row in table)
  return yield new Thingy { Name = row["hazaa"] };

迟早(即迟)我会让表格缺少列驴子,到时候麻烦就来了。经过一些广泛的谷歌搜索(约30秒),我发现了以下保护语法。

foreach(DataRow row in table)
  if(row.Table.Columns.Contains("donkey"))
    return yield new Thingy { Name = row["hazaa"] };
  else
    return null;

现在 - 这就是最简单的语法吗?!真的吗?我希望有一种方法可以在字段存在时获取该字段,否则返回null。或者至少直接在row上提供Contains方法。

我是否漏掉了什么?我将用这种方式映射许多字段,所以代码看起来将非常难读...

6个回答

132
你可以创建一个扩展方法来使它更清晰简洁:
static class DataRowExtensions
{
    public static object GetValue(this DataRow row, string column)
    {
        return row.Table.Columns.Contains(column) ? row[column] : null;
    }
}

现在按以下方式调用:

foreach(DataRow row in table)
    return yield new Thingy { Name = row.GetValue("hazaa") };

这是一个不错的解决方案。不确定为什么它没有得到更多的赞同。无论如何,我给它点赞。 - Konrad Viltersten
哇!一个非常整洁的解决方案。谢谢! - Segmentation Fault
1
不错!但在实际应用中,还应该检查rowcolumn的值是否正确。 - Erk

22

由于您的DataTable表始终具有相同的列(对于任何行都不会改变),因此您只需要一次检查列名。

if (table.Columns.Contains("donkey"))
{
    foreach ...
}

这对于一个列来说很好,但是正如OP所说,最终会有许多列,如果您不知道哪些可能存在,哪些可能不存在,那么您将如何管理它们? - Varun K
@Varun,我肯定不会保留固定字符串。如果列'hazaa'不存在了,你会怎么做? - Heslacher
@Heslacher 这就是重点。有时候我需要管理这一列,有时候又不需要。我对此没有控制权,但仍然需要进行管理。您的示例适用于单个列,并且可以推广到多个列。但请注意,问题是是否存在除您提供的通过表进行检查的语法之外的其他检查语法。 - Konrad Viltersten

11

我真的很喜欢@Varun K.采取的方法。因此,以此为出发点,我只想提供我的建议,以防对其他人有所帮助。我仅仅是改进了它,使其成为通用而不仅仅是使用对象作为返回类型。

static class Extensions
{
  public static T Get<T>(this DataRow self, string column)
  {
    return self.Table.Columns.Contains(column)
      ? (T)self[column]
      : default(T);
    }
  }
}

应该给予应有的荣誉。但是你的回答有很大的改进,我选择重新接受它作为新的正确答案。我还稍微修改了一下,将名称更改为更抽象的名称以适应其通用性。希望没问题。 - Konrad Viltersten
感谢您澄清了积分应该归属的位置。此外,我非常感激您自作主张使方法变得更好。我相信这就是我们的想法。要拥有代码并尝试每次都让它更好。 - Sebastian Inones
2
如果你试图从一个不存在的列中获取整数值,这可能会导致误导性的结果。该方法将返回0,这可能会让某些人认为该列存在并且字段包含有效值0。 - vargonian

8

在Varun K的回答基础上,使用一个通用类型参数:

public static T GetValue<T>(this DataRow row, string column)
{
    if (!row.Table.Columns.Contains(column))
        return default(T);

    object value = row[ColumnName];
    if (value == DBNull.Value)
        return default(T);
    return (T)value;
}

4
foreach (DataColumn item in row.Table.Columns)
{
    switch (item.ColumnName)
    {
        case "ID":
            {
                p.ID = Convert.ToInt32(row[item.ColumnName].ToString());
            }
            break;
        case "firstName":
            {
                p.firstName = row[item.ColumnName].ToString();
            }
            break;
        case "lastName":
            {
                p.lastName = row[item.ColumnName].ToString();
            }
            break;

        default:
            break;
    };
}

这实际上非常适合我所需的。 (虽然我不是很喜欢它,但我认为我找不到更好的选择...) - Grant Birchmeier

2
有时候一个列名可能存在,但是行并没有包含该列的数据;例如,在使用 ReadXML 填充 DataTable 之后。
一个简单、快速和安全的解决方案是使用类型检查:
if(row["columnname"].GetType() != typeof(System.DBNull)){
    //DataRow contains "columname"
}else{
    //a safe scope to set default cell data
}

1
我觉得这个问题仍然能够得到新的回答、点赞和评论,这让我感到很兴奋。毕竟这个问题已经被提出(并回答)了整整七年,不到一周时间。我想知道用户是如何在搜索中找到它的。自从这个问题被提出以来,EF 接管了它,并与 Dapper 和 nHybernate 一起消除了它的相关性,我认为应该是这样的。你是怎么偶然发现它的呢?(此外,对于它的新角度加一分。) - Konrad Viltersten

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接