2012-03-06 15 views
1

これは私が後で自分自身を叩くところの質問ではないと思うが、これは本当に混乱している。私はこれが私のストアドプロシージャの別のもののために働いているので、これはとても混乱しています。それは基本的に両方の設定が同じです。ここで何が起こっているのですか?出力変数がSQL Serverストアドプロシージャに設定されていない

ここに私のストアドプロシージャの例です:今

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 

、私は基本的に、この手順を実行し、返された@Outputが0よりも大きいが、@OutputパラメータであることをAssertしようとするユニットテストを作成しましたコード内のSqlCommandの値は決してありません。私は、次の行にそれをExecuteNonQuery()を呼び出す行をステップオーバー、および新しい(そして正しい)レコードがあるデータベースで確認することができますが、今

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

:ここではC#のコードの一部ですValueが存在しないため、(int)command.Parameters[OUTPUT].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()); 
+0

ここで実際にprocに渡すパラメータを定義していますか? – NotMe

+0

'@ Output'は宣言する必要がありますか? – jp2code

+1

@ChrisLively私はそれらが 'parameters'配列に入っていると思います。もっと重要なのは 'set @ output = 0'だけですが、どこにでも宣言していません。 –

答えて

1

出力パラメータの問題を超えるコードには、さまざまな問題があります。

実際の質問に答えるには、出力としてNULL値を返す可能性があります。これをIntに変換しようとすると、エラーが発生します。

も、SQL行:

IF @Link1ID = null 

常には失敗します。 SQLの言葉では、nullは不確定な値なので、(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; 
} 

注これは宣言し、使用し、ローカルに接続し、コマンドオブジェクトを破棄します。問題がある場合は、リソースが適切に処分されることを確認します。

また、グローバルな「接続」オブジェクトは使用されません。オペレーティングシステムによって提供される接続プーリングは、必要に応じて接続を開閉する際に非常に効率的です。このため、ベストプラクティスは、現在の操作を処理するのに十分な時間だけインスタンス化し、それらを保持することです。開いている時間が長くなればなるほど、問題に遭遇する可能性が高くなります。

+0

このクリスおかげでありがとう:)私はこの記事を読んだ後、 'SqlConnection'と' SqlCommand'オブジェクトを扱う方法を次のように強化するつもりです。しかし、2番目のパラグラフの注記では、実際には '@ Output'パラメータをコレクションに渡しています。私はこれを反映するために私の質問を更新しました。これらのすべては別の手続きのために働いています。これはセットアップと同じ方法ですが、なぜこのprocで動作しないのか分かりません。 –

+0

@Scott:更新を参照してください。 – NotMe

+0

ありがとうございましたが、それは私の最初の質問についてです。これは別のストアドプロシージャで動作するので、 '@ Output'パラメータに何も戻っていないのはなぜだろうかと思います。コードを実行してこの出力を解析する行に着くと、正しいレコードがあることをデータベースで確認し、正しいIDを '@ Output'として選択するSQL行を実行することもできます何らかの理由で 'SqlCommand'に返されることはありません。 –

2

あなたが@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

sprocにはさまざまなものがあり、どのように呼び出されていますか? –

+0

@Aaron - はい、申し訳ありません!私は自分の投稿を編集しました。私が '@ Output'を宣言して、最初に入力したときにそれを見逃してしまったのです。ステファン、私はこれをもっと良く呼んでいますか?私は常に勉強して改善しようとしているので、あなたが持っているフィードバックはすばらしく、ありがとう。 –

関連する問題