Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I implement a Peek() function on a DataReader?

Tags:

c#

.net

ado.net

There doesn't seem to be a Peek method on the DataReader in ado.net. I would like to be able to perform some one-off processing before I loop through my reader, and it would be nice to be able to look at the data in the first row without causing it to be skipped by the subsequent iteration. What is the best way to accomplish this?

I am using a SqlDataReader, but preferably the implementation would be as general as possible (i.e. apply to IDataReader or DbDataReader).

like image 457
Gabe Moothart Avatar asked May 21 '09 17:05

Gabe Moothart


People also ask

Which method returns an DataReader object?

As you've seen in the previous examples, you call the ExecuteReader method of the Command object, which returns an instance of the DataReader.

Which one is the method of DataReader object?

A DataReader parses a Tabular Data Stream from Microsoft SQL Server, and other methods of retrieving data from other sources. A DataReader is usually accompanied by a Command object that contains the query, optionally any parameters, and the connection object to run the query on.

Which is the main method of DataReader in VB net?

The Read() method in the DataReader is used to read the rows from DataReader and it always moves forward to a new valid row, if any row exist . There are two types of DataReader in ADO.NET. They are SqlDataReader and the OleDbDataReader. The System.

How does SqlDataReader work in C#?

SqlDataReader objects allow you to read data in a fast forward-only manner. You obtain data by reading each row from the data stream. Call the Close method of the SqlDataReader to ensure there are not any resource leaks.


1 Answers

I would suggest something similar to Jason's solution, but using a wrapper that implements IDataReader instead, so:

sealed public class PeekDataReader : IDataReader
{
    private IDataReader wrappedReader;
    private bool wasPeeked;
    private bool lastResult;

    public PeekDataReader(IDataReader wrappedReader)
    {
        this.wrappedReader = wrappedReader;
    }

    public bool Peek()
    {
        // If the previous operation was a peek, do not move...
        if (this.wasPeeked)
            return this.lastResult;

        // This is the first peek for the current position, so read and tag
        bool result = Read();
        this.wasPeeked = true;
        return result;
    }

    public bool Read()
    {
        // If last operation was a peek, do not actually read
        if (this.wasPeeked)
        {
            this.wasPeeked = false;
            return this.lastResult;
        }

        // Remember the result for any subsequent peeks
        this.lastResult = this.wrappedReader.Read();
        return this.lastResult;
    }

    public bool NextResult()
    {
        this.wasPeeked = false;
        return this.wrappedReader.NextResult();
    }

    // Add pass-through operations for all other IDataReader methods
    // that simply call on 'this.wrappedReader'
}

Note that this does require quite a bit of pass-through code for all the unaffected properties, but the benefit is that it is a generic abstraction that can 'peek' at any position in the result set without moving forward on the subsequent 'read' operation.

To use:

using (IDataReader reader = new PeekDataReader(/* actual reader */))
{
    if (reader.Peek())
    {
        // perform some operations on the first row if it exists...
    }

    while (reader.Read())
    {
        // re-use the first row, and then read the remainder...
    }
}

Note though that every 'Peek()' call will actually move to the next record if the previous operation was not also a 'Peek()'. Keeping this symmetry with the 'Read()' operation provides a simpler implementation and a more elegant API.

like image 104
jerryjvl Avatar answered Sep 20 '22 12:09

jerryjvl