前回は、手動で各変更系のコマンドオブジェクトを作成していましたが、ADO.NETにはCommandBuilderという
クラスが存在しており、それを使用することにより以下の効果を得ることが出来ます。
SelectCommandのみを作成し、それ以外の変更系のコマンドについてはCommandBuilderに自動生成させる。
ただし、上記の方法にもいくつかの制限があります。
CommandBuilderが各変更系のコマンドを自動生成するには、以下の条件を満たさないといけません。
- クエリがただ一つのテーブルからデータを取得するようになっていること。
- そのテーブルに主キーが設定されていること。
- その主キーのカラムがクエリに設定されていること。
つまり、複数テーブルをJOINしているようなクエリ、または主キーが存在しないテーブルなどに
関しては、各変更系コマンドは自動生成されません。あくまでも1テーブルに対してのクエリの場合に対して
CommandBuilderは対応します。
で、使い方ですがCommandBuilderはDataAdapterと密に関連するので、インスタンスを作成後
DataAdapterプロパティに、使用するデータアダプタオブジェクトを設定し、双方を関連付け
ます。後は、普通にデータアダプタを使えばオッケイです。内部で関連付いているので
自動的にコマンドオブジェクトが生成されます。CommandBuilderは、動作する際に
関連対象のデータアダプタのSelectCommandを利用しますので、予めSelectCommandを設定する
事が必要になります。
using(DbCommand command = conn.CreateCommand){ // // selectクエリを設定. // command.CommandText = "select id, name, age from xxxx"; using(DbDataAdapter adapter = factory.CreateDataAdapter()){ adapter.SelectCommand = command; // // CommandBuilderを作成し、データアダプタと関連付ける。 // DbCommandBuilder builder = factory.CreateCommandBuilder(); builder.DataAdapter = adapter; // // 通常通り、アダプタを用いて処理を行なう。 // } }
尚、関連付けを行なえば良いだけなので、実はインスタンスを保持する必要も実はありません。
以下のようにも出来ます。
factory.CreateCommandBuilder().DataAdapter = adapter;
以下、サンプルです。
使用しているテーブルは、前回と同じテーブルとなっています。
using System; using System.Collections.Generic; using System.Data; using System.Data.Common; using System.Transactions; using NUnit.Framework; using Gsf.Lib.UnitTests; namespace Gsf.Samples.AdoNet { [TestFixture()] public class AdoNetSample011 : TestBase{ [Test()] public void コマンドビルダを使用してコマンドオブジェクトを構築してみる(){ using(TransactionScope tx = new TransactionScope()){ DbProviderFactory factory = DbProviderFactories.GetFactory(_settings.ProviderName); using(DbConnection conn = factory.CreateConnection()){ conn.ConnectionString = _settings.ConnectionString; conn.Open(); using(DbCommand command = conn.CreateCommand()){ command.CommandText = "select id, name, age from AdoNetSample009Table"; using(DbDataAdapter adapter = factory.CreateDataAdapter()) { adapter.SelectCommand = command; // // DbCommandBuilderオブジェクトを作成し、アダプターにディスパッチする。 // 今回は、どのようなSQLが作成されるかのサンプルなので明示的にインスタンスを // 作成するが、実際には、アダプターに関連付けられれば良いので以下のように書いても良い。 // // factory.CreateCommandBuilder().DataAdapter = adpater // DbCommandBuilder builder = factory.CreateCommandBuilder(); builder.DataAdapter = adapter; // // どのようなSQLが作成されているかの確認. // GetXXXXCommandメソッドにtrueを渡すと、内部で生成されるパラメータ名が出来る限り // 実際のカラム名から作成されるようになる。falseを指定すると // パラメータ名が@1,@2のようになる。 // Console.WriteLine(string.Format("INSERT-SQL:{0}", builder.GetInsertCommand(true).CommandText)); Console.WriteLine(string.Format("UPDATE-SQL:{0}", builder.GetUpdateCommand(true).CommandText)); Console.WriteLine(string.Format("DELETE-SQL:{0}", builder.GetDeleteCommand(true).CommandText)); // // 対象テーブルのスキーマ情報を取得し、データテーブルを構築. // DataTable table = new DataTable("AdoNetSample009Table"); adapter.FillSchema(table, SchemaType.Source); ///////////////////////////////////////////////////////////////////// // // Insertをしてみる. // DataRow newRow = table.NewRow(); newRow["id"] = 999; newRow["name"] = "gsf_zero999"; newRow["age"] = 99; table.Rows.Add(newRow); adapter.Update(table); // // 結果確認 // table.Clear(); adapter.Fill(table); Assert.AreEqual(1, table.Select("id = 999").Length); ///////////////////////////////////////////////////////////////////// // // updateをしてみる. // adapter.Fill(table); DataRow updateTargetRow = table.Select("id = 999")[0]; updateTargetRow["name"] = "gsf_zero_updated"; adapter.Update(table); // // 結果確認 // table.Clear(); adapter.Fill(table); Assert.AreEqual(1, table.Select("name = 'gsf_zero_updated'").Length); ///////////////////////////////////////////////////////////////////// // // updateをしてみる. // adapter.Fill(table); table.Select("id = 999")[0].Delete(); adapter.Update(table); // // 結果確認 // table.Clear(); adapter.Fill(table); Assert.AreEqual(0, table.Select("id = 999").Length); // データが登録されると面倒なのでわざとロールバックさせる。 //tx.Complete(); } // END using(DbDataAdapter adapter = factory.CreateDataAdapter()){ } // END using(DbCommand command = conn.CreateCommand()){ } // END using(DbConnection conn = factory.CreateConnection()){ } // END using(TransactionScope tx = new TransactionScope()){ } // END METHOD } }
実行すると、以下のように表示されます。
INSERT-SQL:INSERT INTO [AdoNetSample009Table] ([id], [name], [age]) VALUES (@id, @name, @age) UPDATE-SQL:UPDATE [AdoNetSample009Table] SET [id] = @id, [name] = @name, [age] = @age WHERE *1 DELETE-SQL:DELETE FROM [AdoNetSample009Table] WHERE *2
実際には、SelectCommandしかセットしていないのに、各変更系のコマンドがCommandBuilderによって生成されています。