Behaviour of SQL statement RaiseError with DataSets and IDataReaders

A developer at work queried me to why RaiseError generates an exception when working with a DataSet but not when working with an IDataReader. Here is a short code fragement that demonstrates the problem.

 

using System;

using System.Data;

using System.Data.SqlClient;

 

class TestRaiseError

{

      static void Main(string[] args)

      {

            SqlConnection connection = new SqlConnection("server=myServer;database=northwind;uid=sa;pwd=password");

            SqlCommand command = new SqlCommand("select * from Employees RAISERROR ('raise an error', 16, 1)", connection);

            IDataReader reader = null;

            try

            {

                  connection.Open();

                  reader = command.ExecuteReader();

                  while (reader.Read())

                  {

                        Console.WriteLine(reader.GetString(1));

                  }

            }

            finally

            {

                  if (reader != null)

                  {

                        reader.Close();

                  }

                  if (connection != null)

                  {

                        connection.Close();

                  }

            }          

      }

}

 

If you compile and run the code fragment you’ll see no exception is thrown yet the sql statement being executed contains a raise error. If the program was rewritten to use a DataSet and a SqlDataAdpater then an exception would be thrown.

 

This behaviour may seem a little strange but it is by design. It is very important to remember that the an IDataReader represents an active connection to the database and records from the database will be retrieved in turn where as a dataset grabs all results from a query and places them in the clients memory.

 

It is possible to return a number of different results sets from a stored procedure, when using an IDataReader these are accessed using .NextResult(). Interestingly the ADO.NET client treats RaiseError as separate results set and it is this that can lead to slightly surprising results. This means that if you have a stored procedure something like:

 

SELECT * FROM myTable

 

RAISERROR ('raise an error', 16, 1)

 

Then it is possible to read all the contents of myTable with out ever seeing the exception because you need to call .NextResult() to see the exception that is raised.

 

As the DbDataAdapter that fills the DataSet is written to enumerate over all results sets  from the query so the exception from the RaiseError is picked up.

 

I’ve create a small winfoms application which demonstrates all the situations described in here. It is available here.

Bookmark
dotnetkicks+, digg+, reddit+, del.icio.us+, dzone+, facebook+

Print | posted @ Thursday, June 10, 2004 12:15 PM

Comments on this entry:

No comments posted yet.

Your comment:

(Note: all comments are moderated so it may take sometime to appear)

Title:
Name:
Email:
Website:
 
Italic Underline Blockquote Hyperlink
 
 
Please add 2 and 6 and type the answer here:
 

Links

 Subscribe in a reader
Twitter Follow me on Twitter
FaceBook View my Facebook
LinkedIn View my LinkedIn Profile Viadeo Viadeo Profile (Français)

Badges


Disclaimer

The views expressed on this weblog are mine and do not necessarily reflect the views of my employer.

All postings are provided "AS IS" with no warranties, and confer no rights.


follow robertpi at http://twitter.com