Andres Jaan Tack
Andres Jaan Tack

Reputation: 23024

Why does my successfully-read Npgsql data disappear?

I have the following code shape. It seems that I'm misunderstanding the C# method return values. How is it possible that a "full" enumerator gets returned as an empty one?

class ThingDoer
{
    public NpgsqlDataReader DoQuery()
    {
        NpgsqlCommand c = new NpgsqlCommand(...);
        NpgsqlDataReader dataread = c.ExecuteReader();
        return dataread;  // Debugger confirms that six data are enumerable here.
    }
}

...

class OtherThing
{
    public void higherLevelFunction()
    {
        NpgsqlDataReader result = myThingDoer.DoQuery();
        result.Read();  // No data! result's enumerable returns nothing!
    }
}

Upvotes: 3

Views: 2607

Answers (2)

Zenwalker
Zenwalker

Reputation: 1919

NpgsqlCommand c = new NpgsqlCommand(...);
        NpgsqlDataReader dataread = c.ExecuteReader();

The above lines are very local to the method DoQuery. So as soon as the control comes out of the method, every object created inside to this method loses its scope. Hence you're losing the data because it's a reference type you're referring to in the caller method.

Upvotes: 1

Jon Hanna
Jon Hanna

Reputation: 113342

You don't detail where your connection is coming from. Assuming it's something like:

public NpgsqlDataReader DoQuery()
{
    using(NpgsqlConnection = GetConnectionCode())
    {
        NpgsqlCommand c = new NpgsqlCommand(...);
        NpgsqlDataReader dataread = c.ExecuteReader();
        return dataread;
    }//Connection closes at this using-scope being left because that triggers Dispose()
}

Then change it to:

public NpgsqlDataReader DoQuery()
{
    bool ownershipPassed = false;
    NpgsqlConnection conn = GetConnectionCode();
    try
    {
        NpgsqlCommand c = new NpgsqlCommand(...);
        NpgsqlDataReader dataread = c.ExecuteReader(CommandBehavior.CloseConnection);
        ownershipPassed = true;
        return dataread;
    }
    finally
    {
        if(!ownershipPassed)//only if we didn't create the reader than takes charge of the connection
          conn.Dispose();
    }
}

Then where you use the reader, you have to dispose it to in turn dispose the connection's underlying connection to the database:

public void higherLevelFunction()
{
    using(NpgsqlDataReader result = myThingDoer.DoQuery())
      result.Read();
}

Upvotes: 3

Related Questions