检查是否已在SqlDataReader上调用read()

时间:2012-02-21 23:44:38

标签: c# .net sql

我正在编写一些带有SqlDataReader并处理结果的辅助函数。现在通常你会像这样构造循环:

while(reader.read()){
    // Read fields
}

但是我将函数传递给已经位于一行的读者,在这种情况下我希望它处理当前行。如果在调用函数之前未调用read(),则上面的代码将仅输出整个结果集。

我希望函数执行以下操作:

if(!reader._dataReady)
    rowExists = reader.read() // Read 
while(rowExists){
    // read fields
    rowExists = reader.read()
}

_dataReady是SqlDataReader的实际成员,似乎可以做我需要的,但它是私有的!当然,有一种方法可以确定读者是否位于实际行上,而不是尝试读取字段并捕获异常。

4 个答案:

答案 0 :(得分:2)

为什么不只是继承SqlDataReader,并创建Read()方法?我现在在我的所有项目中都有它:

public class SafeDataReader : IDataReader, SqlDataReader
{
    public IDataReader reader {get;set;}
    public int GetInt32(string aFieldName, int aDefault);
    public int? GetInt32Nullable(string aFieldName);
    .... 
}

答案 1 :(得分:1)

您可以使用FieldCount属性。根据{{​​3}},如果没有位于有效的记录集中,它将返回零。

其他一些解决方案:

  1. Read()循环完全放在辅助方法之外(并且始终只在当前行上运行)

  2. 在帮助程序方法中完成Read()循环 ,并始终传递未提升的新数据读取器

  3. 在数据阅读器之外做第一个Read(),在助手方法中继续Read()循环,并始终假设数据阅读器已经前进到第一个记录。

  4. 可能过度杀戮:写一个IDataReader的包装实现,它将所有调用转发给底层数据读取器(可能通过构造函数传入),但是暴露了一个属性,指示是否曾调用过Read。

    < / LI>

答案 2 :(得分:1)

反思很危险但通常很有用。这是一个扩展

public static bool? DataReady(this SqlDataReader rd) {
            var sharedState = rd.GetType()?.GetField("_sharedState", 
                 BindingFlags.NonPublic | BindingFlags.Instance)?.GetValue(rd);
            return (bool?)sharedState?.GetType().GetField("_dataReady",
                BindingFlags.NonPublic | BindingFlags.Instance)?.GetValue(sharedState);
 }

SqlDataReader referencesource获取的信息。

答案 3 :(得分:0)

这有点超载了目的,但以下情况应该有效:

rowExists = reader.FieldCount > 0;

我怀疑你会发现自己遇到了一个设计问题,你在你的代码中的不同位置做了Read()。尝试在方法中仅进行数据操作(并将其作为IDataRecord而不是IDataReader传递),并将记录遍历逻辑留给调用者。