MENU > HOME VB.NET VB6 VBA ソフトウェア リンク サイト情報
VB.NET> VB.NET 突撃レポート > 1  2  3  4  5  6  7  8  9  10  11  12 
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についてはまだほんの僅かしか試していませんが、また必要な機会に追々触れていこうと思います。

Copyright©Sugi. All rights reserved.