I know that the usually recommended way to fill a DataSet instance from a stored procedure is to use SqlDataAdapter.Fill(DataSet). Every answer I’ve been able to find says to use it the way it comes out of the box. I’ll grant that normally, it works great.
However, it breaks down when you need to do processing of the data between the stored procedure output and the DataSet input. Specifically, when using a custom CLR type in the output, it breaks with InvalidOperationException: DataReader.GetFieldType(n) returned null. where n is the column index of the column (in one of the tables; there seems to be no obvious way of telling which table the column index references) which uses the CLR type in its output. This is understandable, since the reader has no idea what kind of data is in the column in question.
I can break out the deserialization logic of the CLR type and use it in both places, but I don’t seem to have time to call any such deserialization method before Fill() breaks down.
I know about SqlCommand.ExecuteReader(), but can only seem to get a single table out of that one.
The CLR type in question is designed to replace one of the core system fields (which is currently stored as free-form text) with something a little more stringent. The question of going through the database and adding a method call to every single returned instance of such a field has been discussed as a possibility but would definitely be a non-trivial amount of work. So it was thought that the conversion could be done in the DAL instead (only requiring that such columns can be identified programmatically, which is doable), making storage transparent to the client and client use of the data still transparent to the database.
Thus: How do I get access to all the tables in the stored procedure output, without using SqlDataAdapter.Fill()? Alternatively, how do I hook into the execution of SqlDataAdapter.Fill() to do manual processing between execution of the SP and the populating the DataSet?
You can select multiple tables with a
DataReader. You can usereader.NextResultto check if there are more resultsets and to advance the data reader to it: