IDataReader和"HasColumn",最佳方法?

Fly*_*wat 6 c# ado.net idatareader

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

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

要么:

public bool HasColumn(IDataReader reader, string columnName)
{

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

    return (reader.GetSchemaTable().DefaultView.Count > 0);
}
Run Code Online (Sandbox Code Playgroud)

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

但是,在大型数据集上,我认为RowFilter可能不得不对每列执行表扫描,这可能会非常慢.

思考?

Sam*_*ron 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;
}
Run Code Online (Sandbox Code Playgroud)

这种方法的优点是它更简单,并为您提供更好的控制.另外,请注意,您可能希望查看不区分大小写或假名不敏感的比较,这会使事情变得有点棘手.


Eri*_*ger 1

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

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

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

如果您事先知道在正常情况下您要求的列将会存在,则异常方法会更容易接受(因为实际上不存在该列是一种例外情况)。即使没有,它的性能可能会稍好一些,但除非您反复调用它,否则您应该问自己性能是否真的那么重要。

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