いろいろ備忘録日記

主に .NET とか Go とか Flutter とか Python絡みのメモを公開しています。

ADO.NET入門記-017 (DbParameterオブジェクトを再利用する際の注意点)(DbParameter, DbCommand)


直でSQLを記述してデータを検索したりする場合は、通常以下の手順を踏みます。

  1. コマンドオブジェクトを作成
  2. コマンドにSQLを設定
  3. コマンドにパラメータを設定
  4. 実行


よくあるのが、SQLは違うけど指定するパラメータオブジェクトは同じものを再利用する場合です。
その際は、以下の点に注意する必要があります。

パラメータオブジェクトを再利用する際は、必ず特定のコマンドを実行後、DbCommand.Parameters.Clear()を呼んでおく事。


パラメータオブジェクトは、コマンドに追加した時点で、そのコマンドと紐づきます。
紐づきを解除しないまま、別のコマンドに設定すると以下のようなエラーとなります。

ハンドルされていない例外: System.ArgumentException: OracleParameter は、既に別の
 OracleParameterCollection に含まれています。
   場所 System.Data.OracleClient.OracleParameterCollection.Validate(Int32 index,
 Object value)
   場所 System.Data.OracleClient.OracleParameterCollection.Add(Object value)
   場所 Gsf.Demo.CommandObjectTest.Execute()
   場所 Gsf.Demo.CommandObjectTest.Main()


以下、サンプルです。このサンプルの

command.Parameters.Clear();

の部分をコメントアウトすると上記のエラーとなります。

// vim:set ts=4 sw=4 et ws is nowrap ft=cs:
using System;
using System.Data;
using System.Data.Common;

namespace Gsf.Demo{

    public class CommandObjectTest{

        void Execute(){

            DbProviderFactory factory = DbProviderFactories.GetFactory("System.Data.OracleClient");
            using(DbConnection conn = factory.CreateConnection()){

                conn.ConnectionString = "data source=xxxx;user id=xxxx;password=xxxx;";
                conn.Open();

                DbParameter param = null;
                using(DbCommand command = conn.CreateCommand()){

                    command.CommandText = "select * from t_xxx where xxx_cd = :XxxxCd";

                    param = command.CreateParameter();
                    param.ParameterName = "XxxxCd";
                    param.Value         = "0000000001";

                    command.Parameters.Add(param);

                    DbDataAdapter adapter = factory.CreateDataAdapter();
                    adapter.SelectCommand = command;
                    adapter.Fill(new DataTable());

                    //
                    // パラメータを再利用する場合は、必ずDbCommandがDisposeされる前に
                    // ParameterCollectionのClearメソッドを呼んでおく事。これにより
                    // このコマンドとパラメータの紐付けが解除される。
                    // 
                    command.Parameters.Clear();
                }

                using(DbCommand command = conn.CreateCommand()){

                    command.CommandText = "select * from t_zzzz where zzzz_cd = :XxxxCd";
                    command.Parameters.Add(param);

                    DbDataAdapter adapter = factory.CreateDataAdapter();
                    adapter.SelectCommand = command;
                    adapter.Fill(new DataTable());

                    command.Parameters.Clear();
                }
            }
        }

        static void Main(){
            new CommandObjectTest().Execute();
        }
    }
}