1

この単純化された例のようなストアド プロシージャを作成しました。

CREATE PROCEDURE dbo.sp_MyStoredProcedure
    @Var1 INT OUTPUT,
    @Var2 DECIMAL(10,2) OUTPUT
AS
BEGIN
    SET NOCOUNT ON;

    SELECT
        @Var1 = COUNT(*),
        @Var2 = SUM(TranAmount)
    FROM
        MyTable

    SELECT * FROM MyTable
END

ExecuteReader()オブジェクトのメソッドを呼び出した後、出力変数から値を読み取ろうとするとSqlCommand、値が null になります。

string MyConnString = string.Empty;
SqlConnection MyConn = new SqlConnection(MyConnString);
SqlCommand MyCmd = new SqlCommand("sp_MyStoredProcedure", MyConn);
MyCmd.CommandType = CommandType.StoredProcedure;
MyCmd.Parameters.Add(new SqlParameter("@Var1", SqlDbType.Int));
MyCmd.Parameters.Add(new SqlParameter("@Var2", SqlDbType.Decimal);
MyCmd.Parameters[0].Direction = ParameterDirection.Output;
MyCmd.Parameters[1].Direction = ParameterDirection.Output;
SqlDataReader dr = MyCmd.ExecuteReader(CommandBehavior.CloseConnection);
int Var1 = Convert.ToInt32(MyCmd.Parameters[0].Value);
decimal Var1 = Convert.ToDecimal(MyCmd.Parameters[1].Value);

私が間違っていることは何ですか?

4

2 に答える 2

10

最後までリーダーを読み取る必要があります。出力パラメーターは TDS ストリームの最後にあり、クライアントは結果セットが消費されなくなるまでそれらを確認できません。

結果セットを読み取る前にカウントと合計が必要な場合は、OUTPUT パラメータを破棄する必要があります。SELECT * 結果セットを購入した後に、関心のある 2 つの値を含む通常の結果セットを生成するだけです。次に、SqlDataReader.NextResult() を使用して、クライアントで両方の結果セットを読み取ります。

アップデート

2 つの結果セットを持つということの意味は次のとおりです。

CREATE PROCEDURE dbo.sp_MyStoredProcedure    
AS
BEGIN    
  SET NOCOUNT ON;    
  SELECT COUNT(*) as cnt, SUM(TranAmount) as sum_ta
  FROM MyTable
  SELECT * FROM MyTable
END

そしてクライアント:

string MyConnString = string.Empty;
SqlConnection MyConn = new SqlConnection(MyConnString);
SqlCommand MyCmd = new SqlCommand("sp_MyStoredProcedure", MyConn);
MyCmd.CommandType = CommandType.StoredProcedure;
using(SqlDataReader dr = MyCmd.ExecuteReader(CommandBehavior.CloseConnection))
{
  while(dr.Read())
  { 
     count = dr["cnt"];
     sum = dr["sum_ta"];
  }
  dr.NextResult();
  while(dr.Read())
  {
    // process MyTable row here
  }
}

C# コードがデータ リーダーを使用する前に出力パラメーターの値を必要としない場合は、これを行う必要がないことに注意してください。最後までSqlDataReader を読み取るだけで、出力パラメーターを確認できます。それらは設定されます。

于 2009-09-01T21:25:27.933 に答える
1

Remus が言ったように、最初にそれが必要な場合は、クエリの方法を再検討する必要があります。2 つの別々の手順を使用しないのはなぜですか? それが抽象的には最善の解決策です。

それ以外の場合は、同じバッチで 2 つの SQL ステートメントを実行できます

SELECT COUNT(*) AS VAR1, SUM(TranAmount) AS VAR2 FROM MyTable
SELECT * FROM MyTable

次に、ExecuteReader を呼び出すと

SqlDataReader dr = MyCmd.ExecuteReader(CommandBehavior.CloseConnection);
while (dr.read())
{
    var1 = dr["Var1"];
    var2 = dr["Var2"];
}

dr.NextResult();

while (dr.read())
{
   // blah blah blah code
}
于 2009-09-01T21:52:50.640 に答える