我已经看到了两种检查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可能不得不对每列执行表扫描,这可能会非常慢。
思想?
答案 0 :(得分: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;
}
这种方法的优点是它更简单并且可以让您更好地控制。另外,请注意,您可能希望查看不区分大小写或假名不敏感的比较,这会使事情变得有点棘手。
答案 1 :(得分:1)
很大程度上取决于你如何使用HasColumn。你只是召唤一次或两次,还是反复循环?该列是否可能存在或者提前完全未知?
设置行过滤器可能每次都会进行表扫描。 (另外,从理论上讲,GetSchemaTable()可以在每次调用时生成一个全新的表,这会更加昂贵 - 我不相信SqlDataReader会这样做,但是在IDataReader级别,谁知道呢?)但是如果你只是称之为一次或两次我无法想象这是一个很大的问题(除非你有数千列或其他东西)。
(但是,我会至少将GetSchemaTable()的结果存储在方法中的本地var中,以避免在快速连续中调用它两次,如果没有将其缓存在特定IDataReader重新生成它的某个地方。)
如果您事先知道在正常情况下您要求的列将存在,则异常方法更加可口(因为实际上,不存在列的情况是例外情况)。即使不是,它可能表现稍好一些,但除非你反复调用它,否则你应该问问自己性能是否真的非常重要。
如果你反复调用它,你可能应该考虑一种不同的方法,例如:预先调用GetSchemaTable(),循环遍历表,并将字段名称加载到Dictionary或其他一些结构中。专为快速查找而设计。
答案 2 :(得分:0)
我不担心性能影响。即使你有一个包含1000列的表(这将是一个巨大的表),你仍然只进行1000行的“表扫描”。这可能是微不足道的。
过早优化只会引导您走向不必要的复杂实施。实现最适合您的版本,然后衡量性能影响。如果与您的性能要求相比是不可接受的,那么请考虑替代方案。