SqlCommandBuilderクラスによって自動作成されるinsert文というのは実際にはどのようなものだろうか。その内容は次のようなコードにより確認することができる。
// showcb.cs
using System;
using System.Data;
using System.Data.SqlClient;
public class ShowBuildCommand {
public static void Main() {
string connStr = "Server=(local)\\NetSDK;"
+ "Trusted_Connection=yes;"
+ "database=pubs";
string selectStr
= "SELECT pub_id, pub_name FROM publishers";
SqlConnection conn = new SqlConnection(connStr);
SqlDataAdapter da = new SqlDataAdapter(selectStr, conn);
SqlCommandBuilder cb = new SqlCommandBuilder(da);
SqlCommand insert = cb.GetInsertCommand();
Console.WriteLine(insert.CommandText);
foreach (SqlParameter p in insert.Parameters) {
Console.WriteLine(p.ParameterName);
Console.WriteLine(p.SourceColumn);
}
}
}
// コンパイル方法:csc showcb.cs
ここではSqlCommandBuilderクラスのインスタンスを作成したときに得られるオブジェクト(cb)を捨てずに利用している。このクラスのGetInsertCommandメソッドは、insert文を直ちに作成させるためのメソッドである。
このプログラムを実行した結果は次のようになる。
INSERT INTO publishers( pub_id , pub_name ) VALUES ( @p1 , @p2 )
@p1
pub_id
@p2
pub_name
上記のプログラムでは、SqlCommandBuilderオブジェクトのParametersプロパティにより、insert文と同時に自動生成された名前付きパラメータの情報(の一部)も表示している。名前付きパラメータの名前は異なるが、表示されたinsert文は先ほどのサンプル・プログラムのものと(まねたわけではないが)同一である。
では、SqlCommandBuilderクラスはこのinsert文をどうやって作り出しているのだろうか。データアダプタにセットしたselect文を基にしているのはまちがいないようだが、単にそれだけではないのは、それを次のように変更してプログラムを実行すれば分かる。
SELECT * FROM publishers
このように変更したときの出力は次のようになる。
INSERT INTO publishers( pub_id , pub_name , city , state , country ) VALUES ( @p1 , @p2 , @p3 , @p4 , @p5 )
@p1
pub_id
@p2
pub_name
@p3
city
@p4
state
@p5
country
この実行結果からも分かるように、SqlCommandBuilderクラスでは、データベースに接続して列の情報を取り出し、それを基にしてinsert文を作成しているのである。このため自前でinsert文を用意するのに比べると、データベースへの余分な問い合わせが1つ増える。Updateメソッドを呼ぶ瞬間までinsert文が自動作成されないようになっているのも、このためであると思われる。
念のため、先に示したレコードの追加を行う2つのサンプル・プログラム(insertds.csとcbinsertds.cs)において、実際にデータベース・サーバに発行されるSQL文を確認してみよう。
SQL Server 2000には、このような用途のために「SQLプロファイラ」というツールが付属している。このツールでは、あらかじめ対象となるデータベース・サーバを指定しておけば、発行されたすべてのSQL文をトレースすることができる。
次の画面は、SQLプロファイラによるトレースを開始してから、まず最初のサンプル・プログラム(insertds.cs)を実行した後の状態だ。
一方、insert文の自動生成を利用したサンプル・プログラム(cbinsertds.cs)のトレース結果は次のようになる。
見慣れないコマンドはとりあえず置いておくとして、2つの結果を比べると、自動生成させた方のトレース結果には次のようなselect文を含む行が、insert文の直前で余分に実行されているのが分かる。
SET FMTONLY OFF; SET NO_BROWSETABLE ON; SET FMTONLY ON;SELECT pub_id, pub_name FROM publishers SET FMTONLY OFF; SET NO_BROWSETABLE OFF;
これがSqlCommandBuilderクラスによるinsert文自動生成のための問い合わせである。データベースの更新頻度にもよるが、当然ながらこの余分なselect文の発行はアプリケーションのパフォーマンスを悪くするので、SqlCommandBuilderクラスの多用には注意が必要となる。
SqlCommandBuilderクラスはselect文から動的にinsert文を作り出すことができるが、select文が固定であるなら(ほとんどのアプリケーションはそうであると思われるが)、それに対して自動作成されるinsert文もいつも同じである。そのような場合、わざわざ実行時にinsert文を作り出す必要はない。極端な話、select文以外を自分で書きたくないなら、SqlCommandBuilderクラスを使用したツールを作っておいて、出力されたinsert文をプログラムにコピー&ペーストしてからコンパイルすれば、余分な問い合わせを減らすことができる。
Visual Studio .NETを使用してデータベース・アプリケーションを作成している方ならご存じだと思うが、VS.NETの「データアダプタ構成ウィザード」はまさにそれを行っている。Visual Studio .NETによるデータベース・プログラミングは、本連載でも今後取り上げる予定だが、ここではウィザードにより作成されたinsert文について簡単に見ておこう。
データアダプタ構成ウィザードは、ツールボックスの[データ]から[SqlDataAdapter]の項目をフォーム上にドラッグ&ドロップしたときなどに自動的に起動される。
ウィザードによる設定手順の途中には、アプリケーションで使用するselect文を入力する画面がある(クエリ・ビルダによりGUIでselect文を作成することもできる)。
この画面で[次へ]ボタンをクリックするときに、SqlCommandBuilderクラス(あるいはそれに似たクラス)を利用しているようである。SQLプロファイラのトレースを実行していると、クリックしたときに先ほどと同じselect文が実行されているのを確認することができる。
ウィザードでの作業が完了すると、insert文やupdate文、delete文が自動生成され、名前付きパラメータの設定のためのコードとともに、プログラム・コードが自動生成される。データアダプタの作成からinsert文の作成までのコードは次のようになっている。
このようにVisual Studio .NETのデータアダプタ構成ウィザードでは、「自動生成されたinsert文を含んだSqlCommandオブジェクトを作成するコード」を自動生成することにより、すべてをコンパイル時に済ませるようになっている。
今回はデータセットを使った場合のレコードの追加について解説してきた。次回はこれに引き続いて、レコードの更新と削除について解説する予定だ。実は今回では、データセットに追加された新しいレコードをどうやってデータアダプタが見つけ出すかということについて触れていない。これについても次回で解説する予定である。
Copyright© Digital Advantage Corp. All Rights Reserved.