views:

323

answers:

3

Hi,

I'm getting the following error whenever my code creates a DataTableReader from a valid DataTable Object:

"DataTableReader is invalid for current DataTable 'TempTable'."

The thing is, if I reboot my machine, it works fine for an undetermined amount of time, then dies with the above. The code that throws this error could have been working fine for hours and then: bang. you get this error. It's not limited to one line either; it's every single location that a DataTableReader is used. Also, this error does NOT occur on the production web server - ever.

This is an example of one of the lines where it falls over: alt text

If I step over this line, I get this: alt text

However, if I do this in the immediate window:

alt text

alt text

I get no problems. Same goes if I actually use that line in the code.

This has been driving me nuts for the best part of a week, and I've failed to find anything on Google that could help (as I'm pretty positive this isn't a coding issue).

Some technical info:

DEV Box: Vista 32bit (with all current windows updates) Visual Studio 2008 v9.0.30729.1 SP dotNet Framework 3.5 SP1

SQL Server: Microsoft SQL Server 2005 Standard Edition- 9.00.4035.00 (X64) Windows 2003 64bit (with all current windows updates)

Web Server: Windows 2003 64bit (with all current windows updates)

any help, ideas, or advice would be greatly appreciated!

Cheers, Ian

UPDATE 1:

Ok - Have tried the following now with no success:

1: Rebooted 2: SFC / ScanNow 3: Changed SQL Servers 4: Tried a different method that uses DataTableReaders 5: Cleaned solution

The only thing I did find that worked was copy & pasting the code from the main Visual studio instance, into another which had a simple console app. This then worked as expected (queried database and got results into a dataTable, created a datatablereader on that table, then queried hasrows before calling .Read()... All of which worked.

I am struggling to see what could cause this, as there are NO code faults - i'm 100% certain, as it runs perfectly when published to the webserver.

UPDATE 2

OK.. here's a bit more funkiness:

This block of code fails on the final line shown (tr.HasRows) as we already know:

alt text

However, the first line calls into this method:

alt text

Which in turn, calls this method:

alt text

Within this last method, I've simply added a bit of code at the bottom to create a DataTableReader from the DataTable we are about to return, and try the "HasRows" call to see if the same issue would occur...

and it doesn't!

If you step through the code, it creates the reader, sees that it has rows, set's dtr = dtr, returns the datatable to the "getWarehouse" function, which in turn returns the table to the calling code... which then gets the original error.

I know it's not the greatest code, but it should work.. especially as it works a bit lower in the stack!

+1  A: 

Wrap usage of DataTableReader (and all IDisposables) with using.

Andrew Bezzub
that's not really going to help. I create the object, close the object and dispose the object.. as displayed in the code example above.
Sk93
It is going to help to avoid other problems - if exceptions occurres before you close the reader it will remain unclosed. Using statements can help to avoid this.
Andrew Bezzub
That's not quite true. If it throws an exception and goes out of scope, then it'll get closed and disposed via the garbage collecton as normal. But yes, the using statement is the better way forward, and I normally use them. However, this code is "old" code written by another developer.. and it used to work fine. Thanks for the pointer, but what I'm after here is a solution to the problem detailed... Hope you understand :)
Sk93
@Sk93: Yes, it will *eventually* get garbage collected, but in the meantime the connection will remain open. At some point your connection pool is going to be overflowing. Which might result in weird errors like you've seen. The best practice is to use "using" on ANYTHING that implements IDisposable to avoid this type of problem.
Chris Lively
+1 for suggesting the 'using'
JayD
@Chris Lively: I completely understand this - in my own code, I would of course use "using" wherever practicle, for precisely the reasons you state. But this code works fine on every other machine it's been tested on. It has been running on a client machine almost continuously for over a year without fault (and is still continuing without fault). I cant see how this can have anything to do with connection pools, as this is only the second database connection made in the entire lifecycle of the product.
Sk93
OK. To put this suggestion to rest: I have gone through the method and altered it to use "using" wherever it uses an object that implements IDisposable. I have also gone into to two methods it calls and done the same there - ALL connections, dataAdapters, DataTables and DataTableReaders within the callstack for this block of code are now written using "using" blocks.I have also made this the first line of code called by the application as it starts up. Until this line fires, there have been zero connections to the database ..... and the problem persists exactly as described.
Sk93
+1  A: 

I think using the while(reader.read()) may solve your problem.

if (myReader.HasRows)
   while (myReader.Read())
     Console.WriteLine("\t{0}\t{1}", myReader.GetInt32(0), myReader.GetString(1));
else
   Console.WriteLine("No rows returned.");
myReader.Close();

UPDATE: Also from msdn: The HasRows property returns information about the current result set. If the DataTableReader contains multiple result sets, you can examine the value of the HasRows property immediately after you call the NextResult method in order to determine whether the new result set contains rows.

Use the HasRows property to avoid the requirement to call the Read method of the DataTableReader if there are no rows within the current result set.

DataTableReader.HasRows Property

JayD
I was under the impression that OP said it was the call to HasRows that was failing?
Mitch Wheat
Correct. in your example, (myReader.HasRows) is the line that is throwing the exception.
Sk93
A: 

OK.. Further down in the code, I have the following code:

using (DataTableReader tr = dtCustomers.CreateDataReader())
{
    ....
}

If I change this to read:

using (DataTableReader tr2 = dtCustomers.CreateDataReader())
{
    ....
}

Then, and remember this bit of code is much later down in the same procedure, BOTH bits of code work without fault!

So, this doesn't work:

using (DataTableReader tr = dt.CreateDataReader())
{
    ...
}

....

using (DataTableReader tr = dt.CreateDataReader())
{
    ...
}

But this does:

using (DataTableReader tr = dt.CreateDataReader())
{
    ...
}

....

using (DataTableReader tr2 = dt.CreateDataReader())
{
    ...
}

I don't understand why this way works, but it does and as I've not had another answer, I'll be going with this.

If you know why this works, and why the original doesn't, please can you enlighten me? :)

Sk93