PART9: ADO.NETによるデータベースアクセス その3 - リレーション -(2002年3月24日)
さて今回はリレーションです。
リレーションは親となるテーブルと子となるテーブルの関係を指定するために使用するオブジェクトで、SQL文でJOIN句を使用するのとほんのちょっぴり似ています。
リレーションは前回使用した DataSet オブジェクトの Relations コレクションメンバを用います。
DataSet.Relations は以下のように定義されています。
Public ReadOnly Property Relations As DataRelationCollection
DataRelations コレクションということですから、従来どおりのコレクションを用いたコーディングと同様、Add
メソッドにてメンバを追加して使用するはずですから、まずは Add メソッドをヘルプで調べてみましょう。
以下のようにオーバーライドされた7つのAddメソッドが確認できました。Overloads Public Sub Add(DataRelation)
Overloads Overridable Public Function Add(DataColumn, DataColumn) As DataRelation
Overloads Overridable Public Function Add(DataColumn(), DataColumn()) As DataRelation
Overloads Overridable Public Function Add(String, DataColumn, DataColumn) As DataRelation
Overloads Overridable Public Function Add(String, DataColumn(), DataColumn()) As DataRelation
Overloads Overridable Public Function Add(String, DataColumn, DataColumn, Boolean) As DataRelation
Overloads Overridable Public Function Add(String, DataColumn(), DataColumn(), Boolean) As DataRelation
1つ目のAddメソッド以外はいずれも DataColumn
というオブジェクトが引数で使用されている点に気づきます。
DataColumn とはその名のごとくテーブルの列つまり、DataTable の列を意味するオブジェクトです。
DataTable とはこれも前回使用した、そう、RDBMSに対し発行したSQLステートメントを DataAdapter 経由で
Fillメ ソッドにより DataSet にコレクションされた非接続型レコードセットの事です。
ここまで少し調べた内容をまとめると、リレーションは DataSet にコレクションされた2つの DataTable
を指定したそれぞれの DataColumn (列) を関連付けたもの(下手な説明でなんのこっちゃかも!?)です。
ということは異なるプロバイダのデータソース、例えば MSSQL と JET や、MSSQL と Oracle
など、DataSet オブジェクトへ一旦 DataTable として取り込んでしまえば、リレーションなんてのもありありなのかも?
面白くなってきた!(やる気倍増)
今回は SQL Server 2000 のデータと ローカルに作成した JETデータベースで試してみましょう。
まずは SQL Server 側ですが、これは前回使用した T_CATEGORY テーブルをそのまま使うことにします。
JETデータベース側は以下のような製品の一覧テーブルを作成します。
MDBファイル名: D:\Test.mdb
テーブル名: T_SOFT
データ:
ID |
NAME |
CatID |
1 |
Microsoft
Visual Studio.NET |
3 |
2 |
Microsoft
Office XP |
2 |
3 |
Microsoft
Windows XP |
1 |
4 |
Borland
Delphi |
3 |
5 |
Turbo
Linux |
1 |
6 |
Palm OS |
1 |
7 |
Lotus
Super Office |
2 |
8 |
Visual
Café |
3 |
9 |
Code
Warrior |
3 |
例題を上記各レコードのカテゴリIDとSQL
Serverのカテゴリマスタテーブルとのリレーションを作成し、各製品をカテゴリ別に分類するようなものにしようと思います。
まずは今までのおさらいで、各データを DataSet の Tables コレクションに取り込んでいきます。
ちなみにここでは データの取り込みに関するコードは省略させていただき、後でまとめて記述しようと思います。
私はそれぞれ CATEGORY と SOFT という キー で DataTable を作成しました。
次はいよいよリレーションの作成です。
例題では各テーブルどうしのリレーションを指定する列は1つであり、データ出力の際にアクセスするためのキーが必要であることから、4番目か6番目のAddメソッドが妥当ですね。
このAddメソッドに関してもう少し、きちんとした定義内容を挙げておきます。
Overridable Overloads Public Function Add( _
ByVal name As String, _
ByVal parentColumn As DataColumn, _
ByVal childColumn As DataColumn _
) As DataRelation
Overridable Overloads Public Function Add( _
ByVal name As String, _
ByVal parentColumn As DataColumn, _
ByVal childColumn As DataColumn _
ByVal createConstraints As Boolean _
) As DataRelation
今回は特に制約を作成しませんが、特に気にする必要もないと思いますし、前者の Add
メソッドを使用し、コーディングします。
oDS.Relations.Add("SOFTLIST", oDS.Tables("CATEGORY").Columns("CatID"), oDS.Tables("SOFT").Columns("CatID"))
以上のような感じになるかと思います。
カテゴリデータを親テーブルとしてその親にそれぞれ関連する製品を子テーブルとしてぶら下げる。
意味合いとしてはそんな感じですね。
これでOKなのかどうかはわかりませんが、とりあえず実行してみましょう。
なんとエラーもなく進みました。でも、データの内容が確認できない...。
一応、IDEには以前のVBと同じようにローカルウィンドウらしきものがあるにはあるのですが、今回のものはオブジェクトの階層が複雑なので確認し辛いのでやめときます(ここらへんは後ほどたっぷり)。
じゃあ、せっかく新バージョンになったことだし、コントロールの使用方法の確認も含め、親子関係を確認するために最適なコントロール、ツリービューを使って表現してみることにします。
ツリービューのノードを作成するコードは、以前なら以下のような記述でした。
TreeView1.Nodes.Add , , "Parent", "親ノード"
TreeView1.Nodes.Add "Parent", tvwChild, "Child", "子ノード"
今回はどうでしょう。
調べてみると、TreeView の Nodes コレクションには オーバーライドされた2つの Add メソッドがあります。
しかし!
それらは単純にノードのテキストを引数として指定できるものと Node
オブジェクトを参照するもので、いずれも以前のように親ノードとのリレーションを指定できるようなな引数は存在しません。
さて、どうしましょうか...。
Nodesオブジェクトや、Nodeオブジェクトのプロパティやらメソッドやらを順番に確認していくと....、どうやらNodeオブジェクト
はその下の階層のノードのコレクション(Nodesプロパティ)を持っているようです。
要するに親オブジェクトの下の階層であるコレクションにオブジェクトを作成、さらにその下に階層を作成するならそれらコレクションに所属する子オブジェクトに子オブジェクトをAddしてゆくといった手順を踏みます。
確かに以前は 同じコレクションクラスを扱うコードであるにもかかわらす、TreeViewのNodeとListViewのListItem等、使用方法(引数など)が違っていたため、わかりづらいといえばわかりづらかったような気がします。
以前に比べると現在の方が直感的であるように思えます。(私は)
ということで、先程のコードを Windows.Forms の TreeView を使用したコードに書き換えてみると、こんな感じ。
TreeView1.Nodes.Add("親ノード").Nodes.Add("子ノード")
これではしっくりこない方にはこんなのも。
Dim nodParent As TreeNode
nodParent = TreeView1.Nodes.Add("親ノード")
nodParent.Nodes.Add("子ノード")
TreeViewの使い方に関する調査はこれくらいにして、例題に戻ります。
TreeViewの親ノードがカテゴリデータとなり、その子供たちがそのカテゴリに属する製品群といったものを作成してゆきます。
カテゴリデータを列挙してゆくには、前回シングルテーブルのデータを読み込んだのと同じ手順で、TableオブジェクトのRowsコレクションを順に処理してゆきます。
次にそれらの行毎にDataRelationを使用して関連付けられた子行を取得するわけですが、これには Row オブジェクトの
GetChildRows メソッドを使用します。
GetChildRows メソッドは Rows コレクションを戻り値として返しますので、この戻り値をさらに For Each 〜
In を使用し各行の値を列挙してゆけばよいのは自ずと想像がつきますね。
これらを踏まえて、ヘルプのコードをちょこっとパクりつつ記述してゆくと以下のようになるはず。
Dim rowCate As DataRow
Dim rowSoft As DataRow
Dim nodCate As TreeNode
Button1.Enabled = False
'-- 列データをTreeViewに出力する。
For Each rowCate In oDS.Tables("CATEGORY").Rows
nodCate = TreeView1.Nodes.Add(rowCate("Category").ToString)
For Each rowSoft In rowCate.GetChildRows("SOFTLIST")
nodCate.Nodes.Add(rowSoft("NAME").ToString)
Next
Next
で、実行。パーフェクト!!
今回完成したコード
Option Strict On
'-- System.Data.SqlClientネームスペース
Imports System.Data.SqlClient
Imports System.Data.OleDb
Public Class Form1
Inherits System.Windows.Forms.Form
Private oDS As DataSet
Private adpSoft As OleDbDataAdapter
Private adpCate As SqlDataAdapter
Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
Dim rowCate As DataRow
Dim rowSoft As DataRow
Dim nodCate As TreeNode
Button1.Enabled = False
'-- 列データをTreeViewに出力する。
For Each rowCate In oDS.Tables("CATEGORY").Rows
nodCate = TreeView1.Nodes.Add(rowCate("Category").ToString)
For Each rowSoft In rowCate.GetChildRows("SOFTLIST")
nodCate.Nodes.Add(rowSoft("NAME").ToString)
Next
Next
End Sub
Windows フォーム デザイナ で生成されたコード |
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
oDS = New DataSet("DATASET1")
adpCate = New SqlDataAdapter("SELECT * FROM T_CATEGORY", _
"Data Source=○○○○;Initial Catalog=TestDB;UID=○○;PWD=○○")
adpCate.Fill(oDS, "CATEGORY")
adpSoft = New OleDbDataAdapter("SELECT * FROM T_SOFT", _
"Provider=Microsoft.Jet.OLEDB.4.0;Data Source=Test.mdb")
adpSoft.Fill(oDS, "SOFT")
'-- 各データセットでリレーションを作成
oDS.Relations.Add("SOFTLIST", oDS.Tables("CATEGORY").Columns("CatID"), oDS.Tables("SOFT").Columns("CatID"))
End Sub
Private Sub Form1_Closing(ByVal sender As Object, ByVal e As System.ComponentModel.CancelEventArgs) Handles MyBase.Closing
'-- 各オブジェクトの開放
oDS.Clear()
oDS.Dispose()
oDS = Nothing
adpSoft.Dispose()
adpSoft = Nothing
adpCate.Dispose()
adpCate = Nothing
End Sub
End Class
|
今回もADO.NETについてふれましたが、その中でちょこっと使った TreeView
コントロールを見て 「他のコントロールはどう変わったの」と気になって仕方ありません。
次回からは Windows.Forms の各コントロールについて VB6での使い方と比較しながら、違いを洗い出してみようと思います。
ADO.NETについてはまだほんの僅かしか試していませんが、また必要な機会に追々触れていこうと思います。 |