ExecuteScalar возвращает 0 при выполнении хранимой процедуры

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

SELECT @ResultCode AS ResultCode

Код С# выглядит так:

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 в конце.


person systempuntoout    schedule 09.08.2011    source источник
comment
Есть ли SET NOCOUNT ON в вашей хранимой процедуре? Где SQL, который имеет дело с @Foo?   -  person Jodrell    schedule 09.08.2011


Ответы (4)


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

person Chris    schedule 09.08.2011
comment
но, как я уже сказал, StoredProcedure возвращает одно значение. - person systempuntoout; 09.08.2011
comment
@systempuntout: Честно говоря, вы только что сказали, что это заканчивается на SELECT @Resultcode. Это не означает, что нет других SELECTS в другом месте, которые могли бы вернуть этот 0 до конца. Тот факт, что оригинал беспокоится о том, чтобы явно получить последнюю таблицу, а не полагаться на знание, что есть только один оператор select, возвращающий что-либо, заставил меня поверить, что это было вероятной причиной. Можно ли вставить процедуру или она слишком большая/слишком секретная? - person Chris; 09.08.2011
comment
вы правы, я запускал SQL Profiler и возвращалось больше строк из разных таблиц, я об этом не думал. Спасибо :) - person systempuntoout; 09.08.2011
comment
@systempuntoout: Рад, что помог. Я почти не следил, так как волновался, что покровительствую 15-тысячному пользователю, который знает лучше этого. Я рад, что сделал это. ;-) - person Chris; 09.08.2011
comment
15к из его зоны комфорта :) - person systempuntoout; 09.08.2011

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

    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());
person Tatyana Mytko    schedule 31.10.2012

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

person cmsjr    schedule 09.08.2011
comment
спасибо за подсказку, я предложил это давным-давно, но есть сотни SP для такого рефакторинга. - person systempuntoout; 09.08.2011
comment
np, удачи в массовом рефакторинге. - person cmsjr; 09.08.2011

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

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

person canon    schedule 09.08.2011