Выходная переменная не устанавливается в хранимой процедуре SQL Server - PullRequest
1 голос
/ 06 марта 2012

Я надеюсь, что это не один из тех вопросов, когда я ударил себя потом, но это действительно смущает меня.У меня есть это работает для другой из моих хранимых процедур, поэтому это так сбивает с толку.Это в основном одинаковые настройки в обоих.Вот что происходит.

Вот пример моей хранимой процедуры:

ALTER PROCEDURE [dbo].[CreateRecord] 
    -- Add the parameters for the stored procedure here
    @Link1Id INT = NULL,
    @Link2Id INT = NULL,
    @Amount MONEY,
    @Output int out
AS
BEGIN
    -- SET NOCOUNT ON added to prevent extra result sets from
    -- interfering with SELECT statements.
    SET NOCOUNT ON;

    SET @Output = 0

    -- Insert statements for procedure here
    IF @Link1Id = NULL
    BEGIN
        IF NOT EXISTS(SELECT * FROM dbo.Records WHERE Link2Id = @Link2Id)
        INSERT INTO [dbo].[Records]
               ([Link1Id]
               ,[Link2Id])
         VALUES
               (@Link1Id
               ,@Link2Id)
        SET @Output = (SELECT RecordId FROM dbo.Records WHERE Link2Id = @Link2Id)
    END
    ELSE
    BEGIN
        IF NOT EXISTS(SELECT * FROM dbo.Records WHERE Link1Id = @Link1Id)
        INSERT INTO [dbo].[Records]
               ([Link1Id]
               ,[Link2Id])
         VALUES
               (@Link1Id
               ,@Link2Id)
        SET @Output = (SELECT RecordId FROM dbo.Records WHERE Link1Id = @Link1Id)
    END
END

Теперь я создал модульный тест, который в основном выполняет эту процедуру, и пытается Assert вернуть@Output больше 0, но параметр @Output никогда не имеет значения SqlCommand в коде.Вот часть кода C #:

private int ExecuteNonQueryWithOutput(string procedureName, SqlParameter[] parameters)
{
    SqlCommand command = this.GenerateCommand(procedureName, parameters);
    connection.Open();
    command.ExecuteNonQuery();
    int retval = (int)command.Parameters[OUTPUT].Value;
    connection.Close();

    return retval;
}

Теперь я могу перешагнуть строку, которая вызывает ExecuteNonQuery(), и проверить в базе данных, что новая (и правильная) запись есть, но затем нана следующей строке он вызывает исключение, когда вызывает (int)command.Parameters[OUTPUT].Value;, поскольку Value не существует.

Это отлично работает для другой процедуры, которая у меня есть, которая настроена точно так же.Вы знаете, почему это не сработало бы здесь?

Спасибо, я немного озадачен.Некоторое время я отлаживал безуспешно.

Редактировать:

Код, который генерирует массив параметров:

List<SqlParameter> parameters = new List<SqlParameter>();
parameters.Add(new SqlParameter { ParameterName = "@Link1Id", SqlDbType = SqlDbType.Int, Direction = ParameterDirection.Input, Value = link1Val });
parameters.Add(new SqlParameter { ParameterName = "@Link2Id", SqlDbType = SqlDbType.Int, Direction = ParameterDirection.Input, Value = link2Val });
parameters.Add(new SqlParameter { ParameterName = OUTPUT, SqlDbType = SqlDbType.Int, Direction = ParameterDirection.Output });

return this.ExecuteNonQueryWithOutput("CreateRecord", parameters.ToArray());

Ответы [ 2 ]

2 голосов
/ 06 марта 2012

Я не вижу, где вы объявили @Output.Возможно, вы имели в виду:

ALTER PROCEDURE [dbo].[CreateRecord] 
    -- Add the parameters for the stored procedure here
    @Link1Id INT = NULL,
    @Link2Id INT = NULL,
    @Amount MONEY,
    @Output INT = NULL OUTPUT
AS

Также я не на 100% уверен, что у вас есть право синтаксиса для получения именованного выходного параметра.Но параметр должен существовать, прежде чем вы сможете ссылаться на него в любом случае.Как вы сохранили эту хранимую процедуру, не объявив @Output?

1 голос
/ 06 марта 2012

В коде много ошибок, выходящих за рамки проблемы с выходным параметром.

Чтобы ответить на реальный вопрос, вы, скорее всего, передадите значение NULL в качестве результата.Когда он пытается преобразовать это значение в Int, вы получаете ошибку.

Также строка sql:

IF @Link1ID = null

Ошибка ВСЕГДА .На языке SQL null является неопределенным значением, поэтому (null! = Null).Способ проверки на нулевые значения - использовать IS.Например:

IF (@Link1ID is null)

Что заставляет меня поверить, что вы на самом деле получаете нарушение первичного ключа в коде sql.

Теперь перейдем к большей проблеме.Ваш код C # имеет недостатки.Объект команды никогда не удаляется, и если есть какие-либо проблемы, ваш объект подключения также не будет удален.Это приведет к забавным ошибкам sql из-за исчерпания доступных подключений sql ..

Это должно выглядеть примерно так:

private int ExecuteNonQueryWithOutput(string procedureName, SqlParameter[] parameters)
{
    int retval = 0;
    using (SqlConnection conn = new SqlConnection("connection string here"))
    using (SqlCommand command = this.GenerateCommand(procedureName, parameters)) {
        connection.Open();
        command.ExecuteNonQuery();
        retval = (int)command.Parameters[OUTPUT].Value;
    }
    return retval;
}

Обратите внимание, что это объявляет,использует и удаляет ваши соединения и командные объекты локально.Если есть проблема, это обеспечит правильную утилизацию ресурсов.

Также обратите внимание, что он не использует глобальный объект "подключения".Пул соединений, предлагаемый операционной системой, невероятно эффективен при открытии / закрытии соединений по мере необходимости.Из-за этого лучше всего создавать экземпляры и хранить их достаточно долго, чтобы справиться с текущей операцией.Чем дольше он открыт, тем больше вероятность возникновения проблем.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...