ADO.NET has the SqlCommand and SqlConnection objects to allow the user to invoke the SP and have access to the results returned by the SP. Specifically, there are 3 methods that can be used to execute a query or an SP on the database :
- SqlCommand.ExecuteNonQuery() : Used for queries which don't return any value, i.e. insert, update and delete queries
- SqlCommand.ExecuteScalar() : Used for queries which are guaranteed to return a single value
- SqlCommand.ExecuteReader() : Used for queries that return multi column and/or multi row result sets
There is 1 important difference in the use of these 3 methods when it comes to accessing return values. It turns out that when using ExecuteScalar() and ExecuteNonQuery(), we can access the return value immediately following this method call whereas, for the ExecuteReader() method this is not the case. If we try to access the value of the parameter object created for the return value, it will have a null value. The return value is set only after we iterate through the entire result set returned by the reader object. The reasoning behind this behaviour can be as follows. If the result set was returned successfully, it means the SP succeeded so there's no point of checking the return value. It only makes sense to check the return value in case there was no result returned. The return value will then enable us to determine whether there was actually no data in the database for the given query or there is a bug which caused incorrect results to be returned.
Do keep this slight variation in the behaviour of the ExecuteReader() the next time you use it.