続いては、データアダプタ構成ウィザードの完了画面で表示されていた「テーブル・マップ」についてここで解説しておこう。
「sqlDataAdapter1」を選択した状態で[プロパティ]ウィンドウをよく見ると、sqlDataAdapter1のプロパティの1つにTableMappingsプロパティというコレクションがあるが、これの内容がテーブル・マップの正体である。
テーブル・マップは、データベースへの問い合わせの結果からデータセットへデータを読み取る際に、データベースのテーブル名とデータセット内のデータテーブル名、そして、データベース内のテーブルのカラム名とデータテーブル内のカラム名を対応付けるためのものだ。
TableMappingsプロパティの項目を選択して[...]ボタンをクリックすると、そのコレクションの内容を編集するためのダイアログが開く。
まずこのダイアログからは、「Table」というデータベースのテーブル名(画面では「ソース テーブル」となっている)と、「publishers」という名前のデータテーブル(画面では「データセット テーブル」となっている)が対応付けられているのが分かる。
いま対象としているデータベースのテーブル名が「publishers」であるはずなのに、ここではこれが「Table」となっているのは、実行時にデータアダプタがテーブルの名前をDBMSから取得できないことに由来する。
第4回の「DataTableオブジェクトの名前」では、データアダプタのFillメソッドを次のように第2パラメータを指定せずに呼び出した場合には、デフォルトで「Table」という名前が付いてしまうことに触れた。
da.Fill(ds);
このため、次のようにして明示的にデータテーブルに名前を付けていた。
da.Fill(ds, "publishers");
テーブル・マップによる「Table」と「publishers」の対応付けがあれば、データアダプタはそれに従ってデータテーブルに名前を付けるようになる。よってこの場合にはFillメソッドの第2パラメータでの指定は不要となる*3。
*3 複数のselect文をセミコロンで区切って記述したバッチ・クエリをデータアダプタに設定してFillメソッドを呼び出すと、データセット内にはそれぞれのselect文を処理した複数のデータテーブルを作成することができる。この場合には、それぞれのデータテーブルには「Table」、「Table1」、「Table2」といった連番付きの名前が付けられる。このときにはテーブル・マップ(データセットのTableMappingsプロパティ)で、個々のデータテーブルに個別の名前を付けることができる。
一方、テーブルのカラム名については、データアダプタはDBMSに問い合わせて取得することができる。ただし、上記ダイアログ内の列マップから分かるように、デフォルトでは同じ名前での対応付けである。必要であれば、データベースのテーブルとは異なるカラム名をデータテーブル内のカラム(DataColumnオブジェクト)に付けることができるようになっている。
ところで、ここまでの連載では、このようなテーブル・マップによる対応付けがなくても、ds.Tables[0].Rows[0]["pub_id"]という具合にデータテーブルの特定のカラムにアクセスできた。この理由はまず、上記の[プロパティ]ウィンドウにも表示されているMissingSchemaActionプロパティのデフォルトが「Add」であるため、Fillメソッド呼び出し時にデータセットに存在しないカラムについては、それが自動的に作成されるからだ。さらに、MissingMappingActionプロパティがデフォルトで「Passthrough」になっている。この場合には、列マップがなくてもデータテーブル内の同じ名前のカラムが対応付けられる。
データアダプタについてはこれぐらいにして、次はデータセットの生成に進もう。
VS.NETでは、データセットの作成はツールボックスから[DataSet]コントロールをフォーム上にドロップしても行えるが、ここでは先ほど作成してデザイナ画面の下部に並んでいる「sqlDataAdapter1」を右クリックし、[データセットの生成]を実行してデータセットを作成してみよう。すると次のようなダイアログが表示されるのでそのまま[OK]ボタンをクリックする。
これによりデザイナ画面の下部には「dataSet11」が作成される(上記の画面で新規作成となっているのは「DataSet1」で、デザイナ画面上に現れるのは「dataSet11」である*4)。
*4 「DataSet1」というのは、実はVS.NETによりこっそり自動生成されるクラスの名前であり(VS.NETのソリューション・エクスプローラでよく探せば、そのソース・コードが見つかる)、これはDataSetクラスを継承したクラスである(特に「型指定されたデータセット」と呼ばれる)。このクラスにはpublishersやpub_id、pub_nameといったプロパティが定義されていて、このクラスのインスタンスでは、それらを通じてデータセット内のデータテーブルやカラムにアクセスできるようになっている。これにより、例えばds.Tables["publishers"].Rows[0]["pub_id"]と記述していたものをds.publishers[0].pub_idと記述できるようになる(DataSetクラスの子クラスなので、TablesプロパティやRowsプロパティなどを使用した記述も可能)。このようなクラスを自動生成できるのは、生成元となったデータアダプタを利用して、この時点ですでにVS.NETがテーブルのスキーマを読み取っているためだ。
フォームには、さらに2つのButtonコントロール(ここではTextプロパティを変更してボタンに表示される文字列を「Fill」と「Update」に設定している)とDataGridコントロールを次の画面のように適当に配置する。
次に、いま配置したDataGridコントロールを選択して、[プロパティ]ウィンドウでDataSourceプロパティが「(なし)」となっているのを、ドロップダウン・リストボックスから「dataSet11.publishers」に変更する。もしここで「dataSet11」を選択した場合には、第4回の「DataGridコントロールによるデータセットの表示(Windowsフォーム版)」で作ったようなネストしたグリッド表示となる。ここでは「dataSet1.publishers」を指定することにより、データセット内のpublishersという名前のデータテーブルを直接DataGridコントロールにデータ連結している。
以上で、データベースに接続できるデータアダプタ、データアダプタからデータを受け取るデータセット、そしてデータソースが設定されたDataGridコントロールのデータベース連携「三種の神器」がそろった。
あとは[Fill]ボタンがクリックされたときにデータセット(dataSet11)に対してFillメソッドを呼び出してやるだけで、DataGridコントロールにデータセットの内容が自動的に表示される。これには、配置した[Fill]ボタンをダブルクリックしてコードを表示させ、次のようなFillメソッド呼び出しをボタンのイベント・ハンドラに記述すればよい。
private void button1_Click(object sender, System.EventArgs e)
{
sqlDataAdapter1.Fill(dataSet11);
}
また、WindowsフォームのDataGridコントロールでは、グリッド上で編集した内容は、そのデータソースとなっているデータセットに自動的に反映される。よって[Update]ボタンがクリックされたときには単にUpdateメソッドを呼び出せばよい。[Fill]ボタンの場合と同様に、配置した[Update]ボタンをダブルクリックして次のコードを記述する。
private void button1_Click(object sender, System.EventArgs e)
{
sqlDataAdapter1.Update(dataSet11);
}
「Fill」を「Update」に変えただけである。このたった2行のコードを書くだけで、取りあえずテーブル編集アプリケーションが完成だ。アプリケーションを2つ起動して、同時実行制御が正しく動作しているかなどを確認してほしい。
以上で本連載は終わりである。しかしこの連載はあくまで基礎講座ということで、ADO.NETプログラミングのほんの入り口をご紹介したにすぎない。ADO.NETを活用した本格的なデータベース・プログラミングをマスターするには、まだまだ次のような「難所」がある。
しかし本連載を読み終えた読者は、こうした「難所」に向かって、より本格的な.NETデータベース・プログラミングの探検を始めるための最初の1歩は踏み出した。ぜひとも各自で探検を続けてほしい。なお本連載はこれで終了するが、解説できなかった項目については、また別の機会に詳しくご紹介したいと考えている。
Copyright© Digital Advantage Corp. All Rights Reserved.