DataSetには、リレーションを設定することができます。
リレーションを設定すると、データベースのように紐付くデータを取得したり、親の行を取得したり出来るようになります。
やり方は簡単で、データセットオブジェクトのRelationsプロパティに対して追加を行ないます。
RelationsプロパティはRelationsCollectionとなっています。
ds.Relations.Add(リレーション名, 親のカラム, 子のカラム);
また、複合キーでのリレーションを行なう場合は、
ds.Relations.Add(リレーション名, 親のカラムの配列, 子のカラムの配列);
となります。
以下サンプルです。
今回、データベースを使うほどでもないので、データソースにはXMLを利用します。
ちなみに、データセットとデータテーブルは、データベース専用のクラスではありません。
これらのクラスは、データソースと関連を持ちません。そして、これらのクラスは
XMLととても相性がいいです。(元々そのように設計されているので)
まずは、XMLスキーマです。
データベースでいうと、テーブル定義に当たるものです。
<?xml version="1.0" encoding="utf-8"?> <xs:schema id="Memo" targetNamespace="urn:gsf-samples-memo.xsd" elementFormDefault="qualified" xmlns="urn:gsf-samples-memo.xsd" xmlns:mstns="urn:gsf-samples-memo.xsd" xmlns:xs="http://www.w3.org/2001/XMLSchema"> <xs:element name="Memos"> <xs:complexType> <xs:choice maxOccurs="unbounded"> <xs:element name="Memo"> <xs:complexType> <xs:sequence> <xs:element name="MemoId" type="xs:int" /> <xs:element name="Title" type="xs:string" /> <xs:element name="Author" type="xs:string" /> <xs:element name="Data" type="xs:string" /> <xs:element name="CategoryId" type="xs:int" /> </xs:sequence> </xs:complexType> </xs:element> <xs:element name="Category"> <xs:complexType> <xs:sequence> <xs:element name="CategoryId" type="xs:int" /> <xs:element name="CategoryName" type="xs:string" /> </xs:sequence> </xs:complexType> </xs:element> </xs:choice> </xs:complexType> </xs:element> </xs:schema>
次に、使用するデータです。
<?xml version="1.0" encoding="utf-8" ?> <Memos xmlns="urn:gsf-samples-memo.xsd"> <Category> <CategoryId>1</CategoryId> <CategoryName>C#</CategoryName> </Category> <Category> <CategoryId>2</CategoryId> <CategoryName>VB2005</CategoryName> </Category> <Category> <CategoryId>3</CategoryId> <CategoryName>Java</CategoryName> </Category> <Memo> <MemoId>1</MemoId> <Title>タイトル-1</Title> <Author>gsf_zero1</Author> <Data>メモ-1</Data> <CategoryId>1</CategoryId> </Memo> <Memo> <MemoId>2</MemoId> <Title>タイトル-2</Title> <Author>gsf_zero2</Author> <Data>メモ-2</Data> <CategoryId>2</CategoryId> </Memo> <Memo> <MemoId>3</MemoId> <Title>タイトル-3</Title> <Author>gsf_zero3</Author> <Data>メモ-3</Data> <CategoryId>1</CategoryId> </Memo> <Memo> <MemoId>4</MemoId> <Title>タイトル-4</Title> <Author>gsf_zero4</Author> <Data>メモ-4</Data> <CategoryId>3</CategoryId> </Memo> </Memos>
最後にテスト用のクラスです。
using System; using System.Collections.Generic; using System.Data; using System.Data.Common; using NUnit.Framework; namespace Gsf.Samples.AdoNet { [TestFixture()] public class AdoNetSample012{ [Test()] public void データのリレーションが正常に設定されているかどうかの確認(){ // // テストに使用するデータセットを生成。 // // テスト用に作成したXMLファイルからデータを読み取る。 // DataSet ds = new DataSet(); ds.ReadXmlSchema("Memo.xsd"); ds.ReadXml("Memo.xml"); // 読み込めているかどうかの確認. Assert.AreEqual(1, int.Parse(ds.Tables["Category"].Rows[0]["CategoryId"].ToString())); Assert.AreEqual("C#", ds.Tables["Category"].Rows[0]["CategoryName"].ToString()); Assert.AreEqual("gsf_zero1", ds.Tables["Memo"].Rows[0]["Author"].ToString()); /////////////////////////////////////////////////////////////// // // リレーションの設定. // DataTable categoryTable = ds.Tables["Category"]; DataTable memoTable = ds.Tables["Memo"]; // // データセットに制約を追加. // // MemoテーブルのCategoryIdにCategoryテーブルを関連させる。 // // Addメソッドには、リレーション名を指定しないバージョンのメソッドもありますが // 後々、リレーション名からデータを取得する事が多いので指定している方が無難です。 // // 通常Addメソッドを実行すると、デフォルトで自動的にForeignKeyConstraintとUniqueConstraintが // まだ存在していない場合は作成されます。自動で制約を作成してほしくない場合は、以下のようにします。 // // ds.Relations.Add("FK_CategoryMemo", categoryTable.Columns["CategoryId"], memoTable.Columns["CategoryId"], false); // ds.Relations.Add("FK_CategoryMemo", categoryTable.Columns["CategoryId"], memoTable.Columns["CategoryId"]); // // 制約が作成されていることを確認. // Assert.AreEqual(typeof(UniqueConstraint), ds.Tables["Category"].Constraints[0].GetType()); Assert.AreEqual(typeof(ForeignKeyConstraint), ds.Tables["Memo"].Constraints[0].GetType()); // // データを取得. // // Memoから属するCategoryを取得する。 // foreach(DataRow row in memoTable.Rows){ // 所属するカテゴリを取得 DataRow category = row.GetParentRow("FK_CategoryMemo"); string displayValue = string.Format( "memo-id:{0}, title:{1}, author:{2}, data:{3}, category:{4}", row["MemoId"], row["Title"], row["Author"], row["Data"], category["CategoryName"] ); Console.WriteLine(displayValue); } Console.WriteLine(""); // // データを取得. // // Categoryから紐付くMemoを取得する。 // foreach(DataRow row in categoryTable.Rows){ // // 紐付くMemoを取得する. // foreach(DataRow memoRow in row.GetChildRows("FK_CategoryMemo")){ string displayValue = string.Format( "category-id:{0}, category-name:{1}, memo-id:{2}, memo-data:{3}", row["CategoryId"], row["CategoryName"], memoRow["MemoId"], memoRow["Data"] ); Console.WriteLine(displayValue); } } } } }
実行すると以下のようになります。
memo-id:1, title:タイトル-1, author:gsf_zero1, data:メモ-1, category:C# memo-id:2, title:タイトル-2, author:gsf_zero2, data:メモ-2, category:VB2005 memo-id:3, title:タイトル-3, author:gsf_zero3, data:メモ-3, category:C# memo-id:4, title:タイトル-4, author:gsf_zero4, data:メモ-4, category:Java category-id:1, category-name:C#, memo-id:1, memo-data:メモ-1 category-id:1, category-name:C#, memo-id:3, memo-data:メモ-3 category-id:2, category-name:VB2005, memo-id:2, memo-data:メモ-2 category-id:3, category-name:Java, memo-id:4, memo-data:メモ-4
ちゃんとリレーションが動作している事が確認できますね。