I have created a stored procedure similar to this simplified example:
CREATE PROCEDURE dbo.sp_MyStoredProcedure
@Var1 INT OUTPUT,
@Var2 DECIMAL(10,2) OUTPUT
AS
BEGIN
SET NOCOUNT ON;
SELECT
@Var1 = COUNT(*),
@Var2 = SUM(TranAmount)
FROM
MyTable
SELECT * FROM MyTable
END
When I try to read the values from the output variables after I call the ExecuteReader()
method of the SqlCommand
object, the values are null.
string MyConnString = string.Empty;
SqlConnection MyConn = new SqlConnection(MyConnString);
SqlCommand MyCmd = new SqlCommand("sp_MyStoredProcedure", MyConn);
MyCmd.CommandType = CommandType.StoredProcedure;
MyCmd.Parameters.Add(new SqlParameter("@Var1", SqlDbType.Int));
MyCmd.Parameters.Add(new SqlParameter("@Var2", SqlDbType.Decimal);
MyCmd.Parameters[0].Direction = ParameterDirection.Output;
MyCmd.Parameters[1].Direction = ParameterDirection.Output;
SqlDataReader dr = MyCmd.ExecuteReader(CommandBehavior.CloseConnection);
int Var1 = Convert.ToInt32(MyCmd.Parameters[0].Value);
decimal Var1 = Convert.ToDecimal(MyCmd.Parameters[1].Value);
What I am doing wrong?
You need to read the reader till end, the output parameters are at the end of the TDS stream and the client won't see them until the result set isn't consumed.
If you must have the count and sum before you read the resultset you must ditch the OUTPUT params. Just produce an ordinary result set with the two values you're interested in folowed buy the SELECT * result set. Then read both result sets in the client using SqlDataReader.NextResult().
Update
Here is what I mean by having two results set:
CREATE PROCEDURE dbo.sp_MyStoredProcedure
AS
BEGIN
SET NOCOUNT ON;
SELECT COUNT(*) as cnt, SUM(TranAmount) as sum_ta
FROM MyTable
SELECT * FROM MyTable
END
and the client:
string MyConnString = string.Empty;
SqlConnection MyConn = new SqlConnection(MyConnString);
SqlCommand MyCmd = new SqlCommand("sp_MyStoredProcedure", MyConn);
MyCmd.CommandType = CommandType.StoredProcedure;
using(SqlDataReader dr = MyCmd.ExecuteReader(CommandBehavior.CloseConnection))
{
while(dr.Read())
{
count = dr["cnt"];
sum = dr["sum_ta"];
}
dr.NextResult();
while(dr.Read())
{
// process MyTable row here
}
}
Note that you do not need to do this if your C# code does not need the value of the output parameters before consuming the data reader. You can simply read the SqlDataReader till end and then check the output parameters, they will be set.