ExecuteScalar возвращает 0 при выполнении хранимой процедуры - PullRequest
1 голос
/ 09 августа 2011

Я выполняю рефакторинг программы на C #, которая вызывает хранимую процедуру, которая заканчивается на:

SELECT @ResultCode AS ResultCode

Код C # выглядит следующим образом:

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());
}

С приведенным выше кодом, Result правильно заполняется значением, возвращаемым хранимой процедурой
.

Рефакторинг кода с использованием более простого 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(); 

значение Result установлено странным образом0, в то время как ожидаемый результат должен быть целочисленным значением, большим нуля.

Знаете ли вы, что может быть причиной этого странного поведения?

Примечание:

хранимая процедура имеет несколько блоков if, возвращая значения результата ниже нуля в случае определенных проверок;эти случаи правильно обрабатываются ExecuteScalar ().

Проблема возникает, когда хранимая процедура выполняет свою работу правильно, фиксируя транзакции различных обновлений и возвращая значение Result в конце.

Ответы [ 4 ]

4 голосов
/ 31 октября 2012

Я также столкнулся с этой проблемой. На мой взгляд это очень актуально. Поэтому я решил привести здесь правильный пример кода.

    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());
4 голосов
/ 09 августа 2011

В случае возврата нескольких таблиц ваши два куска кода не делают одно и то же. Ваш исходный код занимает первое поле первой строки таблицы last , тогда как скаляр выполнения займет первое поле первой строки таблицы first . Может ли это быть, где ваша проблема лежит?

2 голосов
/ 09 августа 2011

Если у вас есть несколько потенциальных наборов результатов, и существует вероятность неоднозначности, вы можете рассмотреть вопрос об изменении хранимой процедуры для использования выходного параметра вместо выбора в @ResultCode.

2 голосов
/ 09 августа 2011

То, что вам нужно, это первый столбец первой строки из последнего набора результатов . К сожалению, если в вашей процедуре есть несколько операторов выбора, что приводит к созданию более одного набора результатов, ExecuteScalar только получит первый столбец первой строки из первого набора результатов .

Ваш первый блок кода C # проверяет таблицу last в наборе данных, которая (правильно) будет связана с оператором last select в процедуре.

...