none
ADO.NET でのSqlCommand の扱い RRS feed

  • 質問

  • いつも大変お世話になっています。

    SqlCommand について質問させて下さい。

    @IT に、レコードを追加するコード例が掲載されています。
    http://www.atmarkit.co.jp/fdotnet/basics/adonet05/adonet05_02.htmlstring selectStr

    string conn = "Server = ......";
    string selectStr = "SELECT pub_id, pub_name, FROM publishers!;

    SqlCommand selectCmd = new SqlCommand();
     selectCmd.Connection = conn;
     selectCmd.CommandText = selectStr;
     - - - - - -

     というSqlCommand の宣言に続き、下記のinsertCmd が宣言されます。
     SqlCommand insertCmd = new SqlCommand();
     insertCmd.Connection = conn;
     insertCmd.CommandText = insertStr;

     このとき、insertCmd を新たに宣言せずに
     SqlCommand selectCmd = new SqlCommand();
     selectCmd.Connection = conn;
     selectCmd.CommandText = insertStr;

     としてはおかしいでしょうか。

    よろしくお願い致します。

    2011年1月15日 1:45

回答

  • DataAdapterのSelectCommandプロパティにInsert入れるのはだめですが、SqlCommand単体で使用する分にはSqlCommandのインスタンスを指している変数を使いまわすのは、コーディング規約で変数の使い回しを制限されてなければ間違った使い方ではないです。

    コードが長くなると変数が何処で宣言されてるか使われているか判りにくくなるため、コーディング規約で使い回しを制限することはあります。
    @ITの例では判りやすく別のSQLであることを明示するため、変数名をわかりやすく別にしたとも考えられます。

    #メモリが少ない時代は使いまわしのが良かったんですがw
    • 回答としてマーク yasheeki 2011年1月15日 3:49
    2011年1月15日 2:54

すべての返信

  • 同じローカル変数の名前として、selectcmdを新たに宣言することはできません。ですから、

     selectCmd = new SqlCommand();
     selectCmd.Connection = conn;
     selectCmd.CommandText = insertStr;

    とするのはOKです。上記のselectCmdにはSqlCommandをnewすることによって新たなインスタンスがセットされます。
    ただ、selectcmdという名前は一般的に適切ではないでしょう。以下のような感じが良いと思います。

     var cmd = new SqlCommand();
     cmd.Connection = conn;
     cmd.CommandText = selectStr;
          ・
          ・
          ・
     cmd = new SqlCommand();
     cmd.Connection = conn;
     cmd.CommandText = insertStr;

    さらに上記はSqlCommandのコンストラクタを使って、以下のようにまとめて書けます。

    var cmd = new SqlCommand(selectStr, conn);
          ・
          ・
          ・
    cmd = new SqlCommand(insertStr, conn);

     


    ★良い回答には回答済みマークを付けよう! わんくま同盟 MVP - Visual C# http://d.hatena.ne.jp/trapemiya/
    2011年1月15日 2:52
    モデレータ
  • DataAdapterのSelectCommandプロパティにInsert入れるのはだめですが、SqlCommand単体で使用する分にはSqlCommandのインスタンスを指している変数を使いまわすのは、コーディング規約で変数の使い回しを制限されてなければ間違った使い方ではないです。

    コードが長くなると変数が何処で宣言されてるか使われているか判りにくくなるため、コーディング規約で使い回しを制限することはあります。
    @ITの例では判りやすく別のSQLであることを明示するため、変数名をわかりやすく別にしたとも考えられます。

    #メモリが少ない時代は使いまわしのが良かったんですがw
    • 回答としてマーク yasheeki 2011年1月15日 3:49
    2011年1月15日 2:54
  • // (1)
    using (var cmd = new SqlCommand())
    {
      cmd.xxx = ...;
      cmd.CommandText = "SELECT ...";
      /* その後 */
      cmd.xxx = ...;
      cmd.CommandText = "INSERT ...";
    }
    
    // (2)
    using (var cmd = new SqlCommand())
    {
      cmd.xxx = ...;
      cmd.CommandText = "SELECT ...";
    }
    /* その後 */
    using (var cmd = new SqlCommand())
    {
      cmd.xxx = ...;
      cmd.CommandText = "INSERT ...";
    }
    
    

    この場合、(1) と (2) では意味が違い、(1) では、SqlCommand のインスタンスが1つだけ作成されていて (2) では2つ作成されています。多くのデータベースでは、(1) のように SqlCommand を再利用すると、データベースサーバ側のリソースも再利用されます。この時、データベースサーバ側で処理の作り直しがどのように行われるかはデータベースサーバに依存するのですが、SQL Server や Oracle DB の場合にはパフォーマンスに悪影響を与えることが多いです。

    DbCommand ではなく SqlCommand で書かれているので、SQL Server だと思いますが、SQL Server の場合は(バージョンによって異なるとは思いますが) 新しい SqlCommand を new しないで CommandText を書き換えた場合、サーバ側ではクエリの実行計画等のキャッシュを破棄して Recompile 命令が実行され、新しい SqlCommand を作成した場合には、サーバ側では SELECT 側のクエリを無視して新しいクエリが Compile 命令で作られます。結果として、サーバ側に残るクエリの数が異なるため、「SELECT → INSERT → 再 SELECT して画面に表示しなおす」みたいな処理を行った時に、2回目の SELECT で SELECT 用のクエリがキャッシュヒットせず、再構築されることになると記憶しています。

    2011年1月15日 3:17
  • ありがとうございます。

    SqlCommand selectCmd = new SqlCommand();
    が2度使われているコードのご指摘を含め、いつもアドバイスとフォローとをありがとうございます。

    2011年1月15日 3:51
  • 使い回しの良否は、ケースバイケースということですね。

    実は、根本的に間違った解釈をしていないか不安だったので質問させていただきました。

    助かります。

    2011年1月15日 3:53