简体   繁体   中英

ExecuteScalar returns 0 executing a stored procedure

I'm refactoring a C# program that calls a stored procedure that ends with:

SELECT @ResultCode AS ResultCode

The C# code looks like this:

SqlDbCommand.CommandType = System.Data.CommandType.StoredProcedure;
SqlDbCommand.CommandText = "PR_Foo";

SqlDbCommand.Parameters.Clear();
SqlDbCommand.Parameters.Add("@Foo", SqlDbType.Char);  
SqlDbCommand.Parameters["@Foo"].Value = 'Foo';

System.Data.SqlClient.SqlDataAdapter SqlDbAdapter = new System.Data.SqlClient.SqlDataAdapter();
System.Data.DataSet SQLDataSet = new System.Data.DataSet();
SqlDbAdapter.SelectCommand = SqlDbCommand;
SqlDbAdapter.Fill(SQLDataSet);
SQLDataSet.Tables[0].TableName = "PR_Foo";

if (SQLDataSet.Tables.Count != 0) {
       Result = int.Parse(SQLDataSet.Tables[SQLDataSet.Tables.Count - 1].Rows[0][0].ToString());
}

With the above code, Result is correctly populated with the value returned by the
stored procedure.

Refactoring the code with a simpler ExecuteScalar :

SqlDbCommand.CommandType = System.Data.CommandType.StoredProcedure;
SqlDbCommand.CommandText = "PR_Foo";

SqlDbCommand.Parameters.Clear();
SqlDbCommand.Parameters.Add("@Foo", SqlDbType.Char); 
SqlDbCommand.Parameters["@Foo"].Value = 'Foo';

Result = (int)SqlDbCommand.ExecuteScalar(); 

the Result value is oddly set to 0 while the expected result should be an integer value greater than zero.

Do you know what could be the cause of this strange behavior?

Note:

the stored procedure has several if blocks, returning result values lower than zero in case of particular checks; these cases are correctly handled by the ExecuteScalar().

The problem raises when the stored procedure does its job correctly, committing the transactions of the various updates and returning the Result value at the end.

I also encountered this problem. In my opinion it is very relevant. So I decided to give here the correct sample of code.

    SqlCommand cmd2 = new SqlCommand();
    cmd2.Connection = conn;
    cmd2.CommandType = System.Data.CommandType.StoredProcedure;
    cmd2.CommandText = "dbo.Number_Of_Correct";

    SqlParameter sp0 = new SqlParameter("@Return_Value", System.Data.SqlDbType.SmallInt);
    sp0.Direction = System.Data.ParameterDirection.ReturnValue;
    SqlParameter sp1 = new SqlParameter("@QuestionID", System.Data.SqlDbType.SmallInt);

    cmd2.Parameters.Add(sp0);
    cmd2.Parameters.Add(sp1);

    sp1.Value = 3;

    cmd2.ExecuteScalar();     // int Result = (int)cmd2.ExecuteScalar();  trowns System.NullReferenceException
    MessageBox.Show(sp0.Value.ToString());

In the event of multiple tables being returned your two piees of code aren't doing the same thing. Your original code takes the first field of the first row of the last table whereas the execute scalar will take the first field of the first row of the first table. Could this be where your problem lies?

What you seem to want is the first column of the first row of the last result-set . Unfortunately, if you have multiple select statements in your procedure, thereby generating more than one result-set, an ExecuteScalar is only going to get the first column of the first row of the first result-set .

Your first block of C# code checks the last table in the dataset which would (correctly) be associated with the last select statement in the procedure.

如果您有多个可能的结果集,并且可能存在歧义,则可以考虑将存储过程更改为使用输出参数,而不是@ResultCode上的select。

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM