JulianMay / dapper-dot-net

Automatically exported from code.google.com/p/dapper-dot-net
Other
0 stars 0 forks source link

Invalid attempt to call MetaData when reader is closed. #122

Open GoogleCodeExporter opened 8 years ago

GoogleCodeExporter commented 8 years ago
Setup: Create a method that uses a GridReader from QueryMultiple

Steps:
1.Return an empty grid with QueryMultiple
2.Call .Read().ToList() on the empty grid
3.Return a grid containing 1 or more tables with QueryMultiple
4.Call .Read().ToList() on the grid

Expected Outcome: List of objects
Actual Outcome: Invalid attempt to call MetaData when reader is closed.

Product Version: 2.1.267.0
OS Version: Windows 7 Pro and Server 2008 R2 Enterprise 64bit SP1

Additional Info:
This is only a problem when calling .Read().ToList() on an empty GridReader, 
calling .Read<MyGenericClass>() on an empty GridReader does not cause the issue.

Original issue reported on code.google.com by kenith.d...@gmail.com on 11 Nov 2012 at 9:22

GoogleCodeExporter commented 8 years ago
Can you clarify: is this a single SELECT returning 2 grids, one empty one not? 
basically, I want to make sure I can put a suitable repro together

Original comment by marc.gravell on 11 Nov 2012 at 9:31

GoogleCodeExporter commented 8 years ago
In my case it is 3 select statements returning 3 grids, on the first call (Step 
1) all 3 grids are empty and on the second (Step 3) all three grids have some 
rows, does this help?

Original comment by kenith.d...@gmail.com on 11 Nov 2012 at 9:36

GoogleCodeExporter commented 8 years ago
I am also getting this error, except it occurs *sometimes* when doing Query or 
Query<T>. I am having a great deal of difficulty figuring out how to reliably 
reproduce it--it happens for some queries, but not for others. It even varies 
by who is running it. For me it happens at one query (but only in certain 
cases), for another team member with the same code, it happens for another 
query (but also only in certain cases).

It always happens in the same place within dapper, however.

                while (reader.Read())
                {
                    yield return (T)func(reader);
                }

Stepping through it, I see that before reader gets passed, it is open. Soon as 
it is passed in, it is closed. I cannot explain how that happens.

Original comment by smdra...@gmail.com on 27 Nov 2012 at 3:51

GoogleCodeExporter commented 8 years ago
[deleted comment]
GoogleCodeExporter commented 8 years ago
[deleted comment]
GoogleCodeExporter commented 8 years ago
After investigating more, it is caused by the same situation as described by 
kenith. 

1. Run a query which returns 0 rows.
2. Run a query (same query different params) which returns >0 rows.
3. Exception: Invalid attempt to call MetaData when reader is closed.

Original comment by smdra...@gmail.com on 27 Nov 2012 at 4:18

GoogleCodeExporter commented 8 years ago
**** SOLUTION ****

Solved! The cause of the issue is 5 characters.

Line 1527: names[i] = reader.GetName(i + startBound);

This is happening within the "r =>" block. So, it should be:

Line 1527: names[i] = r.GetName(i + startBound);

Essentially, if the first time it runs a query and no rows are returned, it 
will not populate the table variable. The next time it runs the query (and has 
rows), it will try to populate the table variable using the first reader (which 
is now long closed).

-----------

What happens is this: the reader get passed in during QueryInternal on 

line 846: tuple = info.Deserializer = new DeserializerState(hash, 
GetDeserializer(typeof(T), reader, 0, -1, false));

This is the "reader" parameter which was being read on line 1527.

The problem is, the field names aren't pulled until the reader is read for the 
first time on line 854:

                while (reader.Read())
                {
                    yield return (T)func(reader);
                }

then and hits this block

Line 1520:

                r =>
                {
                    if (table == null)
                    {
                        string[] names = new string[effectiveFieldCount];
                        for (int i = 0; i < effectiveFieldCount; i++)
                        {
                            names[i] = r.GetName(i + startBound);
                        }
                        table = new DapperTable(names);
                    }
                    ...

Where r is the current (open) DataReader, and `reader` is the first occurrence 
DataReader used for that hash (if not hit on the first reader, is closed). 

Original comment by smdra...@gmail.com on 27 Nov 2012 at 4:34

GoogleCodeExporter commented 8 years ago
This issue is fixed on GitHub: 
https://github.com/SamSaffron/dapper-dot-net/commit/06aa5cfc5637c48c194c130e65f0
7a8c50809d28

Original comment by pchuch...@gmail.com on 31 Jan 2013 at 12:15

GoogleCodeExporter commented 8 years ago
Should this issue be fixed also on the google code repository?
Or do we have to consider the github repository the official one and forget 
about google code?

Original comment by zocra...@gmail.com on 1 Feb 2013 at 5:10