直でSQLを記述してデータを検索したりする場合は、通常以下の手順を踏みます。
- コマンドオブジェクトを作成
- コマンドにSQLを設定
- コマンドにパラメータを設定
- 実行
よくあるのが、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(); } } }