6

我已经看到了两种常见的方法来检查 IDataReader 中是否存在列:

public bool HasColumn(IDataReader reader, string columnName)
{
  try
  {
      reader.getOrdinal(columnName)
      return true;
  }
  catch 
  {
       return false;
  }
}

或者:

public bool HasColumn(IDataReader reader, string columnName)
{

    reader.GetSchemaTable()
         .DefaultView.RowFilter = "ColumnName='" + columnName + "'";

    return (reader.GetSchemaTable().DefaultView.Count > 0);
}

就个人而言,我使用了第二个,因为我讨厌为此使用异常。

但是,在大型数据集上,我相信 RowFilter 可能必须对每列进行一次表扫描,这可能非常慢。

想法?

4

3 回答 3

5

我想我对这颗古老的宝石有一个合理的答案。

我会采用第一种方法,因为它更简单。如果您想避免异常,您可以缓存字段名称并在缓存上执行 TryGet。

public Dictionary<string,int> CacheFields(IDataReader reader)
{

    var cache = new Dictionary<string,int>();
    for (int i = 0; i < reader.FieldCount; i++)
    {
        cache[reader.GetName(i)] = i;
    }
    return cache;
}

这种方法的好处是它更简单,并为您提供更好的控制。另外,请注意,您可能想研究不区分大小写或不区分假名的比较,这会使事情变得有点棘手。

于 2009-07-14T01:05:37.253 回答
1

很大程度上取决于您如何使用 HasColumn。您是只调用一次或两次,还是在循环中重复调用它?该列可能存在还是事先完全未知?

设置行过滤器可能每次都会进行表扫描。(此外,理论上,GetSchemaTable() 可以在每次调用时生成一个全新的表,这会更加昂贵——我不相信 SqlDataReader 会这样做,但在 IDataReader 级别,谁知道呢?)但如果你只调用一次或两次我无法想象这是一个那么大的问题(除非你有成千上万的列或其他东西)。

(但是,我至少将 GetSchemaTable() 的结果存储在方法内的本地 var 中,以避免快速连续调用它两次,如果不将其缓存在某个地方,那么您的特定 IDataReader 确实会重新生成它。)

如果你事先知道在正常情况下你要求的那一列会出现,那么异常方法就更可口了(因为不存在的那一列,其实是个例外)。即使没有,它的性能也可能会稍微好一些,但是除非你反复调用它,否则你应该问问自己性能是否真的那么重要。

如果你重复调用它,你可能应该考虑另一种方法,例如:调用 GetSchemaTable() 一次,循环遍历表,并将字段名称加载到字典或其他一些专为快速设计的结构中查找。

于 2009-01-09T23:22:47.167 回答
0

我不会担心性能影响。即使您有一个包含 1000 列的表(这将是一个巨大的表),您仍然只进行 1000 行的“表扫描”。这很可能是微不足道的。

过早的优化只会引导您进行不必要的复杂实现。实施您认为最好的版本,然后衡量性能影响。如果与您的性能要求相比它是不可接受的,那么请考虑替代方案。

于 2009-05-21T20:05:20.003 回答