简体   繁体   English

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

[英]Check if read() has been called on SqlDataReader

I'm writing some helper functions that take a SqlDataReader and process the results. 我正在编写一些带有SqlDataReader并处理结果的辅助函数。 Now normally you'd structure the loop like so: 现在通常你会像这样构造循环:

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

But I my be passing the function a reader which is already positioned on a row, and in this case I want it to process the current row. 但是我将函数传递给已经位于一行的读者,在这种情况下我希望它处理当前行。 The code above will only output the entire result set if read() had not been called prior to invoking the function. 如果在调用函数之前未调用read(),则上面的代码将仅输出整个结果集。

I want the function to do something like this: 我希望函数做这样的事情:

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

_dataReady is an actual member of SqlDataReader and seems to do what I need, however it's private! _dataReady是SqlDataReader的实际成员,似乎做我需要的,但它是私有的! Surely there's a way to determine if the reader is positioned on an actual row, short of trying to read the field and catching the exception. 当然有一种方法可以确定读者是否位于实际行上,而不是尝试读取字段并捕获异常。

why not just subclass SqlDataReader, and create Read() method? 为什么不只是子类SqlDataReader,并创建Read()方法? I have it in all my projects, now: 我现在在所有项目中都有它:

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

Reflection is dangerous but often useful. 反思很危险但通常很有用。 Here is an extension 这是一个扩展

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);
 }

Information taken from SqlDataReader referencesource . SqlDataReader referencesource获取的信息。

You can use the FieldCount property. 您可以使用FieldCount属性。 As per the documentation , it returns zero if not positioned in a valid recordset. 根据文档 ,如果没有放在有效的记录集中,它将返回零。

Some other solutions: 其他解决方案:

  1. Do your Read() looping entirely outside of your helper method (and always operate only on the current row) Read()循环完全放在helper方法之外(并且始终只在当前行上运行)

  2. Do your Read() looping entirely within the helper method, and always pass it fresh data readers that have not been advanced 完全在辅助方法中进行Read()循环,并始终传递尚未提升的新数据读取器

  3. Do your first Read() outside of the data reader, continue Read() looping within the helper method, and always assume that the data reader has been advanced to the first record. 在数据读取器外部执行第一个Read() ,在helper方法中继续Read()循环,并始终假设数据读取器已前进到第一个记录。

  4. Probably overkill: write a wrapping implementation of IDataReader that forwards all calls to the underlying data reader (probably passed in via the constructor), but exposes a property indicating whether Read has ever been called. 可能是矫枉过正:编写IDataReader的包装实现,它将所有调用转发给底层数据读取器(可能通过构造函数传入),但是公开了一个属性,指示是否曾调用过Read。

It is sort of overloading the purpose, but the following should work: 它有点超载的目的,但以下应该工作:

rowExists = reader.FieldCount > 0;

I suspect that you are going to find yourself having problems with a design that has you doing Read()s in different locations in your code. 我怀疑你会发现自己遇到了一个设计问题,你在你的代码中的不同位置做了Read()。 Try doing only data manipulation in your method (and passing it as an IDataRecord instead of an IDataReader ), and leave the record traversal logic to the caller. 尝试在您的方法中仅进行数据操作(并将其作为IDataRecord而不是IDataReader传递),并将记录遍历逻辑留给调用者。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM