データセット - xdomainjunko036.html.xdomain.jp/pdf/database/dataset.pdfvs 2005 資料...

69
VS 2005 資料 【電脳梁山泊 烏賊塾】 -1- DataSet クラス データのメモリ内キャッシュを表す。 名 前 空 間:System.Data アセンブリ:System.Datasystem.data.dll 内) 解説 データソースから取得されたデータのメモリ内キャッシュで有る DataSet は、 ADO.NET アーキテクチ ャの主要コンポーネントで有る DataSet は、DataRelation オブジェクトと相互に関連付ける事が出来 DataTable オブジェクトのコレクションで構成される。 UniqueConstraint オブジェクトと ForeignKeyConstraint オブジェクトを使用して、 DataSet 内でデータの整合性を適用する事も出来る。 DataSet オブジェクトの使用の詳細に付いては、「ADO.NET での DataSet の使用」を参照され度い。 DataTable オブジェクトにはデータを格納出来るのに対して、 DataRelationCollection を使用するとテ ーブルの階層構造内を移動出来る。テーブルは、 Tables プロパティを使用してアクセス出来る DataTableCollection に格納される。DataTable オブジェクトにアクセスする時は、条件付きで大文字 と小文字が区別される事に注意され度い。例えば、 mydatatable と謂う名前の DataTable Mydatatable と謂う名前のテーブルが有る場合は、此の 2 つのーブルの孰れかを検索する文字列は大文 字と小文字を区別すると看做される。但し、mydatatable と謂う名前は存在するが Mydatatable と謂 う名前が存在しない場合は、検索文字列は大文字と小文字を区別しないと看做される。DataTable オブ ジェクトの使用の詳細に付いては、「DataTable の作成」を参照され度い。 DataSet では、データとスキーマを XML ドキュメントとして読み取ったり、書き込んだり出来る。読 み込んだデータとスキーマは、HTTP で転送出来、XML 対応の総てのプラットフォーム、及び、アプ リケーションで使用出来る。スキーマを XML スキーマと仕て保存するには WriteXmlSchema メソッ ドを使用する。スキーマとデータの両方を保存するには WriteXml メソッドを使用する。スキーマとデ ータの両方を含む XML ドキュメントを読み取るには、ReadXml メソッドを使用する。 通常の多階層の実装で DataSet を作成・更新し、次に元のデータを更新するステップを次に示す。 1.DataAdapter を使用して、DataSet 内に DataTable を作成し、各テーブルにデータソースのデー タを格納する。 2.DataRow オブジェクトを追加、更新、又は、削除して、個別の DataTable オブジェクト内のデー タを変更する。 3.GetChanges メソッドを呼び出して、データへの変更丈を格納する 2 つ目の DataSet を作成する。 4.此の 2 つ目の DataSet を引数と仕て渡して、DataAdapter Update メソッドを呼び出す。 5.Merge を呼び出して、2 つ目の DataSet に格納された変更を最初のデータセットにマージする。 6. DataSet AcceptChanges を呼び出す。変更をキャンセルするには、 RejectChanges を呼び出す。

Upload: others

Post on 23-Apr-2020

2 views

Category:

Documents


0 download

TRANSCRIPT

Page 1: データセット - xdomainjunko036.html.xdomain.jp/pdf/database/DataSet.pdfVS 2005 資料 【電脳梁山泊 烏賊塾】 -3- EndInit フォーム又は別のコンポーネントで使用するDataSetの初期化を終了する(初

VS 2005 資料 【電脳梁山泊 烏賊塾】

-1-

■ DataSet クラス ■

データのメモリ内キャッシュを表す。

名 前 空 間:System.Data

アセンブリ:System.Data(system.data.dll 内)

■ 解説

データソースから取得されたデータのメモリ内キャッシュで有る DataSet は、ADO.NET アーキテクチ

ャの主要コンポーネントで有る DataSet は、DataRelation オブジェクトと相互に関連付ける事が出来

る DataTable オブジェクトのコレクションで構成される。UniqueConstraint オブジェクトと

ForeignKeyConstraint オブジェクトを使用して、DataSet 内でデータの整合性を適用する事も出来る。

DataSet オブジェクトの使用の詳細に付いては、「ADO.NET での DataSet の使用」を参照され度い。

DataTable オブジェクトにはデータを格納出来るのに対して、DataRelationCollection を使用するとテ

ーブルの階層構造内を移動出来る。テーブルは、Tables プロパティを使用してアクセス出来る

DataTableCollection に格納される。DataTable オブジェクトにアクセスする時は、条件付きで大文字

と小文字が区別される事に注意され度い。例えば、mydatatable と謂う名前の DataTable と

Mydatatable と謂う名前のテーブルが有る場合は、此の 2 つのーブルの孰れかを検索する文字列は大文

字と小文字を区別すると看做される。但し、mydatatable と謂う名前は存在するが Mydatatable と謂

う名前が存在しない場合は、検索文字列は大文字と小文字を区別しないと看做される。DataTable オブ

ジェクトの使用の詳細に付いては、「DataTable の作成」を参照され度い。

DataSet では、データとスキーマを XML ドキュメントとして読み取ったり、書き込んだり出来る。読

み込んだデータとスキーマは、HTTP で転送出来、XML 対応の総てのプラットフォーム、及び、アプ

リケーションで使用出来る。スキーマを XML スキーマと仕て保存するには WriteXmlSchema メソッ

ドを使用する。スキーマとデータの両方を保存するには WriteXml メソッドを使用する。スキーマとデ

ータの両方を含む XML ドキュメントを読み取るには、ReadXml メソッドを使用する。

通常の多階層の実装で DataSet を作成・更新し、次に元のデータを更新するステップを次に示す。

1.DataAdapter を使用して、DataSet 内に DataTable を作成し、各テーブルにデータソースのデー

タを格納する。

2.DataRow オブジェクトを追加、更新、又は、削除して、個別の DataTable オブジェクト内のデー

タを変更する。

3.GetChanges メソッドを呼び出して、データへの変更丈を格納する 2 つ目の DataSet を作成する。

4.此の 2 つ目の DataSet を引数と仕て渡して、DataAdapter の Update メソッドを呼び出す。

5.Merge を呼び出して、2 つ目の DataSet に格納された変更を最初のデータセットにマージする。

6.DataSet で AcceptChanges を呼び出す。変更をキャンセルするには、RejectChanges を呼び出す。

デデーータタセセッットト

Page 2: データセット - xdomainjunko036.html.xdomain.jp/pdf/database/DataSet.pdfVS 2005 資料 【電脳梁山泊 烏賊塾】 -3- EndInit フォーム又は別のコンポーネントで使用するDataSetの初期化を終了する(初

VS 2005 資料 【電脳梁山泊 烏賊塾】

-2-

■ パブリックプロパティ

名前 説明

CaseSensitive DataTableオブジェクト内の文字列比較で大文字と小文字を区別するか

何うかを示す値を取得・設定する。

Container コンポーネントを格納するコンテナを取得する。

DataSetName 現在の DataSet の名前を取得・設定する。

DefaultViewManager カスタム DataViewManager を使用してフィルタ処理、検索、移動の各

操作を行う事が出来る、DataSet に格納されて居るデータのカスタムビ

ューを取得する。

DesignMode コンポーネントが現在デザインモードか何うかを示す値を取得する。

EnforceConstraints 更新操作を試みた時に操作が制約規則に従って居るか何うかを示す値

を取得・設定する。

ExtendedProperties DataSetに関連付けられて居るカスタマイズされたユーザー情報のコレ

クションを取得する。

HasErrors 此の DataSet 内の DataTable オブジェクトの孰れかにエラーが有るか

何うかを示す値を取得する。

IsInitialized DataSet が初期化されて居るか何うかを示す値を取得する。

Locale テーブル内の文字列の比較に使用するロケール情報を取得・設定する。

Namespace DataSet の名前空間を取得・設定する。

Prefix DataSet の名前空間に別名を付ける XML プリフィックスを取得・設定

する。

Relations テーブルをリンクし、親テーブルから子テーブルへ移動出来る様にする

リレーションシップのコレクションを取得する。

RemotingFormat リモート処理中に使用される DataSet の SerializationFormat を取得・

設定する。

SchemaSerializationMode DataSet の SchemaSerializationMode を取得・設定する。

Site DataSet の System.ComponentModel.ISite を取得・設定する。

Tables DataSet に格納されて居るテーブルのコレクションを取得する。

■ プロテクトプロパティ

名前 説明

Events コンポーネントに結び付けられて居るイベントハンドラのリストを取得

する。

■ パブリックメソッド

名前 説明

AcceptChanges 此の DataSet の読み込み、又は、前回の AcceptChanges の呼出以降に此のデ

ータセットに対して行われた総ての変更をコミットする。

BeginInit フォームや別のコンポーネントで使用する DataSet の初期化を開始する(初期

化は実行時に発生する)。

Clear 総てのテーブル内の総ての行を削除して、データの DataSet を消去する。

Clone 総ての DataTable スキーマ、リレーションシップ、及び、制約を含め DataSet

の構造体をコピーする(データのコピーは行わない)。

Copy 此の DataSet の構造体丈でなくデータもコピーする。

CreateDataReader DataTable 毎に 1 つの結果セットを含む DataTableReader を返す(順序は、

Tables コレクション内のテーブルでの出現順序と同じで有る)。

Dispose MarshalByValueComponent に依って使用されて居るリソースを解放する。

Page 3: データセット - xdomainjunko036.html.xdomain.jp/pdf/database/DataSet.pdfVS 2005 資料 【電脳梁山泊 烏賊塾】 -3- EndInit フォーム又は別のコンポーネントで使用するDataSetの初期化を終了する(初

VS 2005 資料 【電脳梁山泊 烏賊塾】

-3-

EndInit フォーム又は別のコンポーネントで使用する DataSet の初期化を終了する(初

期化は実行時に発生する)。

Equals 2 つの Object インスタンスが等しいか何うかを判断する。

GetChanges 前回 DataSet を読み取るか、AcceptChanges を呼び出した以降に此のデータ

セットに対して行われた総ての変更が格納されて居る此のデータセットのコ

ピーを取得する。

GetDataSetSchema

GetHashCode 特定の型のハッシュ関数と仕て機能する。GetHashCode は、ハッシュアルゴ

リズムや、ハッシュテーブルの様なデータ構造での使用に適して居る。

GetObjectData DataSet をシリアル化する為に必要なデータをシリアル化情報オブジェクト

に設定する。

GetService IServiceProvider を実装して居るオブジェクトを取得する。

GetType 現在のインスタンスの Type を取得する。

GetXml DataSet に格納されて居るデータの XML 表現を返す。

GetXmlSchema DataSet に格納されて居るデータの XML 表現の XML スキーマを返す。

HasChanges DataSet に新しい行、削除された行、変更された行等の変更が有るか何うかを

示す値を取得する。

InferXmlSchema XML スキーマを DataSet に適用する。

Load 指定された IDataReader を使用し、DataSet にデータソースからの値を設定

する。

Merge 指定した DataSet か DataTable、又は、DataRow オブジェクトの配列を現在

の DataSet 又は DataTable にマージする。

ReadXml XML スキーマとデータを DataSet に読み込む。

ReadXmlSchema XML スキーマを DataSet に読み込む。

ReferenceEquals 指定した複数の Object インスタンスが同一か何うかを判断する。

RejectChanges 此の DataSet を作成するか、前回 DataSet.AcceptChanges を呼び出した以降

に此のデータセットに対して行われた総ての変更をロールバックする。

Reset DataSet を元の状態にリセットする(サブクラスが Reset をオーバーライドし

て DataSet を元の状態に戻す必要が有る)。

ToString Component の名前を格納して居る String を返す。此のメソッドはオーバーラ

イド出来ません。(MarshalByValueComponent から継承される。)

WriteXml DataSet から XML データを書き込む。オプションでスキーマも書き込む事が

出来る。

WriteXmlSchema DataSet 構造体を XML スキーマと仕て書き込む。

■ プロテクトメソッド

名前 説明

DetermineSchemaSerializationMode DataSet の SchemaSerializationMode を判別する。

Dispose MarshalByValueComponent に依って使用されて居るリソ

ースを解放する。(MarshalByValueComponent から継承さ

れる。)

Finalize [To be supplied.] (MarshalByValueComponent から継承さ

れる。)

GetSchemaSerializable

GetSerializationData

InitializeDerivedDataSet

IsBinarySerialized

MemberwiseClone 現在の Object の簡易コピーを作成する。(Object から継承さ

れる。)

Page 4: データセット - xdomainjunko036.html.xdomain.jp/pdf/database/DataSet.pdfVS 2005 資料 【電脳梁山泊 烏賊塾】 -3- EndInit フォーム又は別のコンポーネントで使用するDataSetの初期化を終了する(初

VS 2005 資料 【電脳梁山泊 烏賊塾】

-4-

OnPropertyChanging OnPropertyChanging イベントを発生させます。

OnRemoveRelation DataTable から DataRelation オブジェクトが削除された

時に発生する。

OnRemoveTable DataSet から DataTable が削除された時に発生する。

RaisePropertyChanging 指定した DataSet プロパティが此れから変更されると謂う

通知を送信する。

ReadXmlSerializable

ShouldSerializeRelations Relations プロパティを永続化する必要が有るか何うかを示

す値を取得する。

ShouldSerializeTables Tables プロパティを永続化する必要が有るか何うかを示す

値を取得する。

■ 使用例

幾つかのメソッドを組み合わせて DataSet を作成した後で Northwind データベースのデータを読み込

む例を次に示す。

Visual basic

Option Explicit On

Option Strict On Imports System.Data

Imports system.Data.SqlClient Public Class NorthwindDataSet

Public Shared Sub Main()

Dim connectionString As String = GetConnectionString( )

ConnectToData(connectionString)

End Sub

Private Shared Sub ConnectToData( ByVal connectionString As String)

' Create a SqlConnection to the Northwind database.

Using connection As SqlConnection = New SqlConnection( connectionString)

' Create a SqlDataAdapter for the Suppliers table.

Dim suppliersAdapter As SqlDataAdapter = New SqlDataAdapter( ) ' A table mapping names the DataTable.

suppliersAdapter.TableMappings.Add("Table", "Suppliers") ' Open the connection.

connection.Open( )

Console.WriteLine("The SqlConnection is open.") ' Create a SqlCommand to retrieve Suppliers data.

Dim suppliersCommand As SqlCommand = New SqlCommand( _

"SELECT SupplierID, CompanyName FROM dbo.Suppliers;", connection)

suppliersCommand.CommandType = CommandType.Text ' Set the SqlDataAdapter's SelectCommand.

suppliersAdapter.SelectCommand = suppliersCommand

' Fill the DataSet.

Dim dataSet As DataSet = New DataSet("Suppliers")

suppliersAdapter.Fill(dataSet)

Page 5: データセット - xdomainjunko036.html.xdomain.jp/pdf/database/DataSet.pdfVS 2005 資料 【電脳梁山泊 烏賊塾】 -3- EndInit フォーム又は別のコンポーネントで使用するDataSetの初期化を終了する(初

VS 2005 資料 【電脳梁山泊 烏賊塾】

-5-

' Create a second SqlDataAdapter and SqlCommand to get

' the Products table, a child table of Suppliers.

Dim productsAdapter As SqlDataAdapter = New SqlDataAdapter( )

productsAdapter.TableMappings.Add("Table", "Products")

Dim productsCommand As SqlCommand = New SqlCommand( _

"SELECT ProductID, SupplierID FROM dbo.Products;", connection)

productsAdapter.SelectCommand = productsCommand

' Fill the DataSet.

productsAdapter.Fill(dataSet)

' Close the connection.

connection.Close( )

Console.WriteLine("The SqlConnection is closed.")

' Create a DataRelation to link the two tables based on the SupplierID.

Dim parentColumn As DataColumn = _

dataSet.Tables("Suppliers").Columns("SupplierID")

Dim childColumn As DataColumn = _

dataSet.Tables("Products").Columns("SupplierID")

Dim relation As DataRelation = New _

System.Data.DataRelation("SuppliersProducts", parentColumn, childColumn)

dataSet.Relations.Add(relation)

Console.WriteLine( "The {0} DataRelation has been created.", relation.RelationName)

End Using

End Sub

Private Shared Function GetConnectionString( ) As String

' To avoid storing the connection string in your code,

' you can retrieve it from a configuration file.

Return "Data Source=(local);Initial Catalog=Northwind; Integrated Security=SSPI;"

End Function

End Class

C#

using System;

using System.Data;

using System.Data.SqlClient; namespace Microsoft.AdoNet.DataSetDemo

{

class NorthwindDataSet

{

static void Main( )

{

string connectionString = GetConnectionString( );

ConnectToData(connectionString);

} private static void ConnectToData(string connectionString)

{

//Create a SqlConnection to the Northwind database.

using (SqlConnection connection = new SqlConnection(connectionString))

Page 6: データセット - xdomainjunko036.html.xdomain.jp/pdf/database/DataSet.pdfVS 2005 資料 【電脳梁山泊 烏賊塾】 -3- EndInit フォーム又は別のコンポーネントで使用するDataSetの初期化を終了する(初

VS 2005 資料 【電脳梁山泊 烏賊塾】

-6-

{

//Create a SqlDataAdapter for the Suppliers table.

SqlDataAdapter adapter = new SqlDataAdapter( ); // A table mapping names the DataTable.

adapter.TableMappings.Add("Table", "Suppliers");

// Open the connection.

connection.Open( );

Console.WriteLine("The SqlConnection is open.");

// Create a SqlCommand to retrieve Suppliers data.

SqlCommand command = new SqlCommand(

"SELECT SupplierID, CompanyName FROM dbo.Suppliers;",connection);

command.CommandType = CommandType.Text;

// Set the SqlDataAdapter's SelectCommand.

adapter.SelectCommand = command; // Fill the DataSet.

DataSet dataSet = new DataSet("Suppliers");

adapter.Fill(dataSet); // Create a second Adapter and Command to get

// the Products table, a child table of Suppliers.

SqlDataAdapter productsAdapter = new SqlDataAdapter( );

productsAdapter.TableMappings.Add("Table", "Products"); SqlCommand productsCommand = new SqlCommand(

"SELECT ProductID, SupplierID FROM dbo.Products;",connection);

productsAdapter.SelectCommand = productsCommand; // Fill the DataSet.

productsAdapter.Fill(dataSet); // Close the connection.

connection.Close( );

Console.WriteLine("The SqlConnection is closed.");

// Create a DataRelation to link the two tables based on the SupplierID.

DataColumn parentColumn = dataSet.Tables["Suppliers"].Columns["SupplierID"];

DataColumn childColumn = dataSet.Tables["Products"].Columns["SupplierID"];

DataRelation relation = new System.Data.DataRelation("SuppliersProducts",

parentColumn, childColumn);

dataSet.Relations.Add(relation);

Console.WriteLine("The {0} DataRelation has been created.",relation.RelationName);

}

}

static private string GetConnectionString( )

{

// To avoid storing the connection string in your code,

// you can retrieve it from a configuration file.

return "Data Source=(local);Initial Catalog=Northwind; Integrated Security=SSPI";

}

}

}

Page 7: データセット - xdomainjunko036.html.xdomain.jp/pdf/database/DataSet.pdfVS 2005 資料 【電脳梁山泊 烏賊塾】 -3- EndInit フォーム又は別のコンポーネントで使用するDataSetの初期化を終了する(初

VS 2005 資料 【電脳梁山泊 烏賊塾】

-7-

■ DataSet クラスの概要

DataSet オブジェクトは、ADO.NET で非接続型分散データシナリオをサポートする上で中心的な役割

を果たす。DataSet は、メモリ内に常駐するデータ表現で有り、データソースの違いに拘らず、一貫性

の有るリレーショナルプログラミングモデルを提供する。複数の異なるデータソースや XML データと

組み合わせて使用出来、アプリケーションに取ってローカルなデータの管理にも使用出来る。DataSet

は、関連テーブル、制約、及び、テーブル間のリレーションシップを含む完全なデータセットを表現す

る。次の図に示すのが DataSet オブジェクトモデルで有る。

DataSet オブジェクトモデル

1 つの DataSet に含まれるメソッドとオブジェクトは、リレーショナルデータベースモデルに含まれる

メソッドやオブジェクトと整合性が有る。

DataSet は、其の内容を XML と仕て永続化、及び、再読み込みしたり、其のスキーマを XML スキー

マ定義言語(XSD)スキーマと仕て永続化、及び、再読み込みしたり出来る。詳細に付いては、「DataSet

での XML の使用」を参照され度い。

DataTableCollection

ADO.NET の DataSet には、DataTable オブジェクトに依って表現される 0 個以上のテーブルのコレ

クションが含まれる。DataTableCollection には、1 つの DataSet に属する総ての DataTable オブジェ

クトが含まれて居る。

DataTable は、System.Data 名前空間で定義され、メモリ常駐データの 1 つのテーブルを表現する。此

のテーブルには、共にテーブルのスキーマを定義する DataColumnCollection で表現される列と

ConstraintCollection で表現される制約のコレクションが含まれる。DataTable には、テーブル内のデ

ータが格納された DataRowCollection で表現される行のコレクションも含まれる。DataRow には、行

に格納された値の変更を識別出来る様に、行の現在の状態と共に、行の現在のバージョンと元のバージ

ョンの両方が保持される。

Page 8: データセット - xdomainjunko036.html.xdomain.jp/pdf/database/DataSet.pdfVS 2005 資料 【電脳梁山泊 烏賊塾】 -3- EndInit フォーム又は別のコンポーネントで使用するDataSetの初期化を終了する(初

VS 2005 資料 【電脳梁山泊 烏賊塾】

-8-

DataRelationCollection

DataSet の DataRelationCollection オブジェクトにはリレーションシップが含まれる。DataRelation

オブジェクトで表現されるリレーションシップは、或る DataTable の行を別の DataTable の行に関連

付ける。リレーションシップは、リレーショナルデータベースの主キー列と外部キー列の間に存在する

結合パスに似て居る。DataRelation は、1 つの DataSet が含む 2 つのテーブルの間で、一致する列を

識別する。

リレーションシップを使用すると、DataSet 内部の、或るテーブルと別のテーブルを行き来する事が出

来る。DataRelation で必須とされる要素は、リレーションシップの名前、関連付けるテーブルの名前、

及び、各テーブル内で関連付けられる列で有る。DataColumn オブジェクトの配列をキー列と仕て指定

する事に依って、テーブル毎に複数の列を使用してリレーションシップを構築出来る。

DataRelationCollection にリレーションシップを追加する時は、関連列の値が変更された時に整合性制

約を適用する為に、オプションで UniqueKeyConstraint 及び ForeignKeyConstraint を追加出来る。

ExtendedProperties

DataSet、DataTable、及び、DataColumn には、総て ExtendedProperties プロパティが有る。

ExtendedProperties は PropertyCollection で有り、此処には、結果セットの生成に使われた SELECT

ステートメントやデータが生成された時刻等、独自の情報を格納出来る。ExtendedProperties コレク

ションは、DataSet のスキーマ情報と共に永続化される。

■ DataSet の作成

DataSet のインスタンスを作成するには、DataSet のコンストラクタを呼び出す。必要に応じて、引数

name を指定する。名前を指定しない場合、DataSet の名前は NewDataSet に設定される。

亦、既存の DataSet に基づいて新しい DataSet を作成する事も出来る。既存の DataSet の正確なコピ

ーを新しい DataSet と仕て作成出来るのは、リレーショナル構造やスキーマはコピーするけれども既存

の DataSet からのデータは含まない DataSet のクローン、又は GetChanges メソッドを使用して既存

の DataSet から変更された行丈を含む DataSet のサブセットの孰れかで有る。詳細に付いては、

「DataSet の内容のコピー」を参照され度い。

DataSet のインスタンスの作成方法を示すコード例を次に示す。

Visual Basic

Dim customerOrders As DataSet = New DataSet("CustomerOrders")

C#

DataSet customerOrders = new DataSet("CustomerOrders");

■ DataSet への DataTable の追加

ADO.NET を使用して DataTable オブジェクトを作成し、其のオブジェクトを既存の DataSet に追加

出来る。PrimaryKey プロパティと Unique プロパティを使用する事で、DataTable の制約情報を設定

出来る。

DataSet を構築し、DataSet に新しい DataTable オブジェクトを追加してから、3 つの DataColumn

オブジェクトを其のテーブルに追加する例を次に示す。コードの最後では、1 つの列が主キーの列と仕

て設定されて居る。

Page 9: データセット - xdomainjunko036.html.xdomain.jp/pdf/database/DataSet.pdfVS 2005 資料 【電脳梁山泊 烏賊塾】 -3- EndInit フォーム又は別のコンポーネントで使用するDataSetの初期化を終了する(初

VS 2005 資料 【電脳梁山泊 烏賊塾】

-9-

大文字と小文字の区別

大文字と小文字の区別が異なれば、DataSet に存在する 2 つ以上のテーブルやリレーションが同じ名前

を持つ事が出来る。此の場合、名前を使用してテーブルとリレーションを参照する際に大文字と小文字

が区別される。例えば、DataSet dataSet に Table1 と table1 のテーブルが有る場合、Table1 を参照す

るには dataSet.Tables["Table1"]、table1 を参照するには dataSet.Tables ["table1"] と名前を指定する。

此の孰れかのテーブルの参照に dataSet.Tables ["TABLE1"] と指定すると、例外が発生する。

特定の名前を持つテーブルやリレーションが 1つ而巳の場合、大文字と小文字は区別されない。例えば、

DataSet に Table1 しか存在しない場合は、dataSet.Tables["TABLE1"] を使用して其のテーブルを参

照出来る。

メモ:此の動作は DataSet の CaseSensitive プロパティの影響を受けない。CaseSensitive プロパティ

は、DataSet 内のデータに適用され、並替、検索、フィルタ処理、制約の適用等に影響を及ぼす。

名前空間のサポート

以前のバージョンの ADO.NET では、異なる名前空間に存在して居るテーブルで有っても、2 つのテー

ブルが同じ名前を持つ事は出来なかった。ADO.NET 2.0 には、此の制限は無い。従って、DataSet に、

Namespace プロパティ値が異なり、TableName プロパティ値が一致する 2 つのテーブルが存在しても

問題無い。

■ テーブル間のリレーションシップの追加

複数の DataTable オブジェクトを含む DataSet では、DataRelation オブジェクトを使用して 1 つのテ

ーブルを別のテーブルに関連付けたり、テーブル間を移動したり、関連付けたテーブルから子や親の行

を戻したり出来る。

DataRelation の作成に必要な引数は、作成する DataRelation の名前、及び、其のリレーションシップ

で親子の列と成る列への 1 つ以上の DataColumn 参照の配列で有る DataRelation の作成後、

DataRelation を使用してテーブル間の移動や値の取得を行う事が出来る。

DataSet への DataRelation の追加は、既定では、 UniqueConstraint が親テーブルに、

ForeignKeyConstraint が子テーブルに追加される。上記の既定の制約の詳細に付いては、「テーブルへ

の制約の追加」を参照され度い。

DataSet に有る 2 つの DataTable オブジェクトを使用して、DataRelation を作成するコード例を次に

示す。各 DataTable には、2 つの DataTable オブジェクト間のリンクと成る CustID と謂う名前の列が

有る。例では、単一の DataRelation が DataSet の Relations コレクションに追加される。例に有る最

初の引数には、作成する DataRelation の名前を指定する。2 番目の引数に依って親の DataColumn が、

3 番目の引数に依って子の DataColumn が設定される。

Visual Basic

customerOrders.Relations.Add("CustOrders", _

customerOrders.Tables("Customers").Columns("CustID"), _

customerOrders.Tables("Orders").Columns("CustID"))

C#

customerOrders.Relations.Add("CustOrders",

customerOrders.Tables["Customers"].Columns["CustID"],

customerOrders.Tables["Orders"].Columns["CustID"]);

DataRelation には、入れ子に成ったプロパティも有る。true に設定すると、WriteXml を使用して XML

要素と仕て書き込む時に、親テーブルの関連付けられた行の中で子テーブルの行が入れ子に成る。詳細

に付いては、「DataSet での XML の使用」を参照され度い。

Page 10: データセット - xdomainjunko036.html.xdomain.jp/pdf/database/DataSet.pdfVS 2005 資料 【電脳梁山泊 烏賊塾】 -3- EndInit フォーム又は別のコンポーネントで使用するDataSetの初期化を終了する(初

VS 2005 資料 【電脳梁山泊 烏賊塾】

-10-

■ テーブル間のリレーションシップの移動

DataRelation の主な機能の 1 つは、DataSet の 1 つの DataTable から別の DataTable を移動出来る事

で有る。此の参照に依り、関連付けられた DataTable から単一の DataRow を指定すると、1 つの

DataTable 内の関連する DataRow オブジェクトを総て取得出来る。例えば、顧客のテーブルとオーダ

ーのテーブル間に DataRelation を確立すると、GetChildRows を使用して特定の顧客行のオーダー行

を総て取得出来る。

DataSet の Customers テーブルと Orders テーブル間の DataRelation を作成し、各顧客の総てのオー

ダーを返すコード例を次に示す。

上記の例に基づいて、4 つのテーブルを相互に関連付け、其のテーブルのリレーションシップ間を移動

する例を次に示す。上記の例に示す様に、CustomerID は Customers テーブルを Orders テーブルに関

連付ける。Customers テーブルに有る各顧客に対しては、Orders テーブルに有る総ての子の行が確定

され、該当する顧客のオーダー数と其の OrderID の値が返される。

展開された例では、OrderDetails テーブルと Products テーブルからも値が返される。各顧客のオーダ

ーに対しては、オーダーされた製品と数量を示す為に、OrderID を使用して Orders テーブルが

OrderDetails テーブルに関連付けられる。OrderDetails テーブルに含まれて居るのは、オーダーされ

た製品の ProductID 丈で有る為、ProductID を使用して、OrderDetails を Products に関連付けて

ProductName を返す。此のリレーションでは、Products テーブルが親と成り、OrderDetails テーブル

が子と成る。其の結果、OrderDetails テーブルを順次処理すると、GetParentRow が呼び出され、関連

付けられた ProductName の値を取得する。

DataRelation が Customers テーブルと Orders テーブルに対して作成された場合には、

createConstraints フラグには値が指定されない(既定値は true)。此れは、Orders テーブルに有る総

ての行に対して親の Customers テーブルに有る CustomerID の値が設定されて居る為で有る Orders

テーブルに、Customers テーブルに存在しない CustomerID が存在する場合、ForeignKeyConstraint

は例外をスローする。

親の列に含まれて居ない値が子の列に含まれる場合、DataRelation の追加時に createConstraints フラ

グが false に設定される。例では、Orders テーブルと OrderDetails テーブル間の DataRelation に対し

て、createConstraints フラグが false に設定されて居る。此の為、此のアプリケーションでは

OrderDetails テーブルから総てのレコードを返し、実行時に例外を生成せずに Orders テーブルからレ

コードのサブセット丈を返す事が出来る。展開された例では、次の形式で出力が生成される。

Customer ID: NORTS

Order ID: 10517

Order Date: 4/24/1997 12:00:00 AM

Product: Filo Mix

Quantity: 6

Product: Raclette Courdavault

Quantity: 4

Product: Outback Lager

Quantity: 6

Order ID: 11057

Order Date: 4/29/1998 12:00:00 AM

Product: Outback Lager

Quantity: 3

Orders テーブルのレコードのサブセット丈と共に、OrderDetails テーブルと Products テーブルからの

値が返された場合に展開された例を次のコード例に示す。

Page 11: データセット - xdomainjunko036.html.xdomain.jp/pdf/database/DataSet.pdfVS 2005 資料 【電脳梁山泊 烏賊塾】 -3- EndInit フォーム又は別のコンポーネントで使用するDataSetの初期化を終了する(初

VS 2005 資料 【電脳梁山泊 烏賊塾】

-11-

Visual Basic

Dim customerOrdersRelation As DataRelation = _ customerOrders.Relations.Add("CustOrders", _ customerOrders.Tables("Customers").Columns("CustomerID"), _ customerOrders.Tables("Orders").Columns("CustomerID")) Dim orderDetailRelation As DataRelation = _ customerOrders.Relations.Add("OrderDetail", _ customerOrders.Tables("Orders").Columns("OrderID"), _ customerOrders.Tables("OrderDetails").Columns("OrderID"), False) Dim orderProductRelation As DataRelation = _ customerOrders.Relations.Add("OrderProducts", _ customerOrders.Tables("Products").Columns("ProductID"), _ customerOrders.Tables("OrderDetails").Columns("ProductID")) Dim custRow, orderRow, detailRow As DataRow For Each custRow In customerOrders.Tables("Customers").Rows Console.WriteLine("Customer ID:" & custRow("CustomerID").ToString( )) For Each orderRow In custRow.GetChildRows(customerOrdersRelation) Console.WriteLine("Order ID: " & orderRow("OrderID").ToString( )) Console.WriteLine(vbTab & "Order Date: " & orderRow("OrderDate").ToString( )) For Each detailRow In orderRow.GetChildRows(orderDetailRelation) Console.WriteLine(vbTab & " Product: " & _ detailRow.GetParentRow(orderProductRelation) ("ProductName").ToString( )) Console.WriteLine(vbTab & "Quantity: " & detailRow("Quantity").ToString( )) Next Next Next

C#

DataRelation customerOrdersRelation = customerOrders.Relations.Add("CustOrders", customerOrders.Tables["Customers"].Columns["CustomerID"], customerOrders.Tables["Orders"].Columns["CustomerID"]); DataRelation orderDetailRelation = customerOrders.Relations.Add("OrderDetail", customerOrders.Tables["Orders"].Columns["OrderID"], customerOrders.Tables["OrderDetails"].Columns["OrderID"], false); DataRelation orderProductRelation = customerOrders.Relations.Add("OrderProducts", customerOrders.Tables["Products"].Columns["ProductID"], customerOrders.Tables["OrderDetails"].Columns["ProductID"]); foreach (DataRow custRow in customerOrders.Tables["Customers"].Rows) { Console.WriteLine("Customer ID: " + custRow["CustomerID"]); foreach (DataRow orderRow in custRow.GetChildRows(customerOrdersRelation)) { Console.WriteLine("Order ID: " + orderRow["OrderID"]); Console.WriteLine("¥tOrder Date: " + orderRow["OrderDate"]); foreach (DataRow detailRow in orderRow.GetChildRows(orderDetailRelation)) { Console.WriteLine("¥t Product: " + detailRow.GetParentRow(orderProductRelation)["ProductName"]); Console.WriteLine("¥t Quantity: " + detailRow["Quantity"]); } } }

Page 12: データセット - xdomainjunko036.html.xdomain.jp/pdf/database/DataSet.pdfVS 2005 資料 【電脳梁山泊 烏賊塾】 -3- EndInit フォーム又は別のコンポーネントで使用するDataSetの初期化を終了する(初

VS 2005 資料 【電脳梁山泊 烏賊塾】

-12-

■ 既存のデータを含む DataSet の使用

DataSet は、データソースに依存しないデータに対するメモリ内のリレーショナル形式で有る。但

し、.NET Framework データプロバイダで使用する場合には、DataSet はデータソース内の既存デー

タと共に使用出来る。.NET Framework データプロバイダでは、DataAdapter を使用してデータソー

スのデータに加えた変更を解決する丈でなく、DataSet にデータやスキーマの情報を格納する。

DataSet の読み込みや、データソースのデータに加えた変更の解決の詳細に付いては、次の資料を参照

され度い。

・DataAdapter からの DataSet の読み込み。此の資料では、データソースのデータを含む DataSet を

読み込む方法に付いて説明する。

・DataAdapter に依るデータソースの更新。此の資料では、DataSet のデータに加えた変更を解決して

データソースに戻る方法に付いて説明する。

・DataSet への既存の制約の追加。此の資料では、データソースの主キー情報を含む DataSet を設定す

る方法に付いて説明する。

・DataAdapter に依るパラメータの使用、及び、パラメータと戻り値の指定。此等の資料では、DataSet

に有るテーブルの列をデータソースで実行されたコマンドの入力、及び、出力パラメータに関連付け

る方法に付いて説明する。

DataSet では、既存の XML データの読み取りや書き込みを行う事も出来る。詳細に付いては、「DataSet

での XML の使用」を参照され度い。

DataAdapter からの DataSet の読み込み

ADO.NET の DataSet は、データソースに依存しない一貫したリレーショナルプログラミングモデルを

提供するメモリ常駐型のデータ表現で有る。DataSet はテーブル、制約、及び、テーブル間のリレーシ

ョンシップを含む完全なデータのセットを表す。DataSet はデータソースとは独立して居る為、DataSet

には、其のアプリケーションに固有のデータと複数のデータソースからのデータを含める事が出来る。

既存のデータソースとの対話は DataAdapter に依って制御される。

DataAdapter の SelectCommand プロパティは、データソースからデータを取得する Command オブ

ジェクトで有る。DataAdapter の InsertCommand、UpdateCommand、DeleteCommand の各プロパ

ティは、DataSet のデータに対して行われた変更に基づいてデータソースのデータ更新を管理する

Command オブジェクトで有る。此等のプロパティに付いては、「DataAdapter に依るデータソースの

更新」で更に詳しく説明する。

DataAdapter の Fill メソッドは、DataAdapter の SelectCommand の結果を使用して DataSet を設定

する為に使用する。Fill は、自らの引数と仕て、設定対象で有る DataSet と、DataTable オブジェクト

(詰まり、SelectCommand が返した行を格納して居る DataTable の名前)を受け取る。

Fill メソッドは、DataReader オブジェクトを暗黙的に使用して DataSet 内でテーブルを作成する為の

列の名前と型、及び、DataSet 内のテーブルの行を設定する為のデータを返す。テーブルと列は、存在

しない場合に丈作成される。既に存在する場合は、Fill は既存の DataSet スキーマを使用する。列の型

は、「.NET Framework データプロバイダのデータ型から.NET Framework のデータ型への変換」の表

に基づき .NET Framework の型と仕て作成される。データソースに主キーが存在し、

DataAdapter.MissingSchemaActionがMissingSchemaAction.AddWithKeyに設定されて居る場合丈、

主キーが作成されるが、其れ以外の場合は主キーは作成されない。Fill はテーブルに主キーが有る事が

解ると、主キー列の値がデータソースから返された主キー列の値と一致する行に付いて、データソース

Page 13: データセット - xdomainjunko036.html.xdomain.jp/pdf/database/DataSet.pdfVS 2005 資料 【電脳梁山泊 烏賊塾】 -3- EndInit フォーム又は別のコンポーネントで使用するDataSetの初期化を終了する(初

VS 2005 資料 【電脳梁山泊 烏賊塾】

-13-

から返されたデータで DataSet 内のデータを上書きする。主キーが見付からない場合は、DataSet のテ

ーブルの末尾にデータを追加する。Fill は DataSet にデータを読み込む時に存在する総てのマッピング

を使用する(「DataTable と DataColumn のマップの設定」を参照され度い)。

メモ:SelectCommand が OUTER JOIN の結果を返す場合、DataAdapter は、生成される DataTable

に PrimaryKey 値を設定しない。開発者が PrimaryKey を定義して、重複行が正しく解決される様にす

る必要が有る。詳細に付いては、「テーブルの主キーの定義」を参照され度い。

Microsoft SQL Server Northwind データベースへの SqlConnection を使用し DataSet 内の DataTable

に顧客リストを読み込む SqlDataAdapter のインスタンスを作成するコード例を次に示す。

SqlDataAdapter コンストラクタに渡される SQL ステートメントと SqlConnection 引数は、

SqlDataAdapter の SelectCommand プロパティを作成する為に使用される。

Visual Basic

' Assumes that connection is a valid SqlConnection object.

Dim queryString As String = "SELECT CustomerID, CompanyName FROM dbo.Customers"

Dim adapter As SqlDataAdapter = New SqlDataAdapter( queryString, connection)

Dim customers As DataSet = New DataSet

adapter.Fill(customers, "Customers")

C#

// Assumes that connection is a valid SqlConnection object.

string queryString = "SELECT CustomerID, CompanyName FROM dbo.Customers";

SqlDataAdapter adapter = new SqlDataAdapter(queryString, connection);

DataSet customers = new DataSet( );

adapter.Fill(customers, "Customers");

メモ:此のサンプルコードでは、Connection の開始と終了を明示的に行って居ない。Fill メソッドは、

接続が未だ開いて居ない事を認識すると DataAdapter が使用して居る Connection を暗黙的に開く。

Fill が接続を開いた場合は、Fill の終了時に Fill が接続を終了する。此れに依り、Fill や Update 等の

単一の操作を扱う場合にコードを簡略化出来る。此れに対し、開いて居る接続を必要とする複数の操作

を実行する場合は、Connection の Open メソッドを明示的に呼び出し、データソースに対する操作の

実行後に Connection の Close メソッドを呼び出す事でアプリケーションのパフォーマンスを改善出来

る。リソースを解放して他のクライアントアプリケーションが使用出来る様にする為に、データソース

への接続を開いた儘にする時間は最小限にする事を推奨する。

・複数結果セット

DataAdapter は複数の結果セットを検出すると、DataSet に複数のテーブルを作成する。此等のテーブ

ルには、Table0 の様に、Table で始まるインクリメンタル既定名 TableN が割り当てられる。テーブル

名を引数と仕て Fill メソッドに渡すと、TableName0 を表す TableName で始まるインクリメンタル既

定名 TableNameN が割り当てられる。

・複数の DataAdapter からの DataSet の読み込み

1 つの DataSet で、任意の数の DataAdapter オブジェクトを使用出来る。夫々れの DataAdapter で 1

つ以上の DataTable オブジェクトにデータを格納し、関連するデータソースに更新を反映させる事が出

来る。DataSet に対して、DataRelation オブジェクトや Constraint オブジェクトを部分的に追加出来

る為、開発者は複数の異なるデータソースから取得したデータを関連付ける事が出来る。例えば、

Microsoft SQL Server データベース、OLE DB を通じて公開される IBM DB2 データベース、及び、

XML をストリーム転送するデータソースからのデータを DataSet に含める事が出来る。1 つ以上の

DataAdapter オブジェクトを使用して、各データソースとの通信を行う事が出来る。

Page 14: データセット - xdomainjunko036.html.xdomain.jp/pdf/database/DataSet.pdfVS 2005 資料 【電脳梁山泊 烏賊塾】 -3- EndInit フォーム又は別のコンポーネントで使用するDataSetの初期化を終了する(初

VS 2005 資料 【電脳梁山泊 烏賊塾】

-14-

・例

次のコード例では、Microsoft SQL Server 2000 の Northwind データベースからの顧客リストと

Microsoft Access 2000 に格納されて居る Northwind データベースからの注文リストを取得する。デー

タが格納されて居るテーブルが DataRelation に関連付けられ、顧客の一覧が各顧客の注文と共に表示

される。DataRelation オブジェクトの詳細に付いては、「テーブル間のリレーションシップの追加」及

び「テーブル間のリレーションシップの移動」を参照され度い。

Visual Basic

' Assumes that customerConnection is a valid SqlConnection object.

' Assumes that orderConnection is a valid OleDbConnection object.

Dim custAdapter As SqlDataAdapter = New SqlDataAdapter( _

"SELECT * FROM dbo.Customers", customerConnection)

Dim ordAdapter As OleDbDataAdapter = New OleDbDataAdapter( _

"SELECT * FROM Orders", orderConnection)

Dim customerOrders As DataSet = New DataSet( )

custAdapter.Fill(customerOrders, "Customers")

ordAdapter.Fill(customerOrders, "Orders")

Dim relation As DataRelation = _

customerOrders.Relations.Add("CustOrders", _

customerOrders.Tables("Customers").Columns("CustomerID"), _

customerOrders.Tables("Orders").Columns("CustomerID"))

Dim pRow, cRow As DataRow

For Each pRow In customerOrders.Tables("Customers").Rows

Console.WriteLine(pRow("CustomerID").ToString( ))

For Each cRow In pRow.GetChildRows(relation)

Console.WriteLine(vbTab & cRow("OrderID").ToString( ))

Next

Next

C#

// Assumes that customerConnection is a valid SqlConnection object.

// Assumes that orderConnection is a valid OleDbConnection object.

SqlDataAdapter custAdapter = new SqlDataAdapter(

"SELECT * FROM dbo.Customers", customerConnection);

OleDbDataAdapter ordAdapter = new OleDbDataAdapter(

"SELECT * FROM Orders", orderConnection);

DataSet customerOrders = new DataSet( );

custAdapter.Fill(customerOrders, "Customers");

ordAdapter.Fill(customerOrders, "Orders");

DataRelation relation = customerOrders.Relations.Add("CustOrders",

customerOrders.Tables["Customers"].Columns["CustomerID"],

customerOrders.Tables["Orders"].Columns["CustomerID"]);

foreach (DataRow pRow in customerOrders.Tables["Customers"].Rows)

{

Console.WriteLine(pRow["CustomerID"]);

foreach (DataRow cRow in pRow.GetChildRows(relation))

Console.WriteLine("¥t" + cRow["OrderID"]);

}

Page 15: データセット - xdomainjunko036.html.xdomain.jp/pdf/database/DataSet.pdfVS 2005 資料 【電脳梁山泊 烏賊塾】 -3- EndInit フォーム又は別のコンポーネントで使用するDataSetの初期化を終了する(初

VS 2005 資料 【電脳梁山泊 烏賊塾】

-15-

・SQL Server の 10 進数型

既定では、DataSet は、.NET Framework のデータ型を使用してデータを格納する。殆どのアプリケ

ーションで、此等のデータ型を使用してデータソース情報を簡単に表示出来る。併し、データソースの

データ型が SQL Server の 10 進数データ型や数値データ型の場合は、此の表現に依って問題が生じる

場合が有る。.NET Frameworkのdecimalデータ型の最大有効桁数は28桁で有るのに対し、SQL Server

の decimal データ型の有効桁数は 38 桁で有る。Fill が動作して居る間に、SqlDataAdapter が、SQL

Serverのdecimalフィールドの有効桁数が28文字を超えて居ると判断した場合、現在の行はDataTable

に追加されない。其の場合は FillError イベントが発生する為、開発者は有効桁数の消失が発生して居

ないか何うかを確認し、適切に対応出来る。FillError イベントの詳細に付いては、「DataAdapter イベ

ントの使用」を参照され度い。SQL Server の decimal 値を取得するには、SqlDataReader オブジェク

トを使用し、GetSqlDecimal メソッドを呼び出す事も出来る。

ADO.NET 2.0 では、DataSet の System.Data.SqlTypes に対するサポート機能が強化されて居る。詳

細に付いては、「SqlTypes と DataSet」を参照され度い。

・OLE DB のチャプタ

階層構造の行セット、詰まり、チャプタ(OLE DB では DBTYPE_HCHAPTER 型、ADO では adChapter

型)を使用して DataSet の内容を格納出来る。OleDbDataAdapter が Fill が動作して居る間にチャプ

タ列を検出すると、其のチャプタ列の為の DataTable を作成し、チャプタから取得した列と行を此のテ

ーブルに格納する。チャプタ列用に作成されたテーブルには、親テーブルの名前とチャプタ列の名前の

両方を使用した ParentTableNameChapteredColumnName 形式の名前が割り当てられる。DataSet

にチャプタ列の名前と一致するテーブルが既に存在する場合は、現在のテーブルにチャプタデータが格

納される。既存のテーブルにチャプタ内の列と一致する列が存在しない場合は、新しい列が追加される。

DataSet 内のテーブルにチャプタ列のデータを格納する前に、親テーブルと子テーブルの両方に 1 つの

整数列を追加し、親列を自動インクリメントに設定し、両方のテーブルに追加された列を使用して

DataRelation を作成すると、階層構造の行セットを形成して居る親テーブルと子テーブルの間にリレ

ーションが作成される。追加されたリレーションには親テーブルの名前とチャプタ列の名前を使用した

ParentTableNameChapterColumnName 形式の名前が割り当てられる。

関連付けられた列は、DataSet 丈に存在する。其のデータソースからの次の Fill 操作を実行すると、

変更を既存の行にマージするのではなく、テーブルに新しい行が追加される。

DataTable を受け取る DataAdapter.Fill オーバーロードを使用した場合は、其のテーブル丈にデータ

が格納される。自動インクリメント整数列は、引き続き其のテーブルに追加されるが、子テーブルの作

成、子テーブルへのデータの格納、及び、リレーションの作成は行われない。

MSDataShapeプロバイダを使用して顧客リスト内の各顧客に対応するオーダー列を生成する例を次に

示す。チャプタ列を生成した後で、1 つの DataSet 内に其のデータを格納する。

Visual Basic

Using connection As OleDbConnection = New OleDbConnection( _

"Provider=MSDataShape;Data Provider=SQLOLEDB;" & _

"Data Source=(local);Integrated " & _

"Security=SSPI;Initial Catalog=northwind")

Dim adapter As OleDbDataAdapter = New OleDbDataAdapter( _

"SHAPE {SELECT CustomerID, CompanyName FROM Customers} " & _

"APPEND ({SELECT CustomerID, OrderID FROM Orders} AS Orders " & _

"RELATE CustomerID TO CustomerID)", connection)

Page 16: データセット - xdomainjunko036.html.xdomain.jp/pdf/database/DataSet.pdfVS 2005 資料 【電脳梁山泊 烏賊塾】 -3- EndInit フォーム又は別のコンポーネントで使用するDataSetの初期化を終了する(初

VS 2005 資料 【電脳梁山泊 烏賊塾】

-16-

Dim customers As DataSet = New DataSet( )

adapter.Fill(customers, "Customers")

End Using

C#

using (OleDbConnection connection = new OleDbConnection(

"Provider=MSDataShape;Data Provider=SQLOLEDB;" +

"Data Source=(local);Integrated Security=SSPI;Initial Catalog=northwind"))

{

OleDbDataAdapter adapter = new OleDbDataAdapter(

"SHAPE {SELECT CustomerID, CompanyName FROM Customers} " +

"APPEND ({SELECT CustomerID, OrderID FROM Orders} AS Orders " +

"RELATE CustomerID TO CustomerID)", connection);

DataSet customers = new DataSet( );

adapter.Fill(customers, "Customers");

}

Fill 操作が完了すると、DataSet に Customers と CustomersOrders の 2 つのテーブルが格納される。

CustomersOrders はチャプタ列を表す。Orders と謂う列が Customers テーブルに追加され、

CustomersOrdersと謂う列がCustomersOrdersテーブルに追加される。CustomersテーブルのOrders

列は、自動インクリメントに設定される。親テーブルで有る Customers テーブルに追加された列を使

用して、CustomersOrders と謂う DataRelation が作成される。サンプル結果の一部を次の表に示す。

TableName:Customers

CustomerID CompanyName Orders

ALFKI Alfreds Futterkiste 0

ANATR Ana Trujillo Emparedados y helados 1

TableName:CustomersOrders

CustomerID OrderID CustomersOrders

ALFKI 10643 0

ALFKI 10692 0

ANATR 10308 1

ANATR 10625 1

DataAdapter に依るデータソースの更新

DataAdapter の Update メソッドを呼び出して、変更を DataSet からデータソースに反映する。Update

メソッドは、Fillメソッドと同様に、引数と仕てDataSetのインスタンス、及び、オプションのDataTable

オブジェクト、又は、DataTable 名を受け取る。DataSet のインスタンスは、行われた変更点を格納す

る DataSet で有る DataTable は、変更点の取得元のテーブルで有る。

Update メソッドを呼び出すと、DataAdapter は、既に加えられた変更を解析し、適切なコマンド

(INSERT、UPDATE、又は、DELETE)を実行する。DataAdapter は DataRow へ加えられた変更

を検出すると、InsertCommand、UpdateCommand、又は、DeleteCommand を使用して其の変更を

処理する。其の結果、デザイン時にコマンド構文を指定し、可能な場合はストアドプロシージャを使用

する事に依り、ADO.NET アプリケーションのパフォーマンスを最適化出来る。コマンドは Update を

呼び出す前に明示的に設定する必要が有る。Update を呼び出し、其の更新に関連する適切なコマンド

が存在しない場合(例えば、削除済みの行に関連する DeleteCommand が存在しない場合)は、例外が

スローされる。

Page 17: データセット - xdomainjunko036.html.xdomain.jp/pdf/database/DataSet.pdfVS 2005 資料 【電脳梁山泊 烏賊塾】 -3- EndInit フォーム又は別のコンポーネントで使用するDataSetの初期化を終了する(初

VS 2005 資料 【電脳梁山泊 烏賊塾】

-17-

Command パラメータを使用して、DataSet 内の各変更行に対する SQL ステートメントやストアドプ

ロシージャに入力値と出力値を指定出来る。詳細に付いては、「DataAdapter に依るパラメータの使用」

を参照され度い。

DataTable を単一データベーステーブルに割り当てたり、単一データベースから生成する場合は、

DbCommandBuilder オブジェクトを利用して自動的に DataAdapter の DeleteCommand、

InsertCommand、及び、UpdateCommand を生成出来る。詳細に付いては、「コマンドの自動生成」

を参照され度い。

Update メソッドは変更点を元のデータソースに反映させるが、DataSet に最後にデータを格納した後、

他のクライアントがデータソースのデータを変更した可能性も有る。DataSet を現在のデータで更新す

るには、DataAdapter と Fill メソッドを使用する。新しい行がテーブルに追加され、更新された情報

が既存の行に取り込まれる。Fill メソッドは、DataSet の行と SelectCommand に依って返された行の

主キーの値を調べて、新しい行が追加されたか、又は、既存の行が更新されたかを判断する。Fill メソ

ッドは、SelectCommand に依って返された結果の行に一致する主キーの値を持つ DataSet の行を見付

けた場合、SelectCommand に依って返された行の情報で既存の行を更新して、既存の行の RowState

を Unchanged に設定する。SelectCommand に依って返された行の主キーの値が、DataSet の何の行

の主キーの値にも一致しない場合、Fill メソッドは、RowState が Unchanged の新しい行を追加する。

メモ:SelectCommand が OUTER JOIN の結果を返す場合、DataAdapter は、生成される DataTable

に PrimaryKey 値を設定しない。自分で PrimaryKey を定義して、重複行が正しく反映される様にする

必要が有る。詳細に付いては、「テーブルの主キーの定義」を参照され度い。

Update メソッド呼出時に発生する例外を処理するには、行更新エラーが発生した時に RowUpdated イ

ベントを使用して応答するか(「DataAdapter イベントの使用」を参照)、又は、Update メソッド呼出

の前に DataAdapter.ContinueUpdateOnError を true に設定し、更新が完了した時点で特定の行の

RowError プロパティに格納されて居るエラー情報に応答する(「行のエラー情報の追加と読み取り」を

参照)。

メモ:DataSet、DataTable、又は、DataRow に対して AcceptChanges を呼び出すと、DataRow の総

ての Original 値が DataRow の Current 値で上書きされる。行を一意に識別するフィールド値が変更さ

れた場合は、AcceptChanges 呼出の後、Original 値はデータソースの値と一致しなく成る。

・例

DataAdapter の UpdateCommand を明示的に設定して、変更済みの行に対して更新を実行する方法を

次の例に示す。UPDATE ステートメントの WHERE 句に指定したパラメータが SourceColumn の

Original値を使用する様に設定されて居る事に注意され度い。Current値が既に変更されて居る可能性、

然して、データソースの値と一致して居ない可能性が有る為、此の設定は重要で有る。Original 値は、

データソースから DataTable にデータを取得する為に使用された値で有る

Visual Basic

' Assumes connection is a valid SqlConnection.

Dim adapter As SqlDataAdapter = New SqlDataAdapter( _

"SELECT CategoryID, CategoryName FROM Categories", connection)

adapter.UpdateCommand = New SqlCommand( _

"UPDATE Categories SET CategoryName = @CategoryName " & _

"WHERE CategoryID = @CategoryID", connection)

adapter.UpdateCommand.Parameters.Add( _

"@CategoryName", SqlDbType.NVarChar, 15, "CategoryName")

Dim parameter As SqlParameter = adapter.UpdateCommand.Parameters.Add( _

"@CategoryID", SqlDbType.Int)

Page 18: データセット - xdomainjunko036.html.xdomain.jp/pdf/database/DataSet.pdfVS 2005 資料 【電脳梁山泊 烏賊塾】 -3- EndInit フォーム又は別のコンポーネントで使用するDataSetの初期化を終了する(初

VS 2005 資料 【電脳梁山泊 烏賊塾】

-18-

parameter.SourceColumn = "CategoryID"

parameter.SourceVersion = DataRowVersion.Original

Dim dataSet As DataSet = New DataSet

adapter.Fill(dataSet, "Categories")

Dim row As DataRow = dataSet.Tables("Categories").Rows(0)

row("CategoryName") = "New Category"

adapter.Update(dataSet, "Categories")

C#

// Assumes connection is a valid SqlConnection.

SqlDataAdapter dataAdpater = new SqlDataAdapter(

"SELECT CategoryID, CategoryName FROM Categories", connection);

dataAdpater.UpdateCommand = new SqlCommand(

"UPDATE Categories SET CategoryName = @CategoryName " +

"WHERE CategoryID = @CategoryID" , connection);

dataAdpater.UpdateCommand.Parameters.Add(

"@CategoryName", SqlDbType.NVarChar, 15, "CategoryName");

SqlParameter parameter = dataAdpater.UpdateCommand.Parameters.Add(

"@CategoryID", SqlDbType.Int);

parameter.SourceColumn = "CategoryID";

parameter.SourceVersion = DataRowVersion.Original;

DataSet dataSet = new DataSet( );

dataAdpater.Fill(dataSet, "Categories");

DataRow row = dataSet.Tables["Categories"].Rows[0];

row ["CategoryName"] = "New Category";

dataAdpater.Update(dataSet, "Categories");

・AutoIncrement 列

データソースからのテーブルに自動インクリメント列が有る場合、DataSet の列に値を格納するには、

自動インクリメント値をストアドプロシージャの出力パラメータと仕て返して其れをテーブルの列に

割り当てるか、又は、DataAdapter の RowUpdated イベントを使用する。此の例に付いては、「ID 値

及び Autonumber 値の取得」を参照され度い。

但し、DataSet 内の値はデータソースの値と同期しなく成る為、予期しない動作を発生する場合が有る。

例えば、CustomerID と謂う自動インクリメント主キー列を持つテーブルが有るとする。DataSet 内に

新しい 2 人の顧客を追加した場合、此等の顧客は自動インクリメント CustomerId 値 1 及び 2 を受け取

る。2 行目の顧客行が DataAdapter の Update メソッドに渡されると、新しく追加された行は、データ

ソースで自動インクリメント CustomerID 値 1 を受け取る。此れは DataSet 内の値 2 とは一致しない。

DataAdapter が DataSet の行に戻り値を設定すると、1 行目の顧客行が既に CustomerID 値と仕て 1

を持つ為、制約違反が発生する。

此の様な動作を防ぐには、データソースの自動インクリメント列、及び、DataSet の自動インクリメン

ト値を使用する時に、AutoIncrementStep を-1、AutoIncrementSeed を 0 に設定して DataSet に列を

作成し、同時に 1 から始まり正のステップ値でインクリメントする自動インクリメント ID 値がデータ

ソースで生成される様にする。其の結果、DataSet では自動インクリメント値と仕て負の数値が生成さ

れる為、データソースで生成される正の自動インクリメント値と矛盾しなく成る。今 1 つの方法は、自

Page 19: データセット - xdomainjunko036.html.xdomain.jp/pdf/database/DataSet.pdfVS 2005 資料 【電脳梁山泊 烏賊塾】 -3- EndInit フォーム又は別のコンポーネントで使用するDataSetの初期化を終了する(初

VS 2005 資料 【電脳梁山泊 烏賊塾】

-19-

動インクリメント列の代わりに Guid 型の列を使用する事で有る。Guid 値生成のアルゴリズムでは、デ

ータソースで生成される Guid と同じ Guid が DataSet で生成される事は無い。DataTable の列を定義

する方法の詳細に付いては、「DataTable のスキーマの定義」を参照され度い。

・挿入、更新、削除の順序

通常の条件下では、DataSet を使用して行う変更の順序をデータソースに送信する事が重要で有る。例

えば、既存の行の主キーの値を更新し、其の新しい主キーの値で新しい行を追加する場合、更新は挿入

の前に処理する必要が有る。

DataTable の Select メソッドを使用すると、特定の RowState を持つ行丈を参照する DataRow 配列を

返す事が出来る。其の後で、返された DataRow 配列を DataAdapter の Update メソッドに渡して変更

行を処理出来る。更新する行のサブセットを指定する事で、挿入、更新、及び、削除の処理順序を制御

出来る。

・例

例えば次のコードでは、テーブルの削除行を最初に処理し、次に更新行、最後に挿入行を処理する。

Visual Basic

Dim table As DataTable = dataSet.Tables("Customers")

' First process deletes.

dataSet.Update(table.Select(Nothing, Nothing, DataViewRowState.Deleted))

' Next process updates.

adapter.Update(table.Select(Nothing, Nothing, DataViewRowState.ModifiedCurrent))

' Finally, process inserts.

dataAdpater.Update(table.Select(Nothing, Nothing, DataViewRowState.Added))

C#

DataTable table = dataSet.Tables["Customers"];

// First process deletes.

adapter.Update(table.Select(null, null, DataViewRowState.Deleted));

// Next process updates.

adapter.Update(table.Select(null, null, DataViewRowState.ModifiedCurrent));

// Finally, process inserts.

adapter.Update(table.Select(null, null, DataViewRowState.Added));

DataSet への既存の制約の追加

DataAdapter の Fill メソッドは、DataSet にデータソースからのテーブルの列と行丈を格納する。制

約は一般にデータソースで設定されるが、既定では Fill メソッドは DataSet にスキーマ情報を追加し

ない。データソースからの既存の主キー制約情報を DataSet に設定するには、DataAdapter の

FillSchema メソッドを呼び出すか、又は、Fill を呼び出す前に DataAdapter の MissingSchemaAction

プロパティを AddWithKey に設定する。此れに依り、データソースの主キー制約が DataSet の主キー

制約に反映される。外部キー制約情報はインクルードされない為、「テーブルへの制約の追加」で示す

様に明示的に作成する必要が有る。

DataSet 内にデータを格納する前にスキーマ情報を追加すると、主キー制約が DataSet 内の DataTable

Page 20: データセット - xdomainjunko036.html.xdomain.jp/pdf/database/DataSet.pdfVS 2005 資料 【電脳梁山泊 烏賊塾】 -3- EndInit フォーム又は別のコンポーネントで使用するDataSetの初期化を終了する(初

VS 2005 資料 【電脳梁山泊 烏賊塾】

-20-

オブジェクトにインクルードされる。其の結果、DataSet に対して格納を行う追加の呼出を行った時、

其の主キー列情報を使用してデータソースから得られた新しい行と各 DataTable の現在の行を一致さ

せ、各テーブルの現在のデータをデータソースのデータで上書きする。スキーマ情報が無いと、DataSet

にデータソースからの新しい行が付け加えられ、重複行が発生する。

メモ:データソースの列を自動インクリメント列と仕て指定した場合は、FillSchema メソッド

(MissingSchemaAction を AddWithKey に設定した Fill メソッド)が、AutoIncrement プロパティを

true に設定した DataColumn を作成する。但し、AutoIncrementStep 値と AutoIncrementSeed 値は

明示的に設定する必要が有る。自動インクリメント列の詳細に付いては、「AutoIncrement 列の作成」

を参照され度い。

FillSchema の使用や MissingSchemaAction の設定を AddWithKey にする場合、データソースで主キ

ー列情報を確認する為の追加の処理が必要に成る。此の追加の処理に依りパフォーマンスが低下する場

合が有る。デザイン時に主キー情報が解って居る場合は、最適のパフォーマンスを得る為に主キー列(複

数の場合も有る)を明示的に指定する事を推奨する。テーブルに関する主キー情報を明示的に設定する

方法に付いては、「テーブルの主キーの定義」を参照され度い。

FillSchema を使用して DataSet にスキーマ情報を追加する方法を次のコード例に示す。

Visual Basic

Dim custDataSet As DataSet = New DataSet( )

custAdapter.FillSchema(custDataSet, SchemaType.Source, "Customers")

custAdapter.Fill(custDataSet, "Customers")

C#

DataSet custDataSet = new DataSet( );

custAdapter.FillSchema(custDataSet, SchemaType.Source, "Customers");

custAdapter.Fill(custDataSet, "Customers");

Fill メソッドのMissingSchemaAction.AddWithKey プロパティを使用してスキーマ情報を DataSetに

追加する方法を次のコード例に示す。

Visual Basic

Dim custDataSet As DataSet = New DataSet( )

custAdapter.MissingSchemaAction = MissingSchemaAction.AddWithKey

custAdapter.Fill(custDataSet, "Customers")

C#

DataSet custDataSet = new DataSet( );

custAdapter.MissingSchemaAction = MissingSchemaAction.AddWithKey;

custAdapter.Fill(custDataSet, "Customers");

・複数結果セット

DataAdapter は、SelectCommand から返された複数の結果セットを検出すると DataSet に複数のテー

ブルを作成する。此等のテーブルには、0 から始まるインクリメンタル既定名 TableN が割り当てられ

る。従って Table0 ではなく、Table から始まる。テーブル名が FillSchema メソッドに引数と仕て渡さ

れると、0 からから始まるインクリメンタル名 TableNameN が割り当てられる。此処では、TableName0

ではなく TableName から始まる。

メモ:OleDbDataAdapter オブジェクトの FillSchema メソッドが複数の結果セットを返すコマンドと

Page 21: データセット - xdomainjunko036.html.xdomain.jp/pdf/database/DataSet.pdfVS 2005 資料 【電脳梁山泊 烏賊塾】 -3- EndInit フォーム又は別のコンポーネントで使用するDataSetの初期化を終了する(初

VS 2005 資料 【電脳梁山泊 烏賊塾】

-21-

仕て呼び出された場合は、最初の結果セットのスキーマ情報が返される。OleDbDataAdapter を使用し

て複数の結果セットのスキーマ情報を返す時は、Fill メソッドを呼び出す時に AddWithKey に設定した

MissingSchemaAction を指定してスキーマ情報を取得する事を推奨する。

DataAdapter に依るパラメータの使用

DataAdapter は、データソースからデータを取得したりデータソースのデータを更新したりする為に使

用される、次の 4 つのプロパティを持って居る。SelectCommand プロパティは、データソースからデ

ータを返す。InsertCommand、UpdateCommand、及び、DeleteCommand の各プロパティは、デー

タソースの変更を管理する為に使用する。SelectCommand プロパティは、DataAdapter の Fill メソッ

ドを呼び出す前に設定する必要が有る。InsertCommand、UpdateCommand、DeleteCommand の各

プロパティは、DataAdapter の Update メソッドを呼び出す前に DataSet 内のデータに対して行われ

た変更に基づいて設定する必要が有る。例えば、行が追加された場合、InsertCommand は Update 呼

出の前に設定されて居る必要が有る。Update が挿入行、更新行、又は、削除行を処理して居る時、

DataAdapter が夫々れの Command プロパティを使用して其のアクションを処理する。変更された行

に付いての現在の情報が Parameters コレクションを通じて Command オブジェクトに渡される。

データソースの行を更新する時は、一意識別子を使用してテーブル内の更新する列を識別する

UPDATE ステートメントを呼び出す。一意識別子は、一般には主キーフィールドの値で有る。UPDATE

ステートメントは、次の Transact-SQL ステートメントで示す様に、一意識別子、及び、更新する列と

値の両方を含むパラメータを使用する。

UPDATE Customers SET CompanyName = @CompanyName WHERE CustomerID = @CustomerID

↑ ↑ ↑

更新する列 値 一意識別子

メモ:パラメータのプレースホルダの構文は、データソースに依って異なる。次に、SQL Server のデ

ータソースのプレースホルダの例を示す。猶、System.Data.OleDb パラメータや System.Data.Odbc

パラメータでは、プレースホルダと仕て、疑問符( ? )を使用する。

此の Visual Basic の例では、CompanyName フィールドは、CustomerID が@CustomerID パラメータ

の値と等しい列の@CompanyName パラメータの値で更新される。此等のパラメータは、SqlParameter

オブジェクトの SourceColumn プロパティを使用して、変更された行から情報を取得する。前のサンプ

ル UPDATE ステートメントのパラメータを次に示す。此のコードは、変数 adapter が有効な

SqlDataAdapter オブジェクトを表す事を前提と仕て居る。

adapter.Parameters.Add("@CompanyName", SqlDbType.NChar, 15, "CompanyName")

Dim parameter As SqlParameter = _

adapter.UpdateCommand.Parameters.Add("@CustomerID", _

SqlDbType.NChar, 5, "CustomerID")

parameter.SourceVersion = DataRowVersion.Original

Parameters コレクションの Add メソッドは、パラメータ名、DataAdapter 固有の型、サイズ(其の型

に適用可能な場合)、及び、DataTable の SourceColumn の名前を受け取る。@CustomerID パラメー

タの SourceVersion が Original に設定されて居る事に注意され度い。此の設定に依り、変更済みの

DataRow の中で、識別を行う 1 つ、又は、複数の列の値が既に変更されて居る場合に、データソース

内の既存の行を更新する事を保証出来る。識別列の値が既に変更されて居る場合は、Original 行の値は

データソースの現在の値と一致し、Current 行の値は更新済みの値を格納する。@CompanyName パラ

メータの SourceVersion は設定されて居ない為、既定の Current の行の値が使用される。

Page 22: データセット - xdomainjunko036.html.xdomain.jp/pdf/database/DataSet.pdfVS 2005 資料 【電脳梁山泊 烏賊塾】 -3- EndInit フォーム又は別のコンポーネントで使用するDataSetの初期化を終了する(初

VS 2005 資料 【電脳梁山泊 烏賊塾】

-22-

・SqlClient の例

SQL ステートメントを SqlDataAdapter の SelectCommand、InsertCommand、UpdateCommand、

DeleteCommand の各プロパティの CommandText と仕て使用する例を次に示す。SqlDataAdapter オ

ブジェクトの場合は、名前付きのパラメータを使用する必要が有る。

Visual Basic

Dim selectSQL As String = _

"SELECT CustomerID, CompanyName FROM Customers " & _

"WHERE CountryRegion = @CountryRegion AND City = @City"

Dim insertSQL As String = _

"INSERT INTO Customers (CustomerID, CompanyName) " & _

"VALUES (@CustomerID, @CompanyName)"

Dim updateSQL As String = _

"UPDATE Customers SET CustomerID = @CustomerID, & _

"CompanyName = @CompanyName " & _

"WHERE CustomerID = @OldCustomerID"

Dim deleteSQL As String = _

"DELETE FROM Customers WHERE CustomerID = @CustomerID"

C#

string selectSQL =

"SELECT CustomerID, CompanyName FROM Customers WHERE CountryRegion = " +

"@CountryRegion AND City = @City";

string insertSQL = "INSERT INTO Customers (CustomerID, CompanyName) " +

"VALUES (@CustomerID, @CompanyName)";

string updateSQL = "UPDATE Customers SET CustomerID = @CustomerID, " +

"CompanyName = @CompanyName WHERE CustomerID = @OldCustomerID";

string deleteSQL =

"DELETE FROM Customers WHERE CustomerID = @CustomerID";

・OleDb 又は Odbc の例

OleDbDataAdapter オブジェクトと OdbcDataAdapter オブジェクトの場合は、疑問符( ? )のプレ

ースホルダを使用してパラメータを識別する必要が有る。

Visual Basic

Dim selectSQL As String = _

"SELECT CustomerID, CompanyName FROM Customers " & _

"WHERE CountryRegion = ? AND City = ?"

Dim insertSQL AS String = _

"INSERT INTO Customers (CustomerID, CompanyName) VALUES (?, ?)"

Dim updateSQL AS String = _

"UPDATE Customers SET CustomerID = ?, CompanyName = ? WHERE CustomerID = ?"

Dim deleteSQL As String = "DELETE FROM Customers WHERE CustomerID = ?"

C#

string selectSQL =

"SELECT CustomerID, CompanyName FROM Customers " +

"WHERE CountryRegion = ? AND City = ?";

string insertSQL =

"INSERT INTO Customers (CustomerID, CompanyName) VALUES (?, ?)";

string updateSQL =

"UPDATE Customers SET CustomerID = ?, CompanyName = ? WHERE CustomerID = ? ";

string deleteSQL = "DELETE FROM Customers WHERE CustomerID = ?";

Page 23: データセット - xdomainjunko036.html.xdomain.jp/pdf/database/DataSet.pdfVS 2005 資料 【電脳梁山泊 烏賊塾】 -3- EndInit フォーム又は別のコンポーネントで使用するDataSetの初期化を終了する(初

VS 2005 資料 【電脳梁山泊 烏賊塾】

-23-

パラメータと仕て使用されるクエリステートメントは、作成する必要の有る入力パラメータと出力パラ

メータを定義する。パラメータを作成するには、Parameters.Add メソッドか Parameter コンストラク

タを使用して列名、データ型、及び、サイズを指定する。Integer 等組み込みのデータ型の場合は、サ

イズを含める必要は無いし、其の場合は自動的に既定のサイズを指定する事に成る。

前の例の SQL ステートメントのパラメータを作成し、DataSet にデータを格納するコード例を次に示

す。

SqlClient

Visual Basic

' Assumes that connection is a valid SqlConnection object.

Dim adapter As SqlDataAdapter = New SqlDataAdapter

Dim selectCMD AS SqlCommand = New SqlCommand(selectSQL, connection)

adapter.SelectCommand = selectCMD

' Add parameters and set values.

selectCMD.Parameters.Add("@CountryRegion", SqlDbType.NVarChar, 15).Value = "UK"

selectCMD.Parameters.Add("@City", SqlDbType.NVarChar, 15).Value = "London"

Dim customers As DataSet = New DataSet

adapter.Fill(customers, "Customers")

C#

// Assumes that connection is a valid SqlConnection object.

SqlDataAdapter adapter = new SqlDataAdapter( );

SqlCommand selectCMD = new SqlCommand(selectSQL, connection);

adapter.SelectCommand = selectCMD;

// Add parameters and set values.

selectCMD.Parameters.Add("@CountryRegion", SqlDbType.NVarChar, 15).Value = "UK";

selectCMD.Parameters.Add("@City", SqlDbType.NVarChar, 15).Value = "London";

DataSet customers = new DataSet( );

adapter.Fill(customers, "Customers");

OleDb

Visual Basic

' Assumes that connection is a valid OleDbConnection object.

Dim adapter As OleDbDataAdapter = New OleDbDataAdapter

Dim selectCMD AS OleDbCommand = New OleDbCommand(selectSQL, connection)

adapter.SelectCommand = selectCMD

' Add parameters and set values.

selectCMD.Parameters.Add("@CountryRegion", OleDbType.VarChar, 15).Value = "UK"

selectCMD.Parameters.Add("@City", OleDbType.VarChar, 15).Value = "London"

Dim customers As DataSet = New DataSet

adapter.Fill(customers, "Customers")

C#

// Assumes that connection is a valid OleDbConnection object.

Page 24: データセット - xdomainjunko036.html.xdomain.jp/pdf/database/DataSet.pdfVS 2005 資料 【電脳梁山泊 烏賊塾】 -3- EndInit フォーム又は別のコンポーネントで使用するDataSetの初期化を終了する(初

VS 2005 資料 【電脳梁山泊 烏賊塾】

-24-

OleDbDataAdapter adapter = new OleDbDataAdapter( );

OleDbCommand selectCMD = new OleDbCommand(selectSQL, connection);

adapter.SelectCommand = selectCMD;

// Add parameters and set values.

selectCMD.Parameters.Add("@CountryRegion", OleDbType.VarChar, 15).Value = "UK";

selectCMD.Parameters.Add("@City", OleDbType.VarChar, 15).Value = "London";

DataSet customers = new DataSet( );

adapter.Fill(customers, "Customers");

Odbc

Visual Basic

' Assumes that connection is a valid OdbcConnection object.

Dim adapter As OdbcDataAdapter = New OdbcDataAdapter

Dim selectCMD AS OdbcCommand = New OdbcCommand(selectSQL, connection)

adapter.SelectCommand = selectCMD

' Add Parameters and set values.

selectCMD.Parameters.Add("@CountryRegion", OdbcType.VarChar, 15).Value = "UK"

selectCMD.Parameters.Add("@City", OdbcType.VarChar, 15).Value = "London"

Dim customers As DataSet = New DataSet

adapter.Fill(customers, "Customers")

C#

// Assumes that connection is a valid OdbcConnection object.

OdbcDataAdapter adapter = new OdbcDataAdapter( );

OdbcCommand selectCMD = new OdbcCommand(selectSQL, connection);

adapter.SelectCommand = selectCMD;

//Add Parameters and set values.

selectCMD.Parameters.Add("@CountryRegion", OdbcType.VarChar, 15).Value = "UK";

selectCMD.Parameters.Add("@City", OdbcType.VarChar, 15).Value = "London";

DataSet customers = new DataSet( );

adapter.Fill(customers, "Customers");

メモ:或るパラメータに対してパラメータ名がサポートされて居ない場合は、Parameter1 から増分し

て行く既定名 ParameterN が割り当てられる。パラメータ名を指定する時には、ParameterN の名前付

けルールを使用しない事を推奨する。此れは、指定した名前が ParameterCollection 内の既存のパラメ

ータ名と競合しない様にする為で有る。指定した名前が既に存在する場合は、例外がスローされる。

・Parameter.DbType

パラメータの型は.NET Framework データプロバイダに固有の属性で有る型が指定されて居る場合は、

其の値がデータソースに渡される前に Parameter の値 .NET Framework データプロバイダ型に変換

される。Parameter オブジェクトの DbType プロパティを特定の DbType に設定する一般的な方法で

Parameter の型を指定する事も出来る。

Parameter オブジェクトの.NET Frameworkデータプロバイダ型は、ParameterオブジェクトのValue

Page 25: データセット - xdomainjunko036.html.xdomain.jp/pdf/database/DataSet.pdfVS 2005 資料 【電脳梁山泊 烏賊塾】 -3- EndInit フォーム又は別のコンポーネントで使用するDataSetの初期化を終了する(初

VS 2005 資料 【電脳梁山泊 烏賊塾】

-25-

の.NET Framework 型か、又は、Parameter オブジェクトの DbType から推論される。Parameter 値

と仕て渡されるオブジェクト、又は、指定された DbType に基づいて推論される Parameter 型を、次

の表に示す。

Framework System.Data.DbType SqlDbType OleDbType OdbcType OracleType

bool Boolean Bit Boolean Bit Byte

byte Byte TinyInt UnsignedTinyInt TinyInt Byte

byte[] Binary VarBinary ※1 VarBinary Binary Raw

char ※2 Char Char Byte

DateTime DateTime DateTime DBTimeStamp DateTime DateTime

Decimal Decimal Decimal Decimal Numeric Number

double Double Float Double Double Double

float Single Real Single Real Float

Guid Guid UniqueIdentifier Guid UniqueIdentifier Raw

Int16 Int16 SmallInt SmallInt SmallInt Int16

Int32 Int32 Int Int Int Int32

Int64 Int64 BitInt BigInt BigInt Number

object Object Variant Variant ※3 Blob

string String NVarChar ※4 VarWChar NVarChar NVarChar

TimeSpan Time ※5 DBTime Time DateTime

UInt16 UInt16 ※6 UnsignedSmallInt Int UInt16

UInt32 UInt32 ※7 UnsignedInt BigInt UInt32

UInt64 UInt64 ※8 UnsignedBigInt Numeric Number

AnsiString VarChar VarChar VarChar VarChar

AnsiStringFixedLength Char Char Char Char

Currency Money Currency ※9 Number

Date ※A DBDate Date DateTime

SByte ※B TinyInt ※C SByte

StringFixedLength NChar WChar NChar NChar

Time ※D DBTime Time DateTime

VarNumeric ※E VarNumeric ※F Number

※1 バイト配列が VarBinary の最大サイズ(8000 バイト)より大きい場合は、此の暗黙の変換はエラ

ーに成る。8000 バイトを超えるバイト配列の場合は、明示的に SqlDbType を設定する。

※2 char からの SqlDbType の推論はサポートされて居ない。

※3 Object からの OdbcType の推論はサポートされて居ない。

※4 文字列が NVarChar の最大サイズ(4000 文字)より大きい場合、此の暗黙の変換はエラーに成る。

4000 文字を超える文字列の場合は、明示的に SqlDbType を設定する。

※5 TimeSpan からの SqlDbType の推論はサポートされて居ない。

※6 UInt16 からの SqlDbType の推論はサポートされて居ない。

※7 UInt32 からの SqlDbType の推論はサポートされて居ない。

※8 UInt64 からの SqlDbType の推論はサポートされて居ない。

※9 Currency からの OdbcType の推論はサポートされて居ない。

※A Date からの SqlType の推論はサポートされて居ない。

※B SByte からの SqlType の推論はサポートされて居ない。

※C SByte からの OdbcType の推論はサポートされて居ない。

※D Time からの SqlType の推論はサポートされて居ない。

※E VarNumeric からの SqlDbType の推論はサポートされて居ない。

※F VarNumeric からの OdbcType の推論はサポートされて居ない。

メモ:.NET Framework Version 1.0 に同梱されて居る.NET Framework データプロバイダは、Decimal

パラメータ値の Precision と Scale を確認しない為、切り捨てられたデータがデータソースに挿入され

る事が有る。.NET Framework Version 1.0 を使用して居る場合は、Decimal 値の Precision と Scale

を検証してからパラメータ値を設定する。.NET Framework Version 1.1 以降では、Decimal パラメー

タ値で無効な Precision が設定されて居る場合、例外がスローされる。Decimal パラメータ スケールを

超える Scale 値は、切り捨てられる。

Page 26: データセット - xdomainjunko036.html.xdomain.jp/pdf/database/DataSet.pdfVS 2005 資料 【電脳梁山泊 烏賊塾】 -3- EndInit フォーム又は別のコンポーネントで使用するDataSetの初期化を終了する(初

VS 2005 資料 【電脳梁山泊 烏賊塾】

-26-

メモ:.NET Framework Version 1.0 以降では、System.Data.SqlTypes を System.Data.SqlClient と

共に使用する事が出来る。詳細に付いては、「SqlTypes の使用」を参照され度い。

・Parameter.Direction

Parameter の Direction を設定する為に ParameterDirection 列挙型で使用出来る値を次の表に示す。

メンバ名 説明

Input 此のパラメータは入力パラメータで有る(此れは、既定の設定で有る)。

InputOutput 此のパラメータは入力と出力の両方の機能を持って居る。

Output 此のパラメータは出力パラメータで有る。

ReturnValue 此のパラメータは戻り値を表す。

Parameter の Direction を設定する方法を次のコード例に示す。

parameter.Direction = ParameterDirection.Output

・Parameter.SourceColumn、Parameter.SourceVersion

SourceColumn 及び SourceVersion は、Parameter コンストラクタに記述子と仕て渡したり、既存の

Parameter のプロパティと仕て設定する事も出来る。SourceColumn は、Parameter の値の取得元で

有る DataRow の DataColumn の名前で有る SourceVersion は、DataAdapter が値を取得する為に使

用する DataRow バージョンを指定する。

SourceVersion で使用出来る DataRowVersion 列挙型の値を次の表に示す。

メンバ名 説明

Current 此のパラメータは列の現在の値を使用する(此れは、既定の設定で有る)。

Default 此のパラメータは列の DefaultValue を使用する。

Original 此のパラメータは列の元の値を使用する。

Proposed 此のパラメータは提示された値を使用する。

CustomerID 列を 2 つのパラメータ@CustomerID(SET CustomerID = @CustomerID)及び

@OldCustomerID(WHERE CustomerID = @OldCustomerID)の SourceColumn と仕て使用する

UPDATE ステートメントを定義するコード例を次に示す。@CustomerID パラメータは、CustomerID

列を DataRow の現在の値に更新する為に使用されて居る。其の為、SourceVersion を Current に設定

した CustomerID SourceColumn が使用されて居る。@OldCustomerID パラメータは、データソース

の現在の行を識別する為に使用されて居る。其の行の Original バージョンで一致する列の値が見付かっ

た為、SourceVersion を Original に設定した同じ SourceColumn(CustomerID)が使用されて居る。

SqlClient

Visual Basic

adapter.UpdateCommand.Parameters.Add( _

"@CustomerID", SqlDbType.NChar, 5, "CustomerID")

adapter.UpdateCommand.Parameters.Add( _

"@CompanyName", SqlDbType.NVarChar, 40, "CompanyName")

Dim parameter As SqlParameter = _

adapter.UpdateCommand.Parameters.Add("@OldCustomerID", _

SqlDbType.NChar, 5, "CustomerID")

parameter.SourceVersion = DataRowVersion.Original

Page 27: データセット - xdomainjunko036.html.xdomain.jp/pdf/database/DataSet.pdfVS 2005 資料 【電脳梁山泊 烏賊塾】 -3- EndInit フォーム又は別のコンポーネントで使用するDataSetの初期化を終了する(初

VS 2005 資料 【電脳梁山泊 烏賊塾】

-27-

C#

adapter.UpdateCommand.Parameters.Add(

"@CustomerID", SqlDbType.NChar, 5, "CustomerID");

adapter.UpdateCommand.Parameters.Add(

"@CompanyName", SqlDbType.NVarChar, 40, "CompanyName");

SqlParameter parameter =

adapter.UpdateCommand.Parameters.Add(

"@OldCustomerID", SqlDbType.NChar, 5, "CustomerID");

parameter.SourceVersion = DataRowVersion.Original;

・UpdatedRowSource

Command オブジェクトの UpdatedRowSource プロパティを使用すると、データソースから返された

値を DataSet に割り当てる方法を制御出来る。UpdatedRowSource プロパティを UpdateRowSource

列挙型の値の 1 つに設定する事で、DataAdapter コマンドが返したパラメータを無視するか、DataSet

内の変更行に適用するかを制御出来る。最初に返された行(存在する場合)を、DataSet 内の変更行に

適用するか何うかを指定する事も出来る。

UpdateRowSource 列挙型の様々の値と、其等の値が DataAdapter で使用されるコマンドの動作に何の

様に影響するかを次の表で説明する。

UpdateRowSource 説明

Both 出力パラメータと返された結果セットの最初の行を DataSet 内の変更行に割

り当てる。

FirstReturnedRecord 返された結果セットの最初の行のデータ丈を DataSet 内の変更行に割り当て

る。

None 出力パラメータ又は返された結果セットの行が無視される。

OutputParameters 出力パラメータ丈を DataSet 内の変更行に割り当てる。

パラメータと戻り値の指定

ストアドプロシージャには、入力パラメータと出力パラメータの他に戻り値を含める事が出来る。次の

例は、ADO.NET が新しいレコードを、主キー列が SQL Server データベースの ID 列と成って居るテ

ーブルに挿入して、入力パラメータ、出力パラメータ、及び、戻り値を受け渡す例を説明して居る。

・例

此の例では、次のストアドプロシージャを使用して Northwind Categories テーブルに新しいカテゴリ

を挿入する。此のストアドプロシージャは CategoryName 列の値を入力パラメータと仕て受け取り、

SCOPE_IDENTITY( ) 関数を使用して ID フィールド CategoryID の新しい値を取得し、其の値を出力

パラメータ内に返す。RETURN ステートメントは、@@ROWCOUNT 関数を使用して、挿入された行

の数を返す。

CREATE PROCEDURE InsertCategory

@CategoryName nchar(15),

@Identity int OUTPUT

AS

SET NOCOUNT ON

INSERT INTO Categories (CategoryName) VALUES(@CategoryName)

SET @Identity = SCOPE_IDENTITY( )

RETURN @@ROWCOUNT

Page 28: データセット - xdomainjunko036.html.xdomain.jp/pdf/database/DataSet.pdfVS 2005 資料 【電脳梁山泊 烏賊塾】 -3- EndInit フォーム又は別のコンポーネントで使用するDataSetの初期化を終了する(初

VS 2005 資料 【電脳梁山泊 烏賊塾】

-28-

上述の InsertCategory ストアドプロシージャを SqlDataAdapter の InsertCommand のソースと仕て

使用する例を次に示す。@Idenrity 出力パラメータと戻り値は、SqlDataAdapter の Update メソッド

が呼び出され、データベースにレコードが挿入された後で DataSet に反映される。

メモ: OleDbDataAdapter を使用する場合、ReturnValue の ParameterDirection を含むパラメータ

を他のパラメータより先に指定する必要が有る。

Visual Basic

' Assumes that connection represents a SqlConnection object.

Dim adapter As SqlDataAdapter = New SqlDataAdapter( _

"SELECT CategoryID, CategoryName FROM dbo.Categories", connection)

adapter.InsertCommand = New SqlCommand("InsertCategory" , connection)

adapter.InsertCommand.CommandType = CommandType.StoredProcedure

Dim parameter As SqlParameter = adapter.InsertCommand.Parameters.Add( _

"@RowCount", SqlDbType.Int)

parameter.Direction = ParameterDirection.ReturnValue

adapter.InsertCommand.Parameters.Add( _

"@CategoryName", SqlDbType.NChar, 15, "CategoryName")

parameter = adapter.InsertCommand.Parameters.Add( _

"@Identity", SqlDbType.Int, 0, "CategoryID")

parameter.Direction = ParameterDirection.Output

Dim categoriesDS As DataSet = New DataSet( )

adapter.Fill(categoriesDS, "Categories")

Dim newRow As DataRow = categoriesDS.Tables("Categories").NewRow( )

newRow("CategoryName") = "New Category"

categoriesDS.Tables("Categories").Rows.Add(newRow)

adapter.Update(categoriesDS, "Categories")

Dim rowCount As Int32 = CInt(adapter.InsertCommand.Parameters("@RowCount").Value)

C#

// Assumes that connection represents a SqlConnection object.

SqlDataAdapter adapter = new SqlDataAdapter(

"SELECT CategoryID, CategoryName FROM dbo.Categories", connection);

adapter.InsertCommand = new SqlCommand("InsertCategory", connection);

adapter.InsertCommand.CommandType = CommandType.StoredProcedure;

SqlParameter parameter = adapter.InsertCommand.Parameters.Add(

"@RowCount", SqlDbType.Int);

parameter.Direction = ParameterDirection.ReturnValue;

adapter.InsertCommand.Parameters.Add(

"@CategoryName", SqlDbType.NChar, 15, "CategoryName");

parameter = adapter.InsertCommand.Parameters.Add(

Page 29: データセット - xdomainjunko036.html.xdomain.jp/pdf/database/DataSet.pdfVS 2005 資料 【電脳梁山泊 烏賊塾】 -3- EndInit フォーム又は別のコンポーネントで使用するDataSetの初期化を終了する(初

VS 2005 資料 【電脳梁山泊 烏賊塾】

-29-

"@Identity", SqlDbType.Int, 0, "CategoryID");

parameter.Direction = ParameterDirection.Output;

DataSet categoriesDS = new DataSet( );

adapter.Fill(categoriesDS, "Categories");

DataRow newRow = categoriesDS.Tables["Categories"].NewRow( );

newRow["CategoryName"] = "New Category";

categoriesDS.Tables["Categories"].Rows.Add(newRow);

adapter.Update(categoriesDS, "Categories");

Int32 rowCount = (Int32)adapter.InsertCommand.Parameters["@RowCount"].Value;

■ DataSet の内容のマージ

DataSet の Merge メソッドを使用して、DataSet、DataTable、又は、DataRow の配列の内容を既存

の DataSet にマージ出来る。一部の係数、及び、オプションは、新しいデータを既存の DataSet にマ

ージする方法に影響する。

主キー

マージに依って新しいデータとスキーマを受け取るテーブルに主キーが有る場合、受信データの新しい

行の主キーと Original 行バージョンの主キーの値が同じで有る既存の行を一致させる。受信スキーマの

列が既存のスキーマの列と一致する場合、既存の行に有るデータが変更される。既存のスキーマと一致

しない列は、MissingSchemaAction パラメータに基づいて無視、又は、追加される(此の資料の

MissingSchemaAction を参照)。主キーの値が既存の行と一致しない新しい行は、既存のテーブルに追

加される。

受信する行、又は、既存する行の行状態が Added の場合、Original 行バージョンが存在しない為、Added

の行の Current 行バージョンの主キーの値を使用して、其の 2 つの行の主キーの値を一致させる。

受信テーブルと既存のテーブルに名前が同じでもデータ型が異なる列が含まれて居る場合、例外がスロ

ーされ、DataSet の MergeFailed イベントが発生する。受信テーブルと既存のテーブルの両方にキー

が定義されて居ても、主キーの対象の列が異なる場合、例外がスローされ、DataSet の MergeFailed

イベントが発生する。

マージに依って新しいデータを受け取るテーブルに主キーが無い場合、受信データの新しい行と其のテ

ーブルの既存の行は一致しない。其の代わりに新しい行が既存のテーブルに追加される。

preserveChanges

DataSet、DataTable、又は、DataRow の各配列を Merge メソッドに渡すと、オプションパラメータ

を含める事が出来る。其のパラメータを使用して、変更内容を既存の DataSet に保存するか何うか、及

び、受信データで見付かった新しいスキーマの要素を処理する方法を指定する。受信データの後に続く

最初のオプションパラメータは、Boolean 型のフラグ preserveChanges で、変更内容を既存の DataSet

に保存するか何うかを指定する。preserveChanges フラグを true に設定した場合、既存する行の

Current 行バージョンの値は受信する値で上書きされない。preserveChanges フラグを false に設定し

た場合、既存する行の Current 行バージョンの値は受信する値で上書きされる。preserveChanges フ

ラグを指定しない場合、既定では false に設定される。行バージョンの詳細に付いては、「行の状態とバ

ージョン」を参照され度い。

preserveChanges を true にすると、既存する行のデータは Current 行バージョンで保存されるが、既

Page 30: データセット - xdomainjunko036.html.xdomain.jp/pdf/database/DataSet.pdfVS 2005 資料 【電脳梁山泊 烏賊塾】 -3- EndInit フォーム又は別のコンポーネントで使用するDataSetの初期化を終了する(初

VS 2005 資料 【電脳梁山泊 烏賊塾】

-30-

存する行の Original 行バージョンには受信する行の Original 行バージョンのデータで上書きされる。

既存する行の RowState は、Modified に設定される。適用する例外を次に示す。

・既存する行の RowState が Deleted の場合、此の RowState は Deleted の儘で Modified には設定さ

れない。此の場合、受信する行のデータは既存する行の Original 行バージョンと仕て保存され、既存

する行の Original 行バージョンのデータを上書きする(受信する行の RowState が Added でない場

合)。

・受信する行の RowState が Added の場合、受信する行には Original 行バージョンが存在しない為、

既存する行の Original 行バージョンのデータは上書きされない。

preserveChanges を false にすると、既存する行の Current 行バージョンと Original 行バージョンの

孰れのデータも受信する行のデータで上書きされ、既存する行のRowStateには受信する行のRowState

が設定される。適用する例外を次に示す。

・受信する行の RowState が Unchanged で、既存する行の RowState が Modified、Deleted、又は、

Added の場合、既存する行の RowState は Modified に設定される。

・受信する行の RowState が、Added で、既存する行の RowState が、Unchanged、Modified、又は

Deleted の場合、既存する行の RowState は Modified に設定される。亦、受信する行には Original

行バージョンが存在しない為、既存する行の Original 行バージョンのデータは、受信する行のデータ

で上書きされない。

MissingSchemaAction

Merge メソッドのオプションの MissingSchemaAction パラメータを使用して、既存の DataSet の一部

ではない受信データのスキーマ要素を Merge で処理する方法を指定出来る。

MissingSchemaAction のオプションの説明を次の表に示す。

MissingSchemaAction の

オプション

説明

Add 新しいスキーマ情報を DataSet に追加し、受信する値を新しい列に読み

込む(此れは、既定の設定で有る)。

AddWithKey 新しいスキーマと主キーの情報を DataSet に追加し、受信する値を新し

い列に読み込む。

Error 一致しないスキーマ情報が見付かった場合、例外をスローする。

Ignore 新しいスキーマ情報を無視する。

制約

Merge メソッドを使用すると、総ての新しいデータが既存の DataSet に追加される迄、制約がチェッ

クされない。新しいデータを追加すると、DataSet の現在の値に制約が適用される。開発者は、制約違

反の為にスローされる例外をコードで処理する必要が有る。

例えば、DataSet に既存する行が Unchanged で、主キーの値が 1 の場合に、受信する行が Modified

で、Original 行バージョンの主キーの値が 2、Current 行バージョンの主キーの値が 1 の状態でマージ

操作を行うと、Original の主キーの値が異なる為、既存する行と受信する行は一致と看做されない。マ

ージが完了し、制約がチェックされると、Current 行バージョンの主キーの値が主キー列の UNIQUE

制約に違反する為、例外がスローされる。

スキーマが異なる 2 つの DataSet オブジェクトを、其の 2 つの受信 DataSet オブジェクトのスキーマ

を組み合わせて、1 つの DataSet にマージするコード例を次に示す。

Page 31: データセット - xdomainjunko036.html.xdomain.jp/pdf/database/DataSet.pdfVS 2005 資料 【電脳梁山泊 烏賊塾】 -3- EndInit フォーム又は別のコンポーネントで使用するDataSetの初期化を終了する(初

VS 2005 資料 【電脳梁山泊 烏賊塾】

-31-

Visual Basic

Using connection As SqlConnection = New SqlConnection( connectionString)

Dim adapter As SqlDataAdapter = New SqlDataAdapter( _

"SELECT CustomerID, CompanyName FROM Customers", connection) connection.Open( )

Dim customers As DataSet = New DataSet( )

adapter.FillSchema(customers, SchemaType.Source, "Customers")

adapter.Fill(customers, "Customers")

Dim orders As DataSet = New DataSet( )

orders.ReadXml("Orders.xml", XmlReadMode.ReadSchema)

orders.AcceptChanges( )

customers.Merge(orders, True, MissingSchemaAction.AddWithKey)

End Using

C#

using (SqlConnection connection = new SqlConnection(connectionString))

{

SqlDataAdapter adapter = new SqlDataAdapter(

"SELECT CustomerID, CompanyName FROM dbo.Customers", connection);

connection.Open( ); DataSet customers = new DataSet( );

adapter.FillSchema(customers, SchemaType.Source, "Customers");

adapter.Fill(customers, "Customers"); DataSet orders = new DataSet( );

orders.ReadXml("Orders.xml", XmlReadMode.ReadSchema);

orders.AcceptChanges( ); customers.Merge(orders, true, MissingSchemaAction.AddWithKey);

}

更新内容を含む既存の DataSet を取得し、其の更新内容を DataAdapter に渡してデータソースで処理

するコード例を次に示す。其の後、其の結果が元の DataSet にマージされる。エラーと成った変更内容

を拒否した後、マージされた変更内容が AcceptChanges を使用してコミットされる。

Visual Basic

Dim customers As DataTable = dataSet.Tables("Customers") ' Make modifications to the Customers table. ' Get changes to the DataSet.

Dim dataSetChanges As DataSet = dataSet.GetChanges( ) ' Add an event handler to handle the errors during Update. AddHandler adapter.RowUpdated, New SqlRowUpdatedEventHandler(AddressOf OnRowUpdated)

connection.Open( )

adapter.Update(dataSetChanges, "Customers")

connection.Close( )

' Merge the updates.

dataSet.Merge(dataSetChanges, True, MissingSchemaAction.Add)

Page 32: データセット - xdomainjunko036.html.xdomain.jp/pdf/database/DataSet.pdfVS 2005 資料 【電脳梁山泊 烏賊塾】 -3- EndInit フォーム又は別のコンポーネントで使用するDataSetの初期化を終了する(初

VS 2005 資料 【電脳梁山泊 烏賊塾】

-32-

' Reject changes on rows with errors and clear the error.

Dim errRows( ) As DataRow = dataSet.Tables("Customers").GetErrors( )

Dim errRow As DataRow

For Each errRow In errRows

errRow.RejectChanges( )

errRow.RowError = Nothing

Next

' Commit the changes.

dataSet.AcceptChanges( )

C#

DataTable customers = dataSet.Tables["Customers"]; // Make modifications to the Customers table.

// Get changes to the DataSet.

DataSet dataSetChanges = dataSet.GetChanges( ); // Add an event handler to handle the errors during Update.

adapter.RowUpdated += new SqlRowUpdatedEventHandler(OnRowUpdated); connection.Open( );

adapter.Update(dataSetChanges, "Customers");

connection.Close( ); // Merge the updates.

dataSet.Merge(dataSetChanges, true, MissingSchemaAction.Add);

// Reject changes on rows with errors and clear the error.

DataRow[] errRows = dataSet.Tables["Customers"].GetErrors( );

foreach (DataRow errRow in errRows)

{

errRow.RejectChanges( );

errRow.RowError = null;

} // Commit the changes.

dataSet.AcceptChanges( );

Visual Basic

Private Sub OnRowUpdated(ByVal sender As Object, ByVal args As SqlRowUpdatedEventArgs)

If args.Status = UpdateStatus.ErrorsOccurred Then

args.Row.RowError = args.Errors.Message

args.Status = UpdateStatus.SkipCurrentRow

End If

End Sub

C#

protected static void OnRowUpdated(object sender, SqlRowUpdatedEventArgs args)

{

if (args.Status == UpdateStatus.ErrorsOccurred)

{

args.Row.RowError = args.Errors.Message;

args.Status = UpdateStatus.SkipCurrentRow;

}

}

Page 33: データセット - xdomainjunko036.html.xdomain.jp/pdf/database/DataSet.pdfVS 2005 資料 【電脳梁山泊 烏賊塾】 -3- EndInit フォーム又は別のコンポーネントで使用するDataSetの初期化を終了する(初

VS 2005 資料 【電脳梁山泊 烏賊塾】

-33-

■ DataSet の内容のコピー

DataSet のコピーを作成すると、元のデータに影響せずにデータを使用したり、DataSet のデータのサ

ブセットを使用したり出来る。DataSet をコピーすると、次の操作を行う事が出来る。

・スキーマ、データ、行状態情報、行バージョン等の DataSet の正確なコピーを作成出来る。

・既存の DataSet のスキーマを含み、行丈を変更した DataSet を作成出来る。変更された総ての行を

返したり、特定の DataRowState を指定したり出来る。行の状態の詳細に付いては、「行の状態とバ

ージョン」を参照され度い。

・行をコピーせずに、DataSet のスキーマ(リレーショナル構造)丈をコピー出来る。ImportRow を

使用して、行を既存の DataTable にインポート出来る。

スキーマとデータを含む DataSet の正確なコピーを作成するには、DataSet の Copy メソッドを使用す

る。DataSet の正確なコピーを作成する方法を次のコード例に示す。

Visual Basic

Dim copyDataSet As DataSet = customerDataSet.Copy( )

C#

DataSet copyDataSet = customerDataSet.Copy( );

スキーマ、及び、データが Added、Modified、又は、Deleted で或る行丈を含む DataSet のコピーを作

成するには、DataSet の GetChanges メソッドを使用する。亦、GetChanges の呼出時に DataRowState

の値を渡す事に依って、GetChanges を使用して特定の行状態の行丈を返す事が出来る。GetChanges

の呼出時に DataRowState を渡す方法を次のコード例に示す。

Visual Basic

' Copy all changes.

Dim changeDataSet As DataSet = customerDataSet.GetChanges( )

' Copy only new rows.

Dim addedDataSetAs DataSet = customerDataSet.GetChanges(DataRowState.Added)

C#

// Copy all changes.

DataSet changeDataSet = customerDataSet.GetChanges( );

// Copy only new rows.

DataSet addedDataSet= customerDataSet.GetChanges(DataRowState.Added);

スキーマ丈を含む DataSet のコピーを作成するには、DataSet の Clone メソッドを使用する。亦、

DataTable の ImportRow メソッドを使用して、複製した DataSet に既存の行を追加する事も出来る。

ImportRow メソッドを使用すると、データ、行の状態、及び、行バージョンの情報が指定したテーブ

ルに追加される。列名が一致し、データ型が互換性の有る型の場合には、列の値丈が追加される。

DataSet のクローンを作成し、CountryRegion 列の値が Germany の顧客に対する DataSet のクロー

ン内の Customers テーブルに、元の DataSet の行を追加するコード例を次に示す。

Visual Basic

Dim germanyCustomers As DataSet = customerDataSet.Clone( )

Dim copyRows( ) As DataRow = _

customerDataSet.Tables("Customers").Select("CountryRegion = 'Germany'")

Page 34: データセット - xdomainjunko036.html.xdomain.jp/pdf/database/DataSet.pdfVS 2005 資料 【電脳梁山泊 烏賊塾】 -3- EndInit フォーム又は別のコンポーネントで使用するDataSetの初期化を終了する(初

VS 2005 資料 【電脳梁山泊 烏賊塾】

-34-

Dim customerTable As DataTable = germanyCustomers.Tables("Customers")

Dim copyRow As DataRow

For Each copyRow In copyRows

customerTable.ImportRow(copyRow)

Next

C#

DataSet germanyCustomers = customerDataSet.Clone( );

DataRow[] copyRows = customerDataSet.Tables["Customers"].Select("CountryRegion = 'Germany'");

DataTable customerTable = germanyCustomers.Tables["Customers"];

foreach (DataRow copyRow in copyRows)

customerTable.ImportRow(copyRow);

■ DataSet イベントの使用

DataSetには、DataSetオブジェクトのスキーマのマージで競合が発生すると、生成されるMergeFailed

イベントが設定されて居る。例えば、マージ対象のテーブルの主キーの列が 2 つの DataSet オブジェク

トのテーブル間で異なる場合、例外がスローされ、MergeFailed イベントが発生する。MergeFailed イ

ベントに渡される MergeFailedEventArgs には、2 つの DataSet オブジェクト間のスキーマで発生した

競合を示すConflictプロパティ、及び、競合が発生したテーブルの名前を示すTableプロパティが有る。

DataSet の使用時に使用出来る其の他のイベントに付いては、「DataTable イベントの使用」及び

「DataAdapter イベントの使用」を参照され度い。

MergeFailed イベントをイベントハンドラに追加するコード例を次に示す。

Visual Basic

Dim workDS As DataSet = New DataSet

AddHandler workDS.MergeFailed, New MergeFailedEventHandler(AddressOf DataSetMergeFailed)

Private Shared Sub DataSetMergeFailed(sender As Object,args As MergeFailedEventArgs)

Console.WriteLine("Merge failed for table " & args.Table.TableName)

Console.WriteLine("Conflict = " & args.Conflict)

End Sub

C#

DataSet workDS = new DataSet( );

workDS.MergeFailed += new MergeFailedEventHandler(DataSetMergeFailed);

private static void DataSetMergeFailed(object sender, MergeFailedEventArgs args)

{

Console.WriteLine("Merge failed for table " + args.Table.TableName);

Console.WriteLine("Conflict = " + args.Conflict);

}

■ 型指定された DataSet の使用

厳密に型指定されて居ない変数を使用した値への遅延バインディングアクセスに加えて、DataSet には、

厳密に型指定された変数を使用したデータへのアクセスも用意されて居る。DataSet の一部で有るテー

ブルと列は、ユーザーが認識しやすい名前と厳密に型指定された変数を使用してアクセス出来る。

Page 35: データセット - xdomainjunko036.html.xdomain.jp/pdf/database/DataSet.pdfVS 2005 資料 【電脳梁山泊 烏賊塾】 -3- EndInit フォーム又は別のコンポーネントで使用するDataSetの初期化を終了する(初

VS 2005 資料 【電脳梁山泊 烏賊塾】

-35-

型指定された DataSet とは、DataSet から派生するクラスの事で有る。従って、型指定された DataSet

は DataSet の総てのメソッド、イベント、及び、プロパティを継承する。更に、型指定された DataSet

には、厳密に型指定されたメソッド、イベント、及び、プロパティが用意されて居る。詰まり、コレク

ションベースのメソッドを使用せずに名前でテーブルや列にアクセス出来る。コードが読み易く変更さ

れた丈でなく、型指定された DataSet を使用して、入力する通りにラインを Visual Studio.NET コー

ドエディタに自動挿入出来る。

更に、厳密に型指定された DataSet を使用してコンパイル時に正しい型で値にアクセス出来る。厳密に

型指定された DataSet を使用すると、型の不一致が実行時ではなく、コードのコンパイル時にキャッチ

される。

厳密に型指定された DataSet の生成

XML スキーマ定義言語(XSD)標準に準拠する XML スキーマを設定すると、.NET Framework SDK

と共に用意される XSD.exe ツールを使用して、厳密に型指定された DataSet を生成出来る。

XSD.exe ツールを使用して DataSet を生成する構文を次のコードで示す。

xsd.exe /d /l:CS XSDSchemaFileName.xsd /n:XSDSchema.Namespace

此の構文では、/d ディレクティブが DataSet を生成する事を知らせる。亦、/l: ディレクティブは使用

する言語(C#、Visual Basic.NET 等)をツールに知らせる。オプションの/n:ディレクティブは、

XSDSchema.Namespace と呼ばれる DataSet の名前空間も生成する事をツールに知らせる。コマンド

の出力は XSDSchemaFileName.cs で、ADO.NET アプリケーションでコンパイルと使用が出来る。生

成されたコードをライブラリ、又は、モジュールと仕てコンパイル出来る。

C#コンパイラ(csc.exe)を使用して、生成されたコードをライブラリと仕てコンパイルする構文を次

のコードで示す。

csc.exe /t:library XSDSchemaFileName.cs /r:System.dll /r:System.Data.dll

/t:ディレクティブはライブラリと仕てコンパイルする事をツールに知らせ、/r:ディレクティブはコンパ

イルに必要な依存ライブラリを指定する。コマンドの出力は XSDSchemaFileName.dll で、/r:ディレク

ティブに依る ADO.NET アプリケーションのコンパイル時にコンパイラに渡す事が出来る。

ADO.NET アプリケーションの XSD.exe に渡された名前空間にアクセスする構文を次のコードで示す。

Visual Basic

Imports XSDSchema.Namespace

C#

using XSDSchema.Namespace;

CustomerDataSet と謂う名前の型指定された DataSet を使用して、Northwind データベースから顧客

リストを読み込むコード例を次に示す。Fill メソッドを使用してデータが読み込まれると、例では、型

指定された CustomersRow(DataRow)オブジェクトを使用して、Customers テーブルの各顧客をル

ープする。此れに依り、DataColumnCollection を経由せずに CustomerID 列に直接アクセス出来る。

Visual Basic

Dim customers As CustomerDataSet= New CustomerDataSet( )

Dim adapter As SqlDataAdapter New SqlDataAdapter( _

"SELECT * FROM dbo.Customers;", _

"Data Source=(local);Integrated " & _

Page 36: データセット - xdomainjunko036.html.xdomain.jp/pdf/database/DataSet.pdfVS 2005 資料 【電脳梁山泊 烏賊塾】 -3- EndInit フォーム又は別のコンポーネントで使用するDataSetの初期化を終了する(初

VS 2005 資料 【電脳梁山泊 烏賊塾】

-36-

"Security=SSPI;Initial Catalog=Northwind")

adapter.Fill(customers, "Customers")

Dim customerRow As CustomerDataSet.CustomersRow

For Each customerRow In customers.Customers

Console.WriteLine(customerRow.CustomerID)

Next

C#

CustomerDataSet customers = new CustomerDataSet( );

SqlDataAdapter adapter = new SqlDataAdapter(

"SELECT * FROM dbo.Customers;",

"Data Source=(local);Integrated " +

"Security=SSPI;Initial Catalog=Northwind");

adapter.Fill(customers, "Customers");

foreach(CustomerDataSet.CustomersRow customerRow in customers.Customers)

Console.WriteLine(customerRow.CustomerID);

例に使用された XML スキーマを次に示す。

<?xml version="1.0" encoding="utf-8"?>

<xs:schema id="CustomerDataSet" xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema"

xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">

<xs:element name="CustomerDataSet" msdata:IsDataSet="true">

<xs:complexType>

<xs:choice maxOccurs="unbounded">

<xs:element name="Customers">

<xs:complexType>

<xs:sequence>

<xs:element name="CustomerID" type="xs:string" minOccurs="0" />

</xs:sequence>

</xs:complexType>

</xs:element>

</xs:choice>

</xs:complexType>

</xs:element>

</xs:schema>

型指定された DataSet に依る注釈の使用

注釈を使用すると、基に成るスキーマを変更せずに型指定された DataSet の要素の名前を変更出来る。

基に成るスキーマの要素の名前を変更すると、データソースに有るオブジェクトへの参照が失われる丈

でなく、型指定された DataSet がデータソースに無いオブジェクトを参照する事に成る。

注釈を使用すると、基に成るスキーマを変更せずに、型指定された DataSet のオブジェクトを解り易い

名前にカスタマイズ出来る為、コードが読み易く成り、型指定された DataSet がクライアントで使用し

易く成る。例えば、次の Northwind データベースの Customers テーブルのスキーマ要素は、

CustomersRow と謂う名前の DataRow オブジェクト名、及び、Customers と謂う名前の

DataRowCollection と成る。

<xs:element name="Customers">

<xs:complexType>

Page 37: データセット - xdomainjunko036.html.xdomain.jp/pdf/database/DataSet.pdfVS 2005 資料 【電脳梁山泊 烏賊塾】 -3- EndInit フォーム又は別のコンポーネントで使用するDataSetの初期化を終了する(初

VS 2005 資料 【電脳梁山泊 烏賊塾】

-37-

<xs:sequence>

<xs:element name="CustomerID" type="xs:string" minOccurs="0" />

</xs:sequence>

</xs:complexType>

</xs:element>

Customers と謂う DataRowCollection 名は、クライアントコードでは意味が有るが、CustomersRow

と謂う DataRow 名は単一のオブジェクトで有る為、誤解が生じる。亦、一般的なシナリオでは、

CustomersRow オブジェクトは Row ID を指定せずに参照される為、単に Customer オブジェクトと仕

て参照される。此の問題を解決するには、スキーマに注釈を付け、DataRow オブジェクトと

DataRowCollection オブジェクトに新しい名前を指定する。上記のスキーマに注釈を付けたスキーマを

次に示す。

<xs:element name="Customers" codegen:typedName="Customer" codegen:typedPlural="Customers">

<xs:complexType>

<xs:sequence>

<xs:element name="CustomerID" type="xs:string" minOccurs="0" />

</xs:sequence>

</xs:complexType>

</xs:element>

Customer と謂う typedName 値を指定すると、Customer と謂う DataRow オブジェクト名に成る。

Customers と謂う typedPlural 値を指定すると、Customers と謂う DataRowCollection 名が保存される。

使用出来る注釈を次の表に示す。

注釈 説明

typedName オブジェクト名

typedPlural オブジェクトのコレクション名

typedParent 親のリレーションシップで参照される場合のオブジェクト名

typedChildren 子のリレーションシップからオブジェクトを返すメソッド名

nullValue 基に成る値が DBNull の場合の値(nullValue の注釈に付いては、次の表を参照され

度い。既定値は_throw で有る)

nullValue 注釈に指定出来る値を次の表に示す。

nullValue の値 説明

Replacement Value 返される値を指定する(返された値は要素の型と一致する必要が有る。例えば、

整数型フィールドが null の場合に 0 を返す為に nullValue="0" を使用する)。

_throw 例外をスローする(此れは、既定の設定で有る)。

_null プリミティブ型が見付かった場合は、null 参照を返すか、例外をスローする。

_empty 文字列の場合は String.Empty を、其れ以外の場合は空のコンストラクタから

作成されたオブジェクトを返す(プリミティブ型が見付かった場合、例外をス

ローする)。

型指定された DataSet のオブジェクトの既定値と使用出来る注釈を次の表に示す。

オブジェクト/メソッド/イベント 既定値 注釈

DataTable TableNameDataTable typedPlural

DataTable のメソッド NewTableNameRow

AddTableNameRow

DeleteTableNameRow

typedName

Page 38: データセット - xdomainjunko036.html.xdomain.jp/pdf/database/DataSet.pdfVS 2005 資料 【電脳梁山泊 烏賊塾】 -3- EndInit フォーム又は別のコンポーネントで使用するDataSetの初期化を終了する(初

VS 2005 資料 【電脳梁山泊 烏賊塾】

-38-

DataRowCollection TableName typedPlural

DataRow TableNameRow typedName

DataColumn DataTable.ColumnNameColumn

DataRow.ColumnName

typedName

Property PropertyName typedName

Child Accessor GetChildTableNameRows typedChildren

Parent Accessor TableNameRow typedParent

DataSet イベント TableNameRowChangeEvent

TableNameRowChangeEventHandler

typedName

型指定された DataSet の注釈を使用するには、XML スキーマ定義言語(XSD)スキーマに次の xmlns

参照をインクルードする必要が有る。

xmlns:codegen="urn:schemas-microsoft-com:xml-msprop"

Orders テーブルとのリレーションを持つ Northwind データベースの Customers テーブルを表示する

注釈の付いたスキーマのサンプルを次に示す。

<?xml version="1.0" encoding="utf-8"?> <xs:schema id="CustomerDataSet" xmlns:codegen="urn:schemas-microsoft-com:xml-msprop" xmlns="" xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata"> <xs:element name="CustomerDataSet" msdata:IsDataSet="true"> <xs:complexType> <xs:choice maxOccurs="unbounded"> <xs:element name="Customers" codegen:typedName="Customer" codegen:typedPlural="Customers"> <xs:complexType> <xs:sequence> <xs:element name="CustomerID" codegen:typedName="CustomerID" type="xs:string" minOccurs="0" /> <xs:element name="CompanyName" codegen:typedName="CompanyName" type="xs:string" minOccurs="0" /> <xs:element name="Phone" codegen:typedName="Phone" codegen:nullValue="" type="xs:string" minOccurs="0" /> </xs:sequence> </xs:complexType> </xs:element> <xs:element name="Orders" codegen:typedName="Order" codegen:typedPlural="Orders"> <xs:complexType> <xs:sequence> <xs:element name="OrderID" codegen:typedName="OrderID" type="xs:int" minOccurs="0" /> <xs:element name="CustomerID" codegen:typedName="CustomerID" codegen:nullValue="" type="xs:string" minOccurs="0" /> <xs:element name="EmployeeID" codegen:typedName="EmployeeID" codegen:nullValue="0" type="xs:int" minOccurs="0" /> <xs:element name="OrderAdapter" codegen:typedName="OrderAdapter" codegen:nullValue="1980-01-01T00:00:00" type="xs:dateTime" minOccurs="0" /> </xs:sequence> </xs:complexType> </xs:element> </xs:choice> </xs:complexType> <xs:unique name="Constraint1"> <xs:selector xpath=".//Customers" /> <xs:field xpath="CustomerID" /> </xs:unique> <xs:keyref name="CustOrders" refer="Constraint1" codegen:typedParent="Customer" codegen:typedChildren="GetOrders"> <xs:selector xpath=".//Orders" /> <xs:field xpath="CustomerID" /> </xs:keyref> </xs:element> </xs:schema>

Page 39: データセット - xdomainjunko036.html.xdomain.jp/pdf/database/DataSet.pdfVS 2005 資料 【電脳梁山泊 烏賊塾】 -3- EndInit フォーム又は別のコンポーネントで使用するDataSetの初期化を終了する(初

VS 2005 資料 【電脳梁山泊 烏賊塾】

-39-

サンプルスキーマから作成された厳密に型指定された DataSet を次のコード例で使用する。亦、一方の

SqlDataAdapter を使用して Customers テーブルを、他方の SqlDataAdapter を使用して Orders テー

ブルを作成する。厳密に型指定された DataSet に依り、DataRelations が定義される。

Visual Basic

' Assumes a valid SqlConnection object named connection.

Dim customerAdapter As SqlDataAdapter = New SqlDataAdapter( _

"SELECT CustomerID, CompanyName, Phone FROM Customers", connection)

Dim orderAdapter As SqlDataAdapter = New SqlDataAdapter( _

"SELECT OrderID, CustomerID, EmployeeID, OrderAdapter FROM Orders", connection)

' Populate a strongly typed DataSet.

connection.Open( )

Dim customers As CustomerDataSet = New CustomerDataSet( )

customerAdapter.Fill(customers, "Customers")

orderAdapter.Fill(customers, "Orders")

connection.Close( )

' Add a strongly typed event.

AddHandler customers.Customers.CustomerChanged, &

New CustomerDataSet.CustomerChangeEventHandler( AddressOf OnCustomerChanged)

' Add a strongly typed DataRow.

Dim newCustomer As CustomerDataSet.Customer = customers.Customers.NewCustomeromer( )

newCustomer.CustomerID = "NEW01"

newCustomer.CompanyName = "My New Company"

customers.Customers.AddCustomer(newCustomer)

' Navigate the child relation.

Dim customer As CustomerDataSet.Customer

Dim order As CustomerDataSet.Order

For Each customer In customers.Customers

Console.WriteLine(customer.CustomerID)

For Each order In customer.GetOrders( )

Console.WriteLine(vbTab & order.OrderID)

Next

Next

Private Shared Sub OnCustomerChanged( _

sender As Object, e As CustomerDataSet.CustomerChangeEvent)

End Sub

C#

// Assumes a valid SqlConnection object named connection.

SqlDataAdapter customerAdapter = new SqlDataAdapter(

"SELECT CustomerID, CompanyName, Phone FROM Customers", connection);

SqlDataAdapter orderAdapter = new SqlDataAdapter(

"SELECT OrderID, CustomerID, EmployeeID, OrderAdapter FROM Orders", connection);

// Populate a strongly typed DataSet.

connection.Open( );

CustomerDataSet customers = new CustomerDataSet( );

customerAdapter.Fill(customers, "Customers");

orderAdapter.Fill(customers, "Orders");

Page 40: データセット - xdomainjunko036.html.xdomain.jp/pdf/database/DataSet.pdfVS 2005 資料 【電脳梁山泊 烏賊塾】 -3- EndInit フォーム又は別のコンポーネントで使用するDataSetの初期化を終了する(初

VS 2005 資料 【電脳梁山泊 烏賊塾】

-40-

connection.Close( );

// Add a strongly typed event.

customers.Customers.CustomerChanged += new

CustomerDataSet.CustomerChangeEventHandler(OnCustomerChanged);

// Add a strongly typed DataRow.

CustomerDataSet.Customer newCustomer =

customers.Customers.NewCustomeromer( );

newCustomer.CustomerID = "NEW01";

newCustomer.CompanyName = "My New Company";

customers.Customers.AddCustomer(newCustomer);

// Navigate the child relation.

foreach(CustomerDataSet.Customer customer in customers.Customers)

{

Console.WriteLine(customer.CustomerID);

foreach(CustomerDataSet.Order order in customer.GetOrders( ))

Console.WriteLine("¥t" + order.OrderID);

}

protected static void OnCustomerChanged(

object sender, CustomerDataSet.CustomerChangeEvent e)

{

}

■ DataTable の作成と使用

DataSet は、テーブル、リレーションシップ、及び、制約のコレクションで構成される。ADO.NET で

は、DataSet 内のテーブルを表す為に DataTable オブジェクトを使用する。DataTable は、1 つのメモ

リ内のリレーショナルデータテーブルを表す。此のテーブルのデータは、其のデータが存在する.NET

ベースアプリケーションのローカルデータだが、DataAdapter を使用して Microsoft SQL Server 等の

データソースから読み込む事も出来る。詳細に付いては、「DataAdapter からの DataSet の読み込み」

を参照され度い。

DataTableクラスは、.NET Frameworkクラスライブラリ内のSystem.Data名前空間のメンバで有る。

DataTable は、単独でも DataSet のメンバと仕ても作成・使用出来る。亦、DataTable オブジェクト

は、DataView 等の他の.NET Framework オブジェクトからも使用出来る。DataSet 内のテーブルのコ

レクションには、DataSet オブジェクトの Tables プロパティを使用してアクセスする。

テーブルのスキーマ(構造)は、列と制約で表される。DataTable のスキーマは、DataColumn、

ForeignKeyConstraint、UniqueConstraint の各オブジェクトを使用して定義する。テーブル内の列は、

データソースの列に割り当てたり、式で算出された値を格納したり、格納されて居る値を自動的にイン

クリメントしたり、主キー値を格納したり出来る。

DataTable には、スキーマ丈でなく、データを格納して順序付ける為の行も必要で有る。

DataRowDataRow クラスは、テーブルに格納される実際のデータを表す。DataRow や其のプロパティ

とメソッドを使用して、テーブル内のデータを取得、評価、及び、操作出来る。行内のデータがアクセ

スされて変更された時は、DataRow オブジェクトは、変更後の現在の状態と変更前の状態を維持する。

テーブル間で 1 つ以上の列を関連付け、テーブル間の親子のリレーションシップを作成出来る。

DataTable オブジェクト間のリレーションシップを作成するには、DataRelation を使用する。

Page 41: データセット - xdomainjunko036.html.xdomain.jp/pdf/database/DataSet.pdfVS 2005 資料 【電脳梁山泊 烏賊塾】 -3- EndInit フォーム又は別のコンポーネントで使用するDataSetの初期化を終了する(初

VS 2005 資料 【電脳梁山泊 烏賊塾】

-41-

DataRelation オブジェクトを使用すると、特定の行に関連付けられた子の行、又は、親の行を返す事

が出来る。詳細に付いては、「テーブル間のリレーションシップの追加」を参照され度い。

DataTable の作成

DataTable は 1 つのインメモリリレーショナルデータのテーブルを表す。DataTable は単独で作成・使

用する事も、他の.NET Framework オブジェクトから DataSet のメンバと仕て使用する事も出来る。

DataTable オブジェクトは、適切な DataTable コンストラクタを使用する事に依り作成出来る。此のオ

ブジェクトを DataSet に追加するには、Add メソッドを使用して、DataTable オブジェクトの Tables

コレクションにオブジェクトを追加する。

DataSet の内部で DataTable オブジェクトを作成する場合は、DataAdapter オブジェクトの Fill メソ

ッド、又は、FillSchema メソッドを使用出来る。亦、定義済みや推論に依る XML スキーマで、DataSet

の ReadXml、ReadXmlSchema、又は、InferXmlSchema の各メソッドを使用して作成する事も出来

る。DataTable を 1 つの DataSet の Tables コレクションのメンバと仕て追加した後で、其の DataTable

を他の DataSet のテーブルのコレクションに追加する事は出来ない。

最初に作成した時点では、DataTable にはスキーマ(構造)が無い。テーブルのスキーマを定義するに

は、DataColumn オブジェクトを作成し、テーブルの Columns コレクションに追加する必要が有る。

テーブルの主キー列を定義したり、Constraint オブジェクトを作成してテーブルの Constraints コレク

ションに追加したりする事も出来る。DataTable のスキーマを定義した後で、DataRow オブジェクト

をテーブルの Rows コレクションに追加する事に依り、データ行をテーブルに追加出来る。

DataTable を作成する時に TableName プロパティの値を指定する必要は無い。此のプロパティは、後

から指定する事も、空の儘に仕て置く事も出来る。但し、TableName 値の無いテーブルを DataSet に

追加した場合、其のテーブルの名前は既定のテーブル名 TableN に成る。此の既定名は Table0 に相当

する Table から始まり、連続する番号が割り当てられて行く。

メモ:TableName 値を指定する時には、TableN の命名規則を使用しない事を推奨する。此れは、指定

した名前が DataSet に既に存在する既定のテーブル名と競合しない様にする為で有る。指定した名前が

既に存在する場合は、例外がスローされる。

DataTable オブジェクトのインスタンスを作成し、Customers と謂う名前を割り当てる例を次に示す。

Visual Basic

Dim workTable as DataTable = New DataTable("Customers")

C#

DataTable workTable = new DataTable("Customers");

DataTable のインスタンスを作成し、DataSet の Tables コレクションに追加する例を次に示す。

Visual Basic

Dim customers As DataSet = New DataSet

Dim customersTable As DataTable = customers.Tables.Add("CustomersTable")

C#

DataSet customers = new DataSet( );

DataTable customersTable = customers.Tables.Add("CustomersTable");

DataTable のスキーマの定義

テーブルのスキーマ(構造)は、列と制約で表される。DataTable のスキーマは、DataColumn、

Page 42: データセット - xdomainjunko036.html.xdomain.jp/pdf/database/DataSet.pdfVS 2005 資料 【電脳梁山泊 烏賊塾】 -3- EndInit フォーム又は別のコンポーネントで使用するDataSetの初期化を終了する(初

VS 2005 資料 【電脳梁山泊 烏賊塾】

-42-

ForeignKeyConstraint、UniqueConstraint の各オブジェクトを使用して定義する。テーブルの列は、

データソースの列に割り当てたり、式で算出された値を格納したり、格納されて居る値を自動的にイン

クリメントしたり、主キー値を格納したり出来る。

テーブルの列、リレーション、及び、制約を名前で参照する場合は、大文字と小文字が区別される。複

数の列、リレーション、又は、制約の名前が同じで有っても、大文字と小文字が異なって居れば、1 つ

のテーブルで使用出来る。例えば、Col1 と col1 を同時に使用出来る。此の場合、列を名前で参照する

時は、列名の大文字と小文字を正確に指定する必要が有る。正確に指定しない場合は、例外がスローさ

れる。例えば、テーブルmyTableに列Col1と列 col1が有る場合、Col1 は名前myTable.Columns["Col1"]

で 参 照 さ れ 、 col1 は 名 前 myTable.Columns["col1"] で 参 照 さ れ る 。 孰 れ か の 列 を

myTable.Columns["COL1"] と謂う名前で参照しようとすると、例外が生成される。

大文字と小文字の区別の規則は、特定の名前の列、リレーション、又は、制約が 1 つしかない場合には

適用されない。詰まり、特定の列、リレーション、又は、制約オブジェクトと名前が一致する列、リレ

ーション、又は、制約オブジェクトがテーブルに存在しない場合は、大文字と小文字を区別せずに其の

オブジェクトを名前で参照する事が出来る。此の時、例外はスローされない。例えば、テーブルに Col1

が 1 つしかない場合は、my.Columns["COL1"] を使用して此の列を参照出来る。

メモ:従って、此の動作は DataTable の CaseSensitive プロパティの影響を受けない。CaseSensitive

プロパティは、テーブルのデータに適用され、並替、検索、フィルタ処理、制約の適用等に影響を及ぼ

す。此のプロパティは、テーブルの列、リレーション、及び、制約の参照には適用されない。

・テーブルへの列の追加

DataTable には、テーブルの Columns プロパティに依って参照される DataColumn オブジェクトのコ

レクションが格納される。此の列のコレクションと制約に依って、テーブルのスキーマ(構造)が定義

される。

テーブル内でDataColumnオブジェクトを作成するには、DataColumnコンストラクタを使用するか、

又は、DataColumnCollection の 1 つで有る、テーブルの Columns プロパティの Add メソッドを呼び

出す。Add メソッドは、オプションの ColumnName、DataType、Expression の各引数を受け取り、

新しい DataColumn をコレクションのメンバと仕て作成する。亦、此のメソッドは既存の DataColumn

オブジェクトを受け取り、此のオブジェクトをコレクションに追加する。必要な場合には、追加された

DataColumn への参照を返す。DataTable オブジェクトはデータソースに依存しない為、DataColumn

のデータ型を指定する時には、.NET Framework 型が使用される。

DataTable に 4 つの列を追加する例を次に示す。

Visual Basic

Dim workTable As DataTable = New DataTable("Customers") Dim workCol As DataColumn = workTable.Columns.Add("CustID", Type.GetType("System.Int32"))

workColumn.AllowDBNull = false

workColumn.Unique = true

workTable.Columns.Add("CustLName", Type.GetType("System.String"))

workTable.Columns.Add("CustFName", Type.GetType("System.String"))

workTable.Columns.Add("Purchases", Type.GetType("System.Double"))

C#

DataTable workTable = new DataTable("Customers");

DataColumn workCol = workTable.Columns.Add("CustID", typeof(Int32));

workCol.AllowDBNull = false;

workCol.Unique = true;

workTable.Columns.Add("CustLName", typeof(String));

workTable.Columns.Add("CustFName", typeof(String));

workTable.Columns.Add("Purchases", typeof(Double));

Page 43: データセット - xdomainjunko036.html.xdomain.jp/pdf/database/DataSet.pdfVS 2005 資料 【電脳梁山泊 烏賊塾】 -3- EndInit フォーム又は別のコンポーネントで使用するDataSetの初期化を終了する(初

VS 2005 資料 【電脳梁山泊 烏賊塾】

-43-

此の例では、DBNull 値を許可せずに値を一意の値に制約する様に、CustID 列のプロパティが設定さ

れて居る。但し、CustID 列をテーブルの主キー列と仕て定義した場合、AllowDBNull プロパティは自

動的に false に設定され、Unique プロパティは自動的に true に設定される。詳細に付いては、「テーブ

ルの主キーの定義」を参照され度い。

注意:列名が指定されて居ない列を DataColumnCollection に追加する場合、此の列には Column1 か

ら始まるインクリメンタル既定名 ColumnN が割り当てられる。列名を指定する時には、ColumnN の

命名規則を使用しない事を推奨する。此れは、指定した名前が DataColumnCollection に既に存在する

既定の列名と競合しない様にする為で有る。指定した名前が既に存在する場合は、例外がスローされる。

・式列の作成

列の式を定義すると、同じ行の他の列値、又は、テーブル内の複数の行の列値に基づいて計算した値を、

其の列に格納出来る。評価する式を定義するには、対象の列の Expression プロパティを使用し、其の

式で ColumnName プロパティを使用して他の列を参照する。式列の DataType は、其の式が返す値に

適した型で有る事が必要で有る。

テーブル内の式列で使用出来る幾つかの式の種類を次の表に示す。

式の種類 例

比較 "Total >= 500"

計算 "UnitPrice * Quantity"

集約 Sum(Price)

次の例に示す様に、既存の DataColumn オブジェクトの Expression プロパティを設定したり、此のプ

ロパティを DataColumn コンストラクタに渡す 3 番目の引数と仕て使用したり出来る。

Visual Basic

workTable.Columns.Add("Total",Type.GetType("System.Double"))

workTable.Columns.Add("SalesTax", Type.GetType("System.Double"), "Total * 0.086")

C#

workTable.Columns.Add("Total", typeof(Double));

workTable.Columns.Add("SalesTax", typeof(Double), "Total * 0.086");

式は他の式列を参照出来る。但し、2 つの式が相互に参照し合う循環参照の場合は、例外が生成される。

式の記述の規則に付いては、DataColumn クラスの Expression プロパティの資料を参照され度い。

・AutoIncrement 列の作成

列値を一意にする為に、新しい行がテーブルに追加された時に列値が自動的にインクリメントされる様

に設定出来る。自動インクリメント DataColumn を作成するには、列の AutoIncrement プロパティを

true に設定する。DataColumn の値は AutoIncrementSeed プロパティで定義された値から開始され、

行が追加される度に、AutoIncrement 列の値には、列の AutoIncrementStep プロパティで定義された

値が加算される。

AutoIncrement 列では、DataColumn の ReadOnly プロパティを true に設定する事を推奨する。

値 200 から開始して 3 宛インクリメントする列を作成する方法を次の例に示す。

Visual Basic

Dim workColumn As DataColumn = workTable.Columns.Add("CustomerID", typeof(Int32))

workColumn.AutoIncrement = true

Page 44: データセット - xdomainjunko036.html.xdomain.jp/pdf/database/DataSet.pdfVS 2005 資料 【電脳梁山泊 烏賊塾】 -3- EndInit フォーム又は別のコンポーネントで使用するDataSetの初期化を終了する(初

VS 2005 資料 【電脳梁山泊 烏賊塾】

-44-

workColumn.AutoIncrementSeed = 200

workColumn.AutoIncrementStep = 3

C#

DataColumn workColumn = workTable.Columns.Add("CustomerID", typeof(Int32));

workColumn.AutoIncrement = true;

workColumn.AutoIncrementSeed = 200;

workColumn.AutoIncrementStep = 3;

・テーブルの主キーの定義

通常、データベーステーブルには、テーブル内の各行を一意に識別する単一の列、又は、複数の列が有

る。行を識別する此の様な列を、主キーと呼ぶ。

1つのDataColumnをDataTableのPrimaryKeyと仕て指定すると、テーブルは其の列のAllowDBNull

プロパティを false に、Unique プロパティを true に自動的に設定する。複数列の主キーの場合は、

AllowDBNull プロパティ丈が自動的に false に設定される。

DataTable の PrimaryKey プロパティが其の値と仕て、1 つ以上の DataColumn オブジェクトから成

る配列を受け取る例を次に示す。最初の例は、1 つの列を主キーと仕て定義して居る。

Visual Basic

workTable.PrimaryKey = New DataColumn( ) {workTable.Columns("CustID")}

' 又は

Dim columns(1) As DataColumn

columns(0) = workTable.Columns("CustID")

workTable.PrimaryKey = columns

C#

workTable.PrimaryKey = new DataColumn[] {workTable.Columns["CustID"]};

// 又は

DataColumn[] columns = new DataColumn[1];

columns[0] = workTable.Columns["CustID"];

workTable.PrimaryKey = columns;

2 つの列を主キーと仕て定義する例を次に示す。

Visual Basic

workTable.PrimaryKey = New DataColumn( ) {workTable.Columns("CustLName"), _

workTable.Columns("CustFName")}

' 又は

Dim keyColumn(2) As DataColumn

keyColumn(0) = workTable.Columns("CustLName")

keyColumn(1) = workTable.Columns("CustFName")

workTable.PrimaryKey = keyColumn

C#

workTable.PrimaryKey = new DataColumn[] {workTable.Columns["CustLName"],

workTable.Columns["CustFName"]};

Page 45: データセット - xdomainjunko036.html.xdomain.jp/pdf/database/DataSet.pdfVS 2005 資料 【電脳梁山泊 烏賊塾】 -3- EndInit フォーム又は別のコンポーネントで使用するDataSetの初期化を終了する(初

VS 2005 資料 【電脳梁山泊 烏賊塾】

-45-

// 又は

DataColumn[] keyColumn = new DataColumn[2];

keyColumn[0] = workTable.Columns["CustLName"];

keyColumn[1] = workTable.Columns["CustFName"];

workTable.PrimaryKey = keyColumn;

・テーブルへの制約の追加

制約を使用すると、データの整合性を維持する為に DataTable のデータを強制的に制限出来る。制約は、

1 つの列、又は、関連付けられた複数の列に対して自動的に適用される規則で有り、行の値が何等かの

方法で変更された時に実行されるアクションを決定する。制約は、DataSet の EnforceConstraints プ

ロパティを true に設定した時に適用される。

ADO.NET には、ForeignKeyConstraint と UniqueConstraint の 2 種類の制約が有る。既定では、

DataRelation を DataSet に追加して複数のテーブル間のリレーションシップを作成すると、此の 2 種

類の制約が両方共自動的に作成される。但し、リレーションの作成時に createConstraints = false と指

定する事に依り、此の動作を無効に出来る。

ForeignKeyConstraint

ForeignKeyConstraint は、関連付けられて居るテーブルに更新や削除を反映させる方法に付いての規

則を適用する。例えば、或るテーブルの行の値が更新や削除され、其の同じ値が、関連付けられて居る

別のテーブルでも使用されて居る場合、関連付けられて居るテーブル内で実行されるアクションは

ForeignKeyConstraint に依って決定される。

ForeignKeyConstraint の DeleteRule プロパティと UpdateRule プロパティは、ユーザーが関連付けら

れて居るテーブルの行を削除、又は、更新しようと仕た時に実行されるアクションを定義する。

ForeignKeyConstraintのDeleteRuleプロパティとUpdateRuleプロパティに使用出来る様々な設定の

説明を次の表に示す。

規則の設定 説明

Cascade 関連付けられて居る行を削除・更新する。

SetNull 関連付けられて居る行の値を DBNull に設定する。

SetDefault 関連付けられて居る行の値を既定値に設定する。

None 関連付けられて居る行に対してアクションは実行しない(既定値)。

ForeignKeyConstraint は、関連付けられて居る行への変更を制限したり、反映させたり出来る。列の

ForeignKeyConstraint に対して設定されたプロパティに依っては、DataSet の EnforceConstraints プ

ロパティが true で有る場合に親の行に対して操作を実行すると、例外が発生する事が有る。例えば、

ForeignKeyConstraint の DeleteRule プロパティが None の場合、子の行を持って居る親の行は削除出

来ない。

ForeignKeyConstraint コンストラクタを使用すると、単一列間や列配列間の外部キー制約を作成出来

る。ConstraintCollection の 1 つで有る、テーブルの Constraints プロパティの Add メソッドに結果の

ForeignKeyConstraint オブジェクトを渡す。コンストラクタ引数を ConstraintCollection の Add メソ

ッドの幾つかのオーバーロードに渡す事に依り、ForeignKeyConstraint を作成する事も出来る。

ForeignKeyConstraint を作成する時に、DeleteRule の値と UpdateRule の値を引数と仕てコンストラ

クタに渡したり、其等の値を次の例に示す様にプロパティと仕て設定したり出来る。此の例では、

DeleteRule の値が None に設定されて居る。

Page 46: データセット - xdomainjunko036.html.xdomain.jp/pdf/database/DataSet.pdfVS 2005 資料 【電脳梁山泊 烏賊塾】 -3- EndInit フォーム又は別のコンポーネントで使用するDataSetの初期化を終了する(初

VS 2005 資料 【電脳梁山泊 烏賊塾】

-46-

Visual Basic

Dim custOrderFK As ForeignKeyConstraint = New ForeignKeyConstraint("CustOrderFK", _

custDS.Tables("CustTable").Columns("CustomerID"), _

custDS.Tables("OrdersTable").Columns("CustomerID"))

custOrderFK.DeleteRule = Rule.None

' Cannot delete a customer value that has associated existing orders.

custDS.Tables("OrdersTable").Constraints.Add(custOrderFK)

C#

ForeignKeyConstraint custOrderFK = new ForeignKeyConstraint("CustOrderFK",

custDS.Tables["CustTable"].Columns["CustomerID"],

custDS.Tables["OrdersTable"].Columns["CustomerID"]);

custOrderFK.DeleteRule = Rule.None;

// Cannot delete a customer value that has associated existing orders.

custDS.Tables["OrdersTable"].Constraints.Add(custOrderFK);

AcceptRejectRule

行への変更は、AcceptChanges メソッドを使用して受け入れる事が出来、DataSet、DataTable、又は、

DataRow の RejectChanges メ ソ ッ ド を 使 用 し て キ ャ ン セ ル 出 来 る 。 DataSet に

ForeignKeyConstraints が含まれて居る場合は、AcceptChanges メソッドや RejectChanges メソッド

を呼び出すと、AcceptRejectRule が強制適用される。ForeignKeyConstraint の AcceptRejectRule プ

ロパティは、親の行に対して AcceptChanges 又は RejectChanges が呼び出された時に、子の行に対し

て実行されるアクションを決定する。

AcceptRejectRule に使用出来る設定の一覧を次の表に示す。

規則の設定 説明

Cascade 子の行への変更を受け入れるか、又は、拒否する。

None 子の行に対してアクションは実行しない(既定値)。

UniqueConstraint

UniqueConstraintオブジェクトは、DataTable内の1つの列や列の配列に対して割り当てる事が出来、

指定された列内の総てのデータが行毎に一意に成る様にする。UniqueConstraint コンストラクタを使

用して、1 つの列や列の配列に対する UNIQUE 制約を作成出来る。ConstraintCollection の 1 つで有

るテーブルのConstraints プロパティのAddメソッドに結果のUniqueConstraintオブジェクトを渡す。

コンストラクタ引数を ConstraintCollection の Add メソッドの幾つかのオーバーロードに渡す事に依

り、UniqueConstraint を作成する事も出来る。1 つの列や複数の列に対して UniqueConstraint を作成

する時は、オプションで、其の列や複数の列を主キーにするか何うかを指定出来る。

列の Unique プロパティを true に設定する事に依り、1 つの列に対する UNIQUE 制約を作成する事も

出来る。亦、1 つの列の Unique プロパティを false に設定する事に依り、既存の UNIQUE 制約を削除

出来る。1 つの列(又は、複数の列)をテーブルの主キーと仕て定義すると、指定した列(又は、複数

の列)の UNIQUE 制約が自動的に作成される。DataTable の PrimaryKey プロパティから列を削除す

ると、UniqueConstraint が削除される。

DataTable の 2 つの列の UniqueConstraint を作成する例を次に示す。

Visual Basic

Dim custTable As DataTable = custDS.Tables("Customers")

Dim custUnique As UniqueConstraint = _

New UniqueConstraint(New DataColumn( ) {custTable.Columns("CustomerID"), _

custTable.Columns("CompanyName")})

Page 47: データセット - xdomainjunko036.html.xdomain.jp/pdf/database/DataSet.pdfVS 2005 資料 【電脳梁山泊 烏賊塾】 -3- EndInit フォーム又は別のコンポーネントで使用するDataSetの初期化を終了する(初

VS 2005 資料 【電脳梁山泊 烏賊塾】

-47-

custDS.Tables("Customers").Constraints.Add(custUnique)

C#

DataTable custTable = custDS.Tables["Customers"];

UniqueConstraint custUnique = new UniqueConstraint(new DataColumn[]

{custTable.Columns["CustomerID"],

custTable.Columns["CompanyName"]});

custDS.Tables["Customers"].Constraints.Add(custUnique);

DataTable 内のデータの操作

DataSet 内に DataTable を作成した後で、データベース内のテーブルを使用する場合と同じ操作を実行

出来る。テーブル内のデータの追加、表示、編集、及び、削除を実行したり、エラーとイベントを監視

したり、テーブル内のデータを照会したり出来る。DataTable 内のデータを変更する時には、変更が正

確か何うかを検証したり、変更をプログラムに依って受け入れるか、又は、拒否するかを決定したりす

る事も出来る。

・テーブルへのデータの追加

DataTable を作成し、列と制約を使用して其のテーブルの構造を定義した後で、テーブルに新しいデー

タ行を追加出来る。新しい行を追加するには、新しい変数を DataRow 型と仕て宣言する。NewRow メ

ソッドを呼び出すと、新しい DataRow オブジェクトが返される。次に、DataTable は、

DataColumnCollection での定義に従って、テーブルの構造に基づいて DataRow オブジェクトを作成

する。

NewRow メソッドを呼び出して新しい行を作成する例を次に示す。

Visual Basic

Dim workRow As DataRow = workTable.NewRow( )

C#

DataRow workRow = workTable.NewRow( );

其の後でインデックス、又は、列名を使用して、新しく追加した行を操作する例を次に示す。

Visual Basic

workRow("CustLName") = "Smith"

workRow(1) = "Smith"

C#

workRow["CustLName"] = "Smith";

workRow[1] = "Smith";

新しい行にデータを挿入した後で Add メソッドを使用して DataRowCollection に行を追加するコード

を次に示す。

Visual Basic

workTable.Rows.Add(workRow)

C#

workTable.Rows.Add(workRow);

Addメソッドを呼び出してObject型の値の配列を渡す事に依り、新しい行を追加する別例を次に示す。

Visual Basic

workTable.Rows.Add(new Object( ) {1, "Smith"})

C#

workTable.Rows.Add(new Object[] {1, "Smith"});

Page 48: データセット - xdomainjunko036.html.xdomain.jp/pdf/database/DataSet.pdfVS 2005 資料 【電脳梁山泊 烏賊塾】 -3- EndInit フォーム又は別のコンポーネントで使用するDataSetの初期化を終了する(初

VS 2005 資料 【電脳梁山泊 烏賊塾】

-48-

Object 型の値の配列を Add メソッドに渡すと、テーブル内に新しい行が作成され、其の行の列値がオ

ブジェクト配列の値に設定される。配列内の値は、テーブル内での列の順序に基づいて、列に順次的に

割り当てられる。

新しく作成した Customers テーブルに 10 行を追加する例を次に示す。

Visual Basic

Dim workRow As DataRow

Dim i As Integer

For i = 0 To 9

workRow = workTable.NewRow( )

workRow(0) = i

workRow(1) = "CustName" & I.ToString( )

workTable.Rows.Add(workRow)

Next

C#

DataRow workRow;

for (int i = 0; i <= 9; i++)

{

workRow = workTable.NewRow( );

workRow[0] = i;

workRow[1] = "CustName" + i.ToString( );

workTable.Rows.Add(workRow);

}

・テーブル内のデータの表示

DataTable の内容には、DataTable の Rows コレクションと Columns コレクションを使用してアクセ

ス出来る。亦、Select メソッドを使用すると、検索条件、並替順序、行の状態等の基準に基づいて

DataTable 内のデータのサブセットを返す事が出来る。更に、主キー値を使用して特定の行を検索する

時は、DataRowCollection の Find メソッドを使用出来る。

DataTable オブジェクトの Select メソッドは、指定された基準と一致する DataRow オブジェクトのセ

ットを返す。Select は、フィルタ式、並替式、及び、DataViewRowState のオプション引数を受け取る。

フィルタ式は、DataColumn 値に基づいて返す行を識別する LastName = 'Smith' 等の式で有る並替式

は、列の並替に付いての標準 SQL 規則に基づく LastName ASC, FirstName ASC 等の式で有る式の記

述の規則に付いては、DataColumn クラスの Expression プロパティの資料を参照され度い。

ヒント:DataTable の Select メソッドへの呼出を多数実行する場合は、最初に DataTable の DataView

を作成する事に依り、パフォーマンスを向上させる事が出来る。DataView を作成すると、テーブルの

行にインデックスが付けられる。Select メソッドが此のインデックスを使用すると、クエリ結果を生成

する迄の時間が大幅に減少する。DataTable の DataView を作成する方法に付いては、「DataView の

作成と使用」を参照され度い。

Select メソッドは、DataViewRowState に基づいて、表示や操作する行のバージョンを判断する。有効

な DataViewRowState 列挙値の説明を次の表に示す。

DataViewRowStateの値 説明

CurrentRows 変更されて居ない行、追加された行、及び、変更された行を含む現在の行。

Deleted 削除された行。

ModifiedCurrent 元のデータを変更した後のバージョンで有る現在のバージョン。

ModifiedOriginal を参照され度い。

Page 49: データセット - xdomainjunko036.html.xdomain.jp/pdf/database/DataSet.pdfVS 2005 資料 【電脳梁山泊 烏賊塾】 -3- EndInit フォーム又は別のコンポーネントで使用するDataSetの初期化を終了する(初

VS 2005 資料 【電脳梁山泊 烏賊塾】

-49-

ModifiedOriginal 変更された総ての行の元のバージョン。

現在のバージョンは、ModifiedCurrent を使用して取得出来る。

Added 新しい行。

None 無し。

OriginalRows 変更されて居ない行、及び、削除された行を含む元の行。

Unchanged 変更されて居ない行。

DataSet オブジェクトをフィルタ処理して、DataViewRowState が CurrentRows に設定されて居る行

丈を操作出来る様にする例を次に示す。

Visual Basic

Dim column As DataColumn

Dim row As DataRow

Dim currentRows( ) As DataRow = _

workTable.Select(Nothing, Nothing, DataViewRowState.CurrentRows)

If (currentRows.Length < 1 ) Then

Console.WriteLine("No Current Rows Found")

Else

For Each column in workTable.Columns

Console.Write(vbTab & column.ColumnName)

Next

Console.WriteLine(vbTab & "RowState")

For Each row In currentRows

For Each column In workTable.Columns

Console.Write(vbTab & row(column).ToString( ))

Next

Dim rowState As String = _

System.Enum.GetName(row.RowState.GetType( ), row.RowState)

Console.WriteLine(vbTab & rowState)

Next

End If

C#

DataRow[] currentRows = workTable.Select(null, null, DataViewRowState.CurrentRows);

if (currentRows.Length < 1 )

Console.WriteLine("No Current Rows Found");

else

{

foreach (DataColumn column in workTable.Columns)

Console.Write("¥t{0}", column.ColumnName);

Console.WriteLine("¥tRowState");

foreach (DataRow row in currentRows)

{

foreach (DataColumn column in workTable.Columns)

Console.Write("¥t{0}", row[column]);

Console.WriteLine("¥t" + row.RowState);

}

}

Select メソッドを使用して、異なる RowState 値やフィールド値を持つ行を返す事も出来る。削除され

た総ての行を参照する DataRow 配列を返し、亦、CustLName を基準にして並べ替えた CustID 列が 5

Page 50: データセット - xdomainjunko036.html.xdomain.jp/pdf/database/DataSet.pdfVS 2005 資料 【電脳梁山泊 烏賊塾】 -3- EndInit フォーム又は別のコンポーネントで使用するDataSetの初期化を終了する(初

VS 2005 資料 【電脳梁山泊 烏賊塾】

-50-

より大きい総ての行を参照する、別の DataRow 配列も返す例を次に示す。Deleted 行の情報を表示す

る方法に付いては、「行の状態とバージョン」を参照され度い。

Visual Basic

' Retrieve all deleted rows. Dim deletedRows( ) As DataRow = workTable.Select(Nothing, Nothing, DataViewRowState.Deleted)

' Retrieve rows where CustID > 5, and order by CustLName.

Dim custRows( ) As DataRow = workTable.Select("CustID > 5", "CustLName ASC")

C#

// Retrieve all deleted rows.

DataRow[] deletedRows = workTable.Select(null, null, DataViewRowState.Deleted);

// Retrieve rows where CustID > 5, and order by CustLName.

DataRow[] custRows = workTable.Select("CustID > 5", "CustLName ASC");

・Load メソッドの使用

Load メソッドを使用して、データソースの行を DataTable に読み込む事が出来る。此れはオーバーロ

ードされたメソッドで、最も単純な形式で単一のDataReaderパラメータを受け取る。此の形式に依り、

此のメソッドは DataTable に対する行の読み込み而巳を行う。或るいは、LoadOption パラメータを指

定して DataTable へのデータの追加方法を制御する事も出来る。

LoadOption パラメータは、DataTable にデータの行が既に含まれて居る場合に特に役立つ。其れは、

此のパラメータに依って、データソースから読み込まれるデータとテーブル内に既に存在するデータを

組み合わせる方法が指定されて居る為で有る例えば、PreserveCurrentValues(既定値)は、DataTable

の行が Added と仕てマークされ、データソースの行に一致する内容に対して Original 値や各列が設定

されて居る場合に指定する。Current 値は、行が追加された時に割り当てられた値が保持され、其の行

の RowState は Changed に設定される。

LoadOption 列挙値の簡単な説明を次の表に示す。

LoadOption の値 説明

OverwriteRow 読み込まれる行と DataTable に既に存在する行で PrimaryKey 値が同じ場合、各列の Original 値と Current 値は読み込まれる行の値に置き換えられ、RowState プロパティは Unchanged に設定される。

DataTable に存在して居なかった行がデータソースから読み込まれ、其の行の RowState 値は Unchanged に設定される。

此のオプションは DataTable の内容を更新して、データソースの内容と一致する様にする。

PreserveCurrentValues

(既定値)

読み込まれる行と DataTable に既に存在する行の PrimaryKey 値が同じ場合、Original 値には読み込まれる行の内容が設定されるが、Current 値は変更されない。

RowState が Added 又は Modified の場合、此の値は Modified に設定される。

RowState が Deleted で有った場合、此の値は Deleted の儘と成る。

DataTable に存在して居なかった行がデータソースから読み込まれ、其の行の RowState は Unchanged に設定される。

UpdateCurrentValues 読み込まれる行と DataTable に既に存在する行の PrimaryKey 値が同じ場合、Current 値が Original 値にコピーされ、Current 値には読み込まれる行の内容が設定される。

DataTable の RowState が Added の場合、RowState は Added の儘と成る。Modified 又は Deleted と仕てマークされた行の RowState は Modified に成る。

DataTable に存在して居なかった行がデータソースから読み込まれ、其の行の RowState は Added に設定される。

Page 51: データセット - xdomainjunko036.html.xdomain.jp/pdf/database/DataSet.pdfVS 2005 資料 【電脳梁山泊 烏賊塾】 -3- EndInit フォーム又は別のコンポーネントで使用するDataSetの初期化を終了する(初

VS 2005 資料 【電脳梁山泊 烏賊塾】

-51-

Load メソッドを使用して Northwind データベースに従業員の誕生日リストを表示する例を次に示す。

Visual Basic

Private Sub LoadBirthdays(ByVal connectionString As String)

' Assumes that connectionString is a valid connection string

' to the Northwind database on SQL Server.

Dim queryString As String = _

"SELECT LastName, FirstName, BirthDate " & _

" FROM dbo.Employees " & _

"ORDER BY BirthDate, LastName, FirstName"

' Open and fill a DataSet.

Dim adapter As SqlDataAdapter = New SqlDataAdapter( _

queryString, connectionString)

Dim employees As New DataSet

adapter.Fill(employees, "Employees")

' Create a SqlDataReader for use with the Load Method.

Dim reader As DataTableReader = employees.GetDataReader( )

' Create an instance of DataTable and assign the first

' DataTable in the DataSet.Tables collection to it.

Dim dataTableEmp As DataTable = employees.Tables(0)

' Fill the DataTable with data by calling Load and passing the SqlDataReader.

dataTableEmp.Load(reader, LoadOption.OverwriteRow)

' Loop through the rows collection and display the values in the console window.

Dim employeeRow As DataRow

For Each employeeRow In dataTableEmp.Rows

Console.WriteLine("{0:MM¥¥dd¥¥yyyy}" & ControlChars.Tab & "{1}, {2}", _

employeeRow("BirthDate"), _

employeeRow("LastName"), _

employeeRow("FirstName"))

Next employeeRow

' Keep the window opened to view the contents.

Console.ReadLine( )

End Sub

・テーブル内のデータの編集

DataRow 内の列値を変更すると、其の変更は直ぐに行の現在の状態に反映される。次に、DataRowState

が Modified に設定され、DataRow の AcceptChanges メソッドや RejectChanges メソッドを使用して

変更が受け入れられるか、又は、拒否される。DataRow は、行の編集中に、其の行の状態を保留に仕

て置く為に使用出来る 3 つのメソッドも提供する。此等のメソッドとは、BeginEdit、EndEdit 及び

CancelEdit で有る。

DataRow の列値が直接変更されると、DataRow は、Current、Default、Original の各行バージョンを

使用して列値を管理する。BeginEdit、EndEdit、CancelEdit の各メソッドでは、此等の行バージョン

に加えて、4 番目の行バージョン Proposed を使用する。行バージョンの詳細に付いては、「行の状態と

バージョン」を参照され度い。

Proposed 行バージョンは、編集操作中に存在するバージョンで有る編集操作は、BeginEdit への呼出

Page 52: データセット - xdomainjunko036.html.xdomain.jp/pdf/database/DataSet.pdfVS 2005 資料 【電脳梁山泊 烏賊塾】 -3- EndInit フォーム又は別のコンポーネントで使用するDataSetの初期化を終了する(初

VS 2005 資料 【電脳梁山泊 烏賊塾】

-52-

に依って開始し、EndEdit 又は CancelEdit の使用、或るいは、AcceptChanges 又は RejectChanges

の呼出に依って終了する。

編集操作中に、DataTable の ColumnChanged イベントで ProposedValue を評価する事に依り、個々

の列に検証ロジックを適用出来る。ColumnChanged イベントは、変更されて居る列への参照と

ProposedValue への参照を維持する DataColumnChangeEventArgs を保持する。提示された値を評価

した後で、値を変更するか、又は、編集をキャンセル出来る。編集が終了すると、行は Proposed 状態

ではなく成る。

EndEdit を呼び出すと編集内容を確定出来、CancelEdit を呼び出すと編集内容をキャンセル出来る。

EndEdit は編集内容を確定するが、DataSet は AcceptChanges が呼び出される迄は実際には変更を受

け入れない。亦、EndEdit 又は CancelEdit を使用して編集を終了する前に AcceptChanges を呼び出し

た場合は、編集が終了し、Proposed 行値が Current 行バージョンと Original 行バージョンの両方に受

け入れられる。同様に、RejectChanges を呼び出した場合も編集が終了し、Current 行バージョンと

Proposed 行バージョンの両方が破棄される。AcceptChanges 又は RejectChanges を呼び出した後で

EndEdit 又は CancelEdit を呼び出しても、編集が既に終了して居る為、其の呼出は無効に成る。

BeginEdit、EndEdit 及び CancelEdit を使用する方法を次の例に示す。此の例では、ColumnChanged

イベントで ProposedValue をチェックして、編集をキャンセルするか何うかを決定して居る。

Visual Basic

Dim workTable As DataTable = New DataTable

workTable.Columns.Add("LastName", Type.GetType("System.String"))

AddHandler workTable.ColumnChanged, _

New DataColumnChangeEventHandler(AddressOf OnColumnChanged)

Dim workRow As DataRow = workTable.NewRow( )

workRow(0) = "Smith"

workTable.Rows.Add(workRow)

workRow.BeginEdit( )

' Causes the ColumnChanged event to write a message and cancel the edit.

workRow(0) = ""

workRow.EndEdit( )

' Displays "Smith, New".

Console.WriteLine("{0}, {1}", workRow(0), workRow.RowState)

Private Shared Sub OnColumnChanged( sender As Object, args As DataColumnChangeEventArgs)

If args.Column.ColumnName = "LastName" Then

If args.ProposedValue.ToString( ) = "" Then

Console.WriteLine("Last Name cannot be blank.Edit canceled.")

args.Row.CancelEdit( )

End If

End If

End Sub

C#

DataTable workTable= new DataTable( );

workTable.Columns.Add("LastName", typeof(String));

workTable.ColumnChanged +=

new DataColumnChangeEventHandler(OnColumnChanged);

Page 53: データセット - xdomainjunko036.html.xdomain.jp/pdf/database/DataSet.pdfVS 2005 資料 【電脳梁山泊 烏賊塾】 -3- EndInit フォーム又は別のコンポーネントで使用するDataSetの初期化を終了する(初

VS 2005 資料 【電脳梁山泊 烏賊塾】

-53-

DataRow workRow = workTable.NewRow( );

workRow[0] = "Smith";

workTable.Rows.Add(workRow);

workRow.BeginEdit( );

// Causes the ColumnChanged event to write a message and cancel the edit.

workRow[0] = "";

workRow.EndEdit( );

// Displays "Smith, New".

Console.WriteLine("{0}, {1}", workRow[0], workRow.RowState);

protected static void OnColumnChanged(Object sender, DataColumnChangeEventArgs args)

{

if (args.Column.ColumnName == "LastName")

if (args.ProposedValue.ToString( ) == "")

{

Console.WriteLine("Last Name cannot be blank. Edit canceled.");

args.Row.CancelEdit( );

}

}

・行の状態とバージョン

ADO.NET は、行の状態とバージョンを使用してテーブル内の行を管理する。行状態は、1 つの行のス

テータスを示す。行バージョンは、1 つの行の値が変更される時に、変更に応じて其の行に格納される

現在の値、元の値、既定値等を維持する。例えば、或る行の 1 つの列を変更すると、此の行の状態は

Modified に成り、次の 2 つの行バージョンが存在する事に成る。Current には現在の行値が格納され、

Original には其の列が変更される前の行値が格納される。

各 DataRow オブジェクトに有る RowState プロパティを調べると、行の現在の状態を確認出来る。各

RowState 列挙値の簡単な説明を次の表に示す。

RowState の値 説明

Unchanged AcceptChanges が最後に呼び出されてから、又は、DataAdapter.Fill に依って行

が作成されてから変更は行われて居ない。

Added 行がテーブルに追加されたが、AcceptChanges が呼び出されて居ない。

Modified 行の幾つかの要素が変更された。

Deleted 行がテーブルから削除されたが、AcceptChanges が呼び出されて居ない。

Detached 行が何の DataRowCollection にも属して居ない。新しく作成された行の RowState

は Detached に設定される。Add メソッドを呼び出して新しい DataRow を

DataRowCollection に追加すると、RowState プロパティの値は Added に設定され

る。

Detached は、Remove メソッドを使用するか、又は、Delete メソッドに続いて

AcceptChanges メソッドを使用してDataRowCollection から削除された行に対し

ても設定される。

DataSet、DataTable、又は、DataRow に対して AcceptChanges が呼び出されると、Deleted の行状

態を持つ総ての行が削除される。残りの行状態は Unchanged に成り、Original 行バージョンの値は

Current 行バージョンの値で上書きされる。RejectChanges が呼び出されると、Added の行状態を持つ

総ての行が削除される。残りの行の行状態は Unchanged に成り、Current 行バージョンの値は Original

行バージョンの値で上書きされる。

Page 54: データセット - xdomainjunko036.html.xdomain.jp/pdf/database/DataSet.pdfVS 2005 資料 【電脳梁山泊 烏賊塾】 -3- EndInit フォーム又は別のコンポーネントで使用するDataSetの初期化を終了する(初

VS 2005 資料 【電脳梁山泊 烏賊塾】

-54-

DataRowVersionパラメータと列参照を渡す事に依り、或る行の行バージョンを表示する例を次に示す。

Visual Basic

Dim custRow As DataRow = custTable.Rows(0)

Dim custID As String = custRow("CustomerID", DataRowVersion.Original).ToString( )

C#

DataRow custRow = custTable.Rows[0];

string custID = custRow["CustomerID", DataRowVersion.Original].ToString( );

各 DataRowVersion 列挙値の簡単な説明を次の表に示す。

DataRowVersion の値 説明

Current 行の現在の値。此の行バージョンは、Deleted の RowState を持つ行に付い

ては存在しない。

Default 特定の行の既定の行バージョン。Added、Modified、又は、Unchanged 行

の既定の行バージョンは、Current で有る Deleted 行の既定の行バージョ

ンは、Original で有る Detached 行の既定の行バージョンは、Proposed で

有る。

Original 行の元の値。此の行バージョンは、Added の RowState を持つ行に付いて

は存在しない。

Proposed 行に対して提示された値。此の行バージョンは、行、詰まり

DataRowCollection の一部ではない行に対する編集操作の間存在する。

HasVersion メソッドを呼び出して DataRowVersion を引数と仕て渡す事に依り、DataRow が特定の行

バージョンを持って居るか何うかを確認出来る。例えば、下記は、新しく追加された行に対して

AcceptChanges が呼び出されて居ない場合に false を返す。

DataRow.HasVersion(DataRowVersion.Original)

テーブルから削除された総ての行の値を表示するコード例を次に示す。Deleted 行には Current 行バー

ジョンが無い為、列値にアクセスする時には DataRowVersion.Original を渡す必要が有る。

Visual Basic

Dim catTable As DataTable = catDS.Tables("Categories")

Dim delRows( ) As DataRow = catTable.Select(Nothing, Nothing, DataViewRowState.Deleted)

Console.WriteLine("Deleted rows:" & vbCrLf)

Dim catCol As DataColumn

Dim delRow As DataRow

For Each catCol In catTable.Columns

Console.Write(catCol.ColumnName & vbTab)

Next

Console.WriteLine( )

For Each delRow In delRows

For Each catCol In catTable.Columns

Console.Write(delRow(catCol, DataRowVersion.Original) & vbTab)

Next

Console.WriteLine( )

Next

Page 55: データセット - xdomainjunko036.html.xdomain.jp/pdf/database/DataSet.pdfVS 2005 資料 【電脳梁山泊 烏賊塾】 -3- EndInit フォーム又は別のコンポーネントで使用するDataSetの初期化を終了する(初

VS 2005 資料 【電脳梁山泊 烏賊塾】

-55-

C#

DataTable catTable = catDS.Tables["Categories"];

DataRow[] delRows = catTable.Select(null, null, DataViewRowState.Deleted);

Console.WriteLine("Deleted rows:¥n");

foreach (DataColumn catCol in catTable.Columns)

Console.Write(catCol.ColumnName + "¥t");

Console.WriteLine( );

foreach (DataRow delRow in delRows)

{

foreach (DataColumn catCol in catTable.Columns)

Console.Write(delRow[catCol, DataRowVersion.Original] + "¥t");

Console.WriteLine( );

}

・テーブルからの行の削除

DataTable オブジェクトから DataRow オブジェクトを削除するには、DataRowCollection オブジェク

トの Remove メソッドと DataRow オブジェクトの Delete メソッドの 2 つのメソッドを使用出来る。

Remove メソッドは DataRowCollection から DataRow を削除するが、一方の Delete メソッドは削除

対象の行をマークする丈で有る。実際の削除は、アプリケーションが AcceptChanges メソッドを呼び

出すと実行される。Delete を使用すると、行を実際に削除する前に、削除対象と仕て何の行がマークさ

れて居るかをプログラムに依ってチェック出来る。削除対象と仕てマークされて居る行の RowState プ

ロパティは、Deleted に設定される。

DataAdapter、及び、リレーショナルデータソースに関連して DataSet や DataTable を使用する時は、

DataRow の Delete メソッドを使用して行を削除する。Delete メソッドは、DataSet や DataTable の

行を Deleted と仕てマークするが、其の行を削除しない。代わりに、DataAdapter が Deleted と仕て

マークされた行を検出した時に DeleteCommand メソッドを実行して、データソースの該当する行を削

除する。其の後、AcceptChanges メソッドを使用して、其の行を永続的に削除出来る。Remove を使用

して行を削除すると、行はテーブルから完全に削除されるが、DataAdapter はデータソースの該当する

行を削除しない。

DataRowCollection の Remove メソッドが DataRow を引数と仕て受け取り、其の行をコレクションか

ら削除する例を次に示す。

Visual Basic

workTable.Rows.Remove(workRow)

C#

workTable.Rows.Remove(workRow);

此れに対して、DataRow の Delete メソッドを呼び出して、該当する行の RowState を Deleted に変更

する例を次に示す。

Visual Basic

workRow.Delete

C#

workRow.Delete( );

行を削除対象と仕てマークしてからDataTableオブジェクトのAcceptChangesメソッドを呼び出すと、

Page 56: データセット - xdomainjunko036.html.xdomain.jp/pdf/database/DataSet.pdfVS 2005 資料 【電脳梁山泊 烏賊塾】 -3- EndInit フォーム又は別のコンポーネントで使用するDataSetの初期化を終了する(初

VS 2005 資料 【電脳梁山泊 烏賊塾】

-56-

其の行が DataTable から削除される。此れに対して、RejectChanges を呼び出すと、行の RowState

は其の行が Deleted と仕てマークされる前の状態に戻る。

メモ: DataRow の RowState が Added で有る場合、詰まり、テーブルに行が追加された直後の状態

の場合に、其の行を Deleted と仕てマークすると、其の行はテーブルから削除される。

・行のエラー情報の追加と読み取り

DataTable の値を編集して居る時に、行エラーに対処する必要を無くす為に、エラー情報を行に追加し

て後で使用する事が出来る。DataRow オブジェクトは、此の目的の為に各行に RowError プロパティ

を提供する。DataRow の RowError プロパティにデータを追加すると、其の DataRow の HasErrors

プロパティが true に設定される。DataRow が DataTable の一部で有り、DataRow.HasErrors が true

で有る場合は、DataTable.HasErrors プロパティも true に成る。此の原則は、DataTable が属して居

る DataSet に対しても適用される。エラーの有無を確認する場合は、HasErrors プロパティをチェッ

クして、エラー情報が追加された行が有るか何うかを判断出来る。HasErrors が true の場合に

DataTable の GetErrors メソッドを使用して、エラーの有る行丈を返してチェックする例を次に示す。

Visual Basic

Dim workTable As DataTable = New DataTable("Customers")

workTable.Columns.Add("CustID", Type.GetType("System.Int32"))

workTable.Columns.Add("Total", Type.GetType("System.Double"))

AddHandler workTable.RowChanged, _

New DataRowChangeEventHandler(AddressOf OnRowChanged)

Dim i As Int32

For i= 0 To 10

workTable.Rows.Add(New Object( ) {i , i *100})

Next

If workTable.HasErrors Then

Console.WriteLine("Errors in Table " & workTable.TableName)

Dim myRow As DataRow

For Each myRow In workTable.GetErrors( )

Console.WriteLine("CustID = " & myRow("CustID").ToString( ))

Console.WriteLine(" Error = " & myRow.RowError & vbCrLf)

Next

End If

Private Shared Sub OnRowChanged(sender As Object, args As DataRowChangeEventArgs)

' Check for zero values.

If CDbl(args.Row("Total")) = 0 Then args.Row.RowError = "Total cannot be 0."

End Sub

C#

DataTableworkTable = new DataTable("Customers");

workTable.Columns.Add("CustID", typeof(Int32));

workTable.Columns.Add("Total", typeof(Double));

workTable.RowChanged += new DataRowChangeEventHandler(OnRowChanged);

for (int i = 0; i < 10; i++)

workTable.Rows.Add(new Object[] {i, i*100});

Page 57: データセット - xdomainjunko036.html.xdomain.jp/pdf/database/DataSet.pdfVS 2005 資料 【電脳梁山泊 烏賊塾】 -3- EndInit フォーム又は別のコンポーネントで使用するDataSetの初期化を終了する(初

VS 2005 資料 【電脳梁山泊 烏賊塾】

-57-

if (workTable.HasErrors)

{

Console.WriteLine("Errors in Table " + workTable.TableName);

foreach (DataRow myRow in workTable.GetErrors( ))

{

Console.WriteLine("CustID = " + myRow["CustID"]);

Console.WriteLine(" Error = " + myRow.RowError + "¥n");

}

}

protected static void OnRowChanged(Object sender, DataRowChangeEventArgs args)

{

// Check for zero values.

if (args.Row["Total"].Equals(0D)) args.Row.RowError = "Total cannot be 0.";

}

・行への変更の受入と拒否

DataTable 内のデータに行われた変更が正確で有るか何うかを検証した後で、DataRow、DataTable、

又は、DataSet の AcceptChanges メソッドを使用して、変更を受け入れる事が出来る。変更を受け入

れると、Current 行値が Original 値に設定され、RowState プロパティが Unchanged に設定される。

変更を受け入れるか、又は、拒否すると、RowError 情報が削除され、HasErrors プロパティが false

に設定される。変更を受け入れるか、又は、拒否した場合、データソース内で実行中の更新操作にも影

響する事が有る。詳細に付いては、「DataAdapter に依るデータソースの更新」を参照され度い。

DataTable に外部キー制約が存在する場合、AcceptChanges と RejectChanges を使用して受け入れら

れた変更、又は、拒否された変更は、ForeignKeyConstraint.AcceptRejectRule に基づいて DataRow

の子の行に反映される。詳細に付いては、「テーブルへの制約の追加」を参照され度い。

行にエラーが有るか何うかをチェックし、必要に応じてエラーを解決し、エラーを解決出来ない場合に

は其の行を拒否する例を次に示す。解決されたエラーに付いては、RowError 値が空の文字列にリセッ

トされる為、HasErrors プロパティが false に設定される。エラーの有る行が総て解決又は拒否された

時点で、DataTable 全体に対する総ての変更を受け入れる為に、AcceptChanges が呼び出される。

Visual Basic

If workTable.HasErrors Then

Dim errRow As DataRow

For Each errRow in workTable.GetErrors( )

If errRow.RowError = "Total cannot exceed 1000." Then

errRow("Total") = 1000

errRow.RowError = ""' Clear the error.

Else

errRow.RejectChanges( )

End If

Next

End If

workTable.AcceptChanges( )

C#

if (workTable.HasErrors)

{

foreach (DataRow errRow in workTable.GetErrors( ))

Page 58: データセット - xdomainjunko036.html.xdomain.jp/pdf/database/DataSet.pdfVS 2005 資料 【電脳梁山泊 烏賊塾】 -3- EndInit フォーム又は別のコンポーネントで使用するDataSetの初期化を終了する(初

VS 2005 資料 【電脳梁山泊 烏賊塾】

-58-

{

if (errRow.RowError == "Total cannot exceed 1000.")

{

errRow["Total"] = 1000;

errRow.RowError = "";// Clear the error.

}

else

errRow.RejectChanges( );

}

}

workTable.AcceptChanges( );

・DataTable イベントの使用

DataTable オブジェクトは、アプリケーションが処理出来る一連のイベントを提供する。DataTable イ

ベントの説明を次の表に示す。

イベント 説明

ColumnChanged 値が列に正常に挿入された時に発生する。

ColumnChanging 列に対して値が提示された時に発生する。

RowChanged テーブル内の行が正常に編集された後に発生する。

RowChanging テーブル内の行が変更される時に発生する。

RowDeleted テーブル内の行が Deleted とマークされた後に発生する。

RowDeleting テーブル内の行が Deleted と仕てマークされる前に発生する。

4 つのイベント OnColumnChanged、OnColumnChanging、OnRowChanged、及び、OnRowChanging

を作成する例を次に示す。此等の各イベントは、列や行が変更される時に発生する。

Visual Basic

AddHandler workTable.ColumnChanged, New _

DataColumnChangeEventHandler(AddressOf OnColumnChanged)

AddHandler workTable.ColumnChanging, New _

DataColumnChangeEventHandler(AddressOf OnColumnChanging)

AddHandler workTable.RowChanged, New _

DataRowChangeEventHandler(AddressOf OnRowChanged)

AddHandler workTable.RowChanging, New _

DataRowChangeEventHandler(AddressOf OnRowChanging)

Private Shared Sub OnColumnChanged(sender As Object, args As DataColumnChangeEventargs)

Console.Write(" ColumnChanged: ")

Console.Write(args.Column.ColumnName & " changed to '" & _

args.ProposedValue.ToString( ) & "'" & vbCrLf)

End Sub

Private Shared Sub OnColumnChanging(sender As Object, args As DataColumnChangeEventargs)

Console.Write("ColumnChanging: ")

Console.Write(args.Column.ColumnName & " equals '" & _

args.Row(args.Column).ToString( ) & _

"', changing to '" & args.ProposedValue.ToString( ) & "'" & vbCrLf)

End Sub

Private Shared Sub OnRowChanging(sender As Object, args As DataRowChangeEventargs)

Page 59: データセット - xdomainjunko036.html.xdomain.jp/pdf/database/DataSet.pdfVS 2005 資料 【電脳梁山泊 烏賊塾】 -3- EndInit フォーム又は別のコンポーネントで使用するDataSetの初期化を終了する(初

VS 2005 資料 【電脳梁山泊 烏賊塾】

-59-

If args.Action <> DataRowAction.Nothing Then

Dim actionStr As String

actionStr = System.Enum.GetName(args.Action.GetType( ), args.Action)

Console.WriteLine(" RowChanging: Action = " & actionStr & ", _

CustID = " & args.Row("CustID").ToString( ))

End If

End Sub

Private Shared Sub OnRowChanged(sender As Object, args As DataRowChangeEventargs)

If args.Action <> DataRowAction.Nothing Then

Dim actionStr As String

actionStr = System.Enum.GetName(args.Action.GetType( ), args.Action)

Console.WriteLine("RowChanged: Action = " & actionStr & ", _

CustID = " & args.Row("CustID").ToString( ))

End If

End Sub

C#

workTable.ColumnChanged+= new

DataColumnChangeEventHandler(OnColumnChanged);

workTable.ColumnChanging += new

DataColumnChangeEventHandler(OnColumnChanging);

workTable.RowChanged += new DataRowChangeEventHandler(OnRowChanged);

workTable.RowChanging += new DataRowChangeEventHandler(OnRowChanging); protected static void OnColumnChanged(object sender, DataColumnChangeEventArgs args)

{

Console.Write(" ColumnChanged: ");

Console.Write(args.Column.ColumnName + " changed to '" + args.ProposedValue + "'¥n");

} protected static void OnColumnChanging(object sender, DataColumnChangeEventArgs args)

{

Console.Write("ColumnChanging: ");

Console.Write(args.Column.ColumnName + " equals '" +

args.Row[args.Column] + "', changing to '" + args.ProposedValue + "'¥n");

}

protected static void OnRowChanging(object sender, DataRowChangeEventArgs args)

{

if (args.Action != DataRowAction.Nothing)

Console.WriteLine(" RowChanging: Action = " + args.Action + ",

CustID = " + args.Row["CustID"]);

} protected static void OnRowChanged(object sender, DataRowChangeEventArgs args)

{

if (args.Action != DataRowAction.Nothing)

Console.WriteLine("RowChanged: Action = " + args.Action + ",

CustID = " + args.Row["CustID"]);

}

■ DataView の作成と使用

DataView では、DataTable に格納されて居るデータの様々なビューを作成出来る。此の機能は、デー

タ連結アプリケーションで頻繁に使用される。DataView を使用すると、様々な並替順序を使用してテ

ーブルのデータを公開したり、行の状態やフィルタ式に基づいてデータをフィルタ処理したり出来る。

Page 60: データセット - xdomainjunko036.html.xdomain.jp/pdf/database/DataSet.pdfVS 2005 資料 【電脳梁山泊 烏賊塾】 -3- EndInit フォーム又は別のコンポーネントで使用するDataSetの初期化を終了する(初

VS 2005 資料 【電脳梁山泊 烏賊塾】

-60-

DataView では、基に成る DataTable のデータの動的ビューが作成される。ビューの内容、順序、メン

バシップには、変更が反映される。此れは、DataTable の Select メソッドとは異なる。此のメソッドで

は、特定のフィルタや並替順序毎にテーブルから DataRow 配列が戻される。戻される配列の内容には、

基に成るテーブルの変更内容が反映されて居るが、メンバシップと順序は静的で有る。DataView は動

的機能を備えて居る為、データ連結アプリケーションに取って理想的なオブジェクトで有る

DataView は、1 つのデータセットの動的ビューで有るデータベースのビューと同様に、此の動的ビュ

ーには、様々な並替順序やフィルタ処理条件を適用出来る。但し、データベースビューとは異なり、

DataView は、テーブルと仕ては処理出来ず、結合テーブルのビューも作成出来ない。亦、ソーステー

ブルの既存の列を除外したり、ソーステーブルにない列(計算列等)を追加したり出来ない。

DataSet の総てのテーブルのビュー設定を管理するには、DataViewManager を使用する。

DataViewManager を使用すると、各テーブルの既定のビュー設定を簡単に管理出来る。DataSet の複

数のテーブルにコントロールを連結する最適な方法は、DataViewManager に連結する方法で有る。

・DataView の作成

DataView は 2 通りの方法で作成出来る。DataView コンストラクタを使用するか、又は、DataTable

の DefaultView プロパティへの参照を作成する。空の DataView コンストラクタを使用出来る。亦、

DataView コンストラクタでは、DataTable を 1 つの引数と仕て取るか、又は、フィルタ条件、並替条

件、及び、行状態フィルタと共に DataTable を使用する。DataView で使用出来る其の他の引数に付い

ては、「DataView を使用したデータの並替とフィルタ処理」を参照され度い。

DataView のインデックスが作成されるのは、DataView が作成される時点と、Sort、RowFilter、又は

RowStateFilter の各プロパティが変更される時点で有る為、DataView の作成時に初期の並替順序や初

期フィルタ条件をコンストラクタ引数と仕て指定すると、パフォーマンスを最大限に引き出す事が出来

る。並替条件やフィルタ条件を指定せずに DataView を作成してから、Sort、RowFilter、又は

RowStateFilter の各プロパティを設定すると、インデックスが少なくとも 2 回作成される。此れは、

DataView の作成時点と、並替プロパティやフィルタプロパティの変更時で有る。

引数を取らないコンストラクタを使用して DataView を作成すると、Table プロパティを設定して居な

い間は、DataView が使用出来る。

DataView コンストラクタを使用して DataView を作成するコード例を次に示す。DataTable と共に

RowFilter、Sort 列、及び、DataViewRowState が指定されて居る。

Visual Basic

Dim custDV As DataView = New DataView(custDS.Tables("Customers"), _

"Country = 'USA'", "ContactName", DataViewRowState.CurrentRows)

C#

DataView custDV = new DataView(custDS.Tables["Customers"],

"Country = 'USA'", "ContactName", DataViewRowState.CurrentRows);

テーブルの DefaultView プロパティを使用して DataTable の既定の DataView への参照を取得するコ

ード例を次に示す。

Visual Basic

Dim custDV As DataView = custDS.Tables("Customers").DefaultView

C#

DataView custDV = custDS.Tables["Customers"].DefaultView;

Page 61: データセット - xdomainjunko036.html.xdomain.jp/pdf/database/DataSet.pdfVS 2005 資料 【電脳梁山泊 烏賊塾】 -3- EndInit フォーム又は別のコンポーネントで使用するDataSetの初期化を終了する(初

VS 2005 資料 【電脳梁山泊 烏賊塾】

-61-

・DataView を使用したデータの並替とフィルタ処理

DataView には、DataTable のデータの並替とフィルタ処理を行う様々な方法が用意されて居る。

・Sort プロパティを使用すれば、1 列、又は、複数列の並替順序を指定し、ASC(昇順)パラメータと

DESC(降順)パラメータを含める事が出来る。 ・ApplyDefaultSort プロパティを使用すると、テーブルの主キー列(1 列、又は、複数列)に基づいて

昇順の並替順序を自動的に作成出来る。Sort プロパティが null 参照か空の文字列の場合、及び、テ

ーブルに主キーが定義されて居る場合は、ApplyDefaultSort 丈が適用される。 ・RowFilter プロパティを使用すると、列の値に基づいて行のサブセットを指定出来る。RowFilter プ

ロパティの有効な式の詳細に付いては、DataColumn クラスの Expression プロパティの情報を参照

され度い。

データサブセットの動的ビューの作成とは対照的に、データに対して特定のクエリの実行結果を返す

場合、パフォーマンスを最大限に引き出すには、RowFilter プロパティを設定する代わりに DataView

の Find メソッドや FindRows メソッドを使用する。RowFilter プロパティを設定すると、データの

インデックスが再作成され、アプリケーションのオーバーヘッドが増加してパフォーマンスの低下を

招く。RowFilter プロパティは、データ連結アプリケーションでの使用に適して居る。此のアプリケ

ーションでは、連結されたコントロールに依ってフィルタ処理結果が表示される。Find メソッドと

FindRows メソッドでは、現在のインデックスが使用される。此の為、インデックスを再作成する必

要は無い。Find メソッドと FindRows メソッドの詳細に付いては、「DataView の検索」を参照され

度い。 ・RowStateFilter プロパティを使用して、表示する行バージョンを指定出来る。DataView は、基に成

る行の RowState に従って、暗黙的に行バージョンを公開する。例えば、RowStateFilter が

DataViewRowState.Deleted に設定されて居る場合、DataView は行バージョンが Original の

Deleted 行を総て公開する。此れは、Current 行バージョンが存在しない為で有る DataRowView の

RowVersion プロパティを使用すると、公開される行のバージョンを確認出来る。

DataViewRowState のオプションを次の表に示す。

DataViewRowState のオプション 説明

CurrentRows Current 行バージョンの総ての Unchanged 行、Added 行、及び、Modified 行で有る(既定値)。

Added Current 行バージョンの総ての Added 行で有る。

Deleted Original 行バージョンの総ての Deleted 行で有る。

ModifiedCurrent Current 行バージョンの総ての Modified 行で有る。

ModifiedOriginal Original 行バージョンの総ての Modified 行で有る。

None 行が無い。

OriginalRows Original 行バージョンの総ての Unchanged 行、Modified 行、及び、Deleted 行で有る。

Unchanged Current 行バージョンの総ての Unchanged 行で有る。

行状態と行バージョンの詳細に付いては、「行の状態とバージョン」を参照され度い。

在庫数が標準在庫数以下で有る製品を、仕入先 ID(supplier ID)で並べ替え、更に製品名(product name)

で並べ替えたビューを作成するコード例を次に示す。

Visual Basic

Dim prodView As DataView = New DataView(prodDS.Tables("Products"), _ "UnitsInStock <= ReorderLevel", "SupplierID, ProductName", DataViewRowState.CurrentRows)

C#

DataView prodView = new DataView(prodDS.Tables["Products"], "UnitsInStock <= ReorderLevel", "SupplierID, ProductName", DataViewRowState.CurrentRows);

Page 62: データセット - xdomainjunko036.html.xdomain.jp/pdf/database/DataSet.pdfVS 2005 資料 【電脳梁山泊 烏賊塾】 -3- EndInit フォーム又は別のコンポーネントで使用するDataSetの初期化を終了する(初

VS 2005 資料 【電脳梁山泊 烏賊塾】

-62-

・DataView を使用したデータの表示

DataView は、一般にデータ連結アプリケーションで使用される。データ連結アプリケーションでは、

基に成るテーブルの内容がコントロールに依ってビューと仕て公開される。以降の資料では、DataView

の内容をカスタムコントロールに対して公開する方法、データ連結アプリケーション以外のアプリケー

ションで公開する方法、詰まり、DataView で特定の値を検索する方法に付いて説明する。亦、親子の

リレーションシップから子データのビューを作成する方法に付いて説明する。

DataView は、DataRowView オブジェクトの列挙可能なコレクションを公開する。DataRowView オ

ブジェクトは、基に成るテーブルの列の名前や列の序数参照に依ってインデックスが設定されて居るオ

ブジェクトの配列と仕て値を公開する。DataRowView が DataRowView の Row プロパティを使用して

公開して居る DataRow にアクセス出来る。

DataRowViewを使用して値を表示して居る場合は、DataViewのRowStateFilterプロパティに依って、

基に成る DataRow から公開される行バージョンが決まる。DataRow を使用して様々な行バージョン

にアクセスする方法に付いては、「行の状態とバージョン」を参照され度い。

テーブルの現在の値と元の値を総て表示するコード例を次に示す。

Visual Basic

Dim catView As DataView = New DataView(catDS.Tables("Categories"))

Console.WriteLine("Current Values:")

WriteView(catView)

Console.WriteLine("Original Values:")

catView.RowStateFilter = DataViewRowState.ModifiedOriginal

WriteView(catView) Public Shared Sub WriteView(thisDataView As DataView)

Dim rowView As DataRowView

Dim i As Integer

For Each rowView In thisDataView

For i = 0 To thisDataView.Table.Columns.Count - 1

Console.Write(rowView(i) & vbTab)

Next

Console.WriteLine( )

Next

End Sub

C#

DataView catView = new DataView(catDS.Tables["Categories"]);

Console.WriteLine("Current Values:");

WriteView(catView);

Console.WriteLine("Original Values:");

catView.RowStateFilter = DataViewRowState.ModifiedOriginal;

WriteView(catView); public static void WriteView(DataView thisDataView)

{

foreach (DataRowView rowView in thisDataView)

{

for (int i = 0; i < thisDataView.Table.Columns.Count; i++)

Console.Write(rowView[i] + "¥t");

Console.WriteLine( );

}

}

Page 63: データセット - xdomainjunko036.html.xdomain.jp/pdf/database/DataSet.pdfVS 2005 資料 【電脳梁山泊 烏賊塾】 -3- EndInit フォーム又は別のコンポーネントで使用するDataSetの初期化を終了する(初

VS 2005 資料 【電脳梁山泊 烏賊塾】

-63-

DataView の検索

DataView の Find メソッドと FindRows メソッドを使用すると、並替キーの値に基づいて行を検索出

来る。Find メソッドと FindRows メソッドに依る検索で、値の大文字と小文字が区別されるか何うか

は、基に成る DataTable の CaseSensitive プロパティに依って決まる。検索結果を返すには、検索値が

既存の並替キーの値と完全に一致して居る必要が有る。

Find メソッドは、検索条件に一致する DataRowView のインデックスの整数値を返す。複数の行が検

索条件に一致する場合は、一致した最初の DataRowView が返される。一致する DataRowView が無い

場合には、Find は-1 を返す。

複数の行に一致する検索結果を返すには、FindRows メソッドを使用する。FindRows は Find メソッ

ドと同様に機能するが、DataView 内で条件に一致する総ての行を参照する DataRowView 配列を返す

点が Find メソッドとは異なる。一致する行が見付からない場合、DataRowView 配列は空に成る。

Find メソッド、又は、FindRows メソッドを使用するには、並替順序を指定する必要が有る。並替順序

を指定するには、ApplyDefaultSort を true に設定するか、又は、Sort プロパティを使用する。並替順

序が指定されないと、例外がスローされる。

Find メソッドと FindRows メソッドには、並替順序に指定されて居る列の数と長さが一致する値配列

を入力と仕て渡す。1 つの列に基づく並替の場合は、1 つの値を渡す。複数列に基づく並替の場合は、

オブジェクトの配列を渡す。複数列に基づく並替では、オブジェクト配列の値の順序が、DataView の

Sort プロパティに指定されて居る列の順序と一致する必要が有る。

1 列の並替順序が設定されて居る DataView に対して Find メソッドを呼び出すコード例を次に示す。

Visual Basic

Dim custView As DataView = _

New DataView(custDS.Tables("Customers"), "", _

"CompanyName", DataViewRowState.CurrentRows)

Dim rowIndex As Integer = custView.Find("The Cracker Box")

If rowIndex = -1 Then

Console.WriteLine("No match found.")

Else

Console.WriteLine("{0}, {1}", _

custView(rowIndex)("CustomerID").ToString( ), _

custView(rowIndex)("CompanyName").ToString( ))

End If

C#

DataView custView = new DataView(custDS.Tables["Customers"], "",

"CompanyName", DataViewRowState.CurrentRows);

int rowIndex = custView.Find("The Cracker Box");

if (rowIndex == -1)

Console.WriteLine("No match found.");

else

Console.WriteLine("{0}, {1}",

custView[rowIndex]["CustomerID"].ToString( ),

custView[rowIndex]["CompanyName"].ToString( ));

Page 64: データセット - xdomainjunko036.html.xdomain.jp/pdf/database/DataSet.pdfVS 2005 資料 【電脳梁山泊 烏賊塾】 -3- EndInit フォーム又は別のコンポーネントで使用するDataSetの初期化を終了する(初

VS 2005 資料 【電脳梁山泊 烏賊塾】

-64-

Sort プロパティで複数の列が指定される場合は、次のコード例に示す様に、各列に対応する検索値を

Sort プロパティで指定されて居る順序で格納したオブジェクト配列を渡す必要が有る。

Visual Basic

Dim custView As DataView = _

New DataView(custDS.Tables("Customers"), "", _

"CompanyName, ContactName", DataViewRowState.CurrentRows)

Dim foundRows( ) As DataRowView = _

custView.FindRows(New object( ) {"The Cracker Box", "Liu Wong"})

If foundRows.Length = 0 Then

Console.WriteLine("No match found.")

Else

Dim myDRV As DataRowView

For Each myDRV In foundRows

Console.WriteLine("{0}, {1}", _

myDRV("CompanyName").ToString( ), myDRV("ContactName").ToString( ))

Next

End If

C#

DataView custView = new DataView(custDS.Tables["Customers"], "",

"CompanyName, ContactName", DataViewRowState.CurrentRows);

DataRowView[] foundRows =

custView.FindRows(new object[] {"The Cracker Box", "Liu Wong"});

if (foundRows.Length == 0)

Console.WriteLine("No match found.");

else

foreach (DataRowView myDRV in foundRows)

Console.WriteLine("{0}, {1}", myDRV["CompanyName"].ToString( ),

myDRV["ContactName"].ToString( ));

DataView を使用したリレーションシップ間の移動

DataSet 内のテーブル間にリレーションシップが存在する場合は、此のリレーションシップの子テーブ

ルの行が含まれて居る DataView を作成出来る。此の様な DataView を作成するには、親テーブルの行

に対して DataRowView の CreateChildView メソッドを使用する。例えば、次のコードは、

CategoryName と ProductName に依ってデータをアルファベット順に並べ替えられた Categories と

此のテーブルに関連する Products を表示す。

Visual Basic

Dim catTable As DataTable = catDS.Tables("Categories")

Dim prodTable As DataTable = catDS.Tables("Products")

' Create a relation between the Categories and Products tables.

Dim relation As DataRelation = catDS.Relations.Add("CatProdRel", _

catTable.Columns("CategoryID"), prodTable.Columns("CategoryID"))

' Create DataViews for the Categories and Products tables.

Dim catView As DataView = New DataView(catTable, "", _

"CategoryName", DataViewRowState.CurrentRows)

Page 65: データセット - xdomainjunko036.html.xdomain.jp/pdf/database/DataSet.pdfVS 2005 資料 【電脳梁山泊 烏賊塾】 -3- EndInit フォーム又は別のコンポーネントで使用するDataSetの初期化を終了する(初

VS 2005 資料 【電脳梁山泊 烏賊塾】

-65-

Dim prodView As DataView

' Iterate through the Categories table.

Dim catDRV, prodDRV As DataRowView For Each catDRV In catView

Console.WriteLine(catDRV("CategoryName"))

' Create a DataView of the child product records.

prodView = catDRV.CreateChildView(relation)

prodView.Sort = "ProductName"

For Each prodDRV In prodView

Console.WriteLine(vbTab & prodDRV("ProductName"))

Next

Next

C#

DataTable catTable = catDS.Tables["Categories"];

DataTable prodTable = catDS.Tables["Products"]; // Create a relation between the Categories and Products tables.

DataRelation relation = catDS.Relations.Add("CatProdRel",

catTable.Columns["CategoryID"], prodTable.Columns["CategoryID"]); // Create DataViews for the Categories and Products tables.

DataView catView = new DataView(catTable, "", "CategoryName",

DataViewRowState.CurrentRows);

DataView prodView; // Iterate through the Categories table.

foreach (DataRowView catDRV in catView)

{

Console.WriteLine(catDRV["CategoryName"]);

// Create a DataView of the child product records.

prodView = catDRV.CreateChildView(relation);

prodView.Sort = "ProductName";

foreach (DataRowView prodDRV in prodView)

Console.WriteLine("¥t" + prodDRV["ProductName"]);

}

・DataView を使用したデータの変更

DataView を使用して、データ行を基に成るテーブルに追加、削除、又は、変更出来る。基に成るテー

ブルのデータを DataView で変更出来るか何うかは、DataView の 3 つのブール値プロパティで制御さ

れる。此の 3 つのプロパティとは、AllowNew、AllowEdit、AllowDelete で有る。此等のプロパティの

既定値は true で有る。

AllowNew が true の場合は、DataView の AddNew メソッドを使用して DataRowView を新規に作成

出来る。DataRowView の EndEdit メソッドが呼び出される迄は、新規に作成された行は基に成る

DataTable に追加されない。DataRowView の CancelEdit メソッドが呼び出されると、新規に作成さ

れた行は破棄される。一度に編集出来るのは、1 つの DataRowView 丈で有る。保留中の行が有る場合

は、DataRowView の AddNew メソッドや BeginEdit メソッドを呼び出すと、保留中の行に対して

EndEdit が暗黙的に呼び出される。EndEdit が呼び出されると、基に成る DataTable に対して変更が

適用される。適用された変更をコミットするには DataTable、DataSet、又は、DataRow の各オブジェ

クトの AcceptChanges メソッドを使用し、拒否するには此等のオブジェクトの RejectChanges メソッ

ドを使用する。AllowNew が false の場合は、DataRowView の AddNew メソッドを呼び出すと例外が

スローされる。

Page 66: データセット - xdomainjunko036.html.xdomain.jp/pdf/database/DataSet.pdfVS 2005 資料 【電脳梁山泊 烏賊塾】 -3- EndInit フォーム又は別のコンポーネントで使用するDataSetの初期化を終了する(初

VS 2005 資料 【電脳梁山泊 烏賊塾】

-66-

AllowEdit が true の場合は、DataRowView を使用すると DataRow の内容を変更出来る。基に成る行

の変更内容を確定するには DataRowView.EndEdit を使用し、変更内容を取り消すには

DataRowView.CancelEditを使用する。一度に編集出来るのは1行丈で有る。保留中の行が有る場合は、

DataRowView の AddNew メソッドや BeginEdit メソッドを呼び出すと、保留中の行に対して EndEdit

が暗黙的に呼び出される。EndEdit が呼び出されると、基に成る DataRow の Current 行バージョンに

対して変更が適用される。適用された変更をコミットするには DataTable、DataSet、又は、DataRow

の各オブジェクトの AcceptChanges メソッドを使用し、拒否するには此等のオブジェクトの

RejectChanges メソッドを使用する。AllowEdit が false の場合は、DataRowView の値を変更しよう

とすると例外がスローされる。

既存の DataRowView の編集中でも、未だ確定されて居ない変更に関して、基に成る DataTable のイベ

ントが発生する場合が有る。DataRowView に対して EndEdit と CancelEdit の孰れが呼び出されて居

るかに関係なく、基に成る DataRow に対して EndEdit を呼び出すと、確定されて居ない変更が適用さ

れ、CancelEdit を呼び出すと、確定されて居ない変更が取り消される。

AllowDelete が true の場合は、DataView オブジェクト、又は、DataRowView オブジェクトの Delete

メソッドを使用して DataView の行を削除出来る。DataView の行を削除すると、基に成る DataTable

から行が削除される。後で此の削除操作をコミットするには AcceptChanges を使用し、拒否するには

RejectChanges を使用する。AllowDelete が false の場合は、DataView、又は、DataRowView の Delete

メソッドを呼び出すと例外がスローされる。

次のコード例は、DataView を使用して行を削除する機能を無効にし、DataView を使用して基に成る

テーブルに新しい行を追加する。

Visual Basic

Dim custTable As DataTable = custDS.Tables("Customers")

Dim custView As DataView = custTable.DefaultView

custView.Sort = "CompanyName"

custView.AllowDelete = False Dim newDRV As DataRowView = custView.AddNew( )

newDRV("CustomerID") = "ABCDE"

newDRV("CompanyName") = "ABC Products"

newDRV.EndEdit( )

C#

DataTable custTable = custDS.Tables["Customers"];

DataView custView = custTable.DefaultView;

custView.Sort = "CompanyName"; custView.AllowDelete = false;

DataRowView newDRV = custView.AddNew( );

newDRV["CustomerID"] = "ABCDE";

newDRV["CompanyName"] = "ABC Products";

newDRV.EndEdit( );

・DataView イベントの操作

DataView の ListChanged イベントを使用して、ビューが更新されて居るか何うかを確認出来る。基に

成るテーブルの行の追加、削除、又は、変更や、此のスキーマの列の追加や削除、親子のリレーション

シップの変更等、此等の更新を行うと此のイベントが発生する。更に、現在表示されて居る行のリスト

が新しい並替順序やフィルタの適用に依り大幅に変更された場合、ListChanged イベントは其の事も通

知する。

Page 67: データセット - xdomainjunko036.html.xdomain.jp/pdf/database/DataSet.pdfVS 2005 資料 【電脳梁山泊 烏賊塾】 -3- EndInit フォーム又は別のコンポーネントで使用するDataSetの初期化を終了する(初

VS 2005 資料 【電脳梁山泊 烏賊塾】

-67-

ListChanged イベントは、System.ComponentModel 名前空間の ListChangedEventHandler デリゲー

トを実装し、ListChangedEventArgs オブジェクトを入力と仕て受け取る。発生した変更の内容を確認

するには、ListChangedEventArgs オブジェクトの ListChangedType プロパティの ListChangedType

列挙値を使用する。行の追加、削除、又は、移動に依る変更の場合、追加された行や移動された行の新

しいインデックスと削除された行の古いインデックスには、ListChangedEventArgs オブジェクトの

NewIndex プロパティを使用してアクセス出来る。移動された行の場合、移動前の古いインデックスに

アクセスするには ListChangedEventArgs オブジェクトの OldIndex プロパティを使用する。

DataViewManager は、更にテーブルが追加や削除された場合に、又は、基に成る DataSet の Relations

コレクションが変更された場合に、其の事を通知する為に ListChanged イベントを公開する。

ListChanged イベントハンドラを追加する方法を次のコード例に示す。

Visual Basic

AddHandler custView.ListChanged, _

New System.ComponentModel.ListChangedEventHandler( _

AddressOf OnListChanged)

Private Shared Sub OnListChanged( _

sender As Object, args As System.ComponentModel.ListChangedEventArgs)

Console.WriteLine("ListChanged:")

Console.WriteLine(vbTab & "Type = " & _

System.Enum.GetName(args.ListChangedType.GetType( ), args.ListChangedType))

Console.WriteLine(vbTab & "OldIndex = " & args.OldIndex)

Console.WriteLine(vbTab & "NewIndex = " & args.NewIndex)

End Sub

C#

custView.ListChanged+= new

System.ComponentModel.ListChangedEventHandler(OnListChanged);

protected static void OnListChanged(object sender,

System.ComponentModel.ListChangedEventArgs args)

{

Console.WriteLine("ListChanged:");

Console.WriteLine("¥tType = " + args.ListChangedType);

Console.WriteLine("¥tOldIndex = " + args.OldIndex);

Console.WriteLine("¥tNewIndex = " + args.NewIndex);

}

・DataViewManager を使用した既定のテーブルビューの設定

DataView の総てのテーブルのビュー設定を管理するには、DataViewManager を使用する。リレーシ

ョンシップを移動するグリッド等の様に、1 つのコントロールを複数のテーブルに連結する場合は、

DataViewManager が適して居る。

DataViewManager には、DataSet のテーブルのビュー設定に使用される DataViewSetting オブジェ

クトのコレクションが含まれて居る。DataViewSettingCollection には、DataSet の各テーブルに対応

するDataViewSettingオブジェクトが1つ宛含まれて居る。参照テーブルの既定のApplyDefaultSort、

Sort、RowFilter、RowStateFilter の各プロパティを設定するには、DataViewSetting を使用する。名

前や序数参照に依って、又は、参照を其の特定のテーブルオブジェクトに渡す事に依って、特定のテー

ブルの DataViewSetting を参照出来る。DataViewManager の DataViewSetting オブジェクトのコレ

クションにアクセスするには、DataViewSettings プロパティを使用する。

Page 68: データセット - xdomainjunko036.html.xdomain.jp/pdf/database/DataSet.pdfVS 2005 資料 【電脳梁山泊 烏賊塾】 -3- EndInit フォーム又は別のコンポーネントで使用するDataSetの初期化を終了する(初

VS 2005 資料 【電脳梁山泊 烏賊塾】

-68-

DataSet に、SQL Server Northwind データベースの Customers、Orders、Order Details の各テーブ

ルを格納し、テーブル間のリレーションシップを作成し、DataViewManager を使用して既定の

DataView 設定を設定し、DataGrid を DataViewManager に連結するコード例を次に示す。此の例で

は DataSet の総てのテーブルを対象とした既定の DataView 設定が設定される。此の設定では、テーブ

ルの主キーに依ってテーブルの内容が並べ替えられ(ApplyDefaultSort = true)、次に Customers テー

ブルの並替順序が、CompanyName に依る並替順序に変更される。

Visual Basic

' Assumes connection is a valid SqlConnection to Northwind.

' Create a Connection, DataAdapters, and a DataSet.

Dim custDA As SqlDataAdapter = New SqlDataAdapter( _

"SELECT CustomerID, CompanyName FROM Customers", connection)

Dim orderDA As SqlDataAdapter = New SqlDataAdapter( _

"SELECT OrderID, CustomerID FROM Orders", connection)

Dim ordDetDA As SqlDataAdapter = New SqlDataAdapter( _

"SELECT OrderID, ProductID, Quantity FROM [Order Details]", connection)

Dim custDS As DataSet = New DataSet( )

' Open the Connection.

connection.Open( )

' Fill the DataSet with schema information and data.

custDA.MissingSchemaAction = MissingSchemaAction.AddWithKey

orderDA.MissingSchemaAction = MissingSchemaAction.AddWithKey

ordDetDA.MissingSchemaAction = MissingSchemaAction.AddWithKey

custDA.Fill(custDS, "Customers")

orderDA.Fill(custDS, "Orders")

ordDetDA.Fill(custDS, "OrderDetails")

' Close the Connection.

connection.Close( )

' Create relationships.

custDS.Relations.Add("CustomerOrders", _

custDS.Tables("Customers").Columns("CustomerID"), _

custDS.Tables("Orders").Columns("CustomerID"))

custDS.Relations.Add("OrderDetails", _

custDS.Tables("Orders").Columns("OrderID"), _

custDS.Tables("OrderDetails").Columns("OrderID"))

' Create default DataView settings.

Dim viewManager As DataViewManager = New DataViewManager(custDS)

Dim viewSetting As DataViewSetting

For Each viewSetting In viewManager.DataViewSettings

viewSetting.ApplyDefaultSort = True

Next

viewManager.DataViewSettings("Customers").Sort = "CompanyName"

' Bind to a DataGrid.

Page 69: データセット - xdomainjunko036.html.xdomain.jp/pdf/database/DataSet.pdfVS 2005 資料 【電脳梁山泊 烏賊塾】 -3- EndInit フォーム又は別のコンポーネントで使用するDataSetの初期化を終了する(初

VS 2005 資料 【電脳梁山泊 烏賊塾】

-69-

Dim grid As System.Windows.Forms.DataGrid = New System.Windows.Forms.DataGrid( )

grid.SetDataBinding(viewManager, "Customers")

C#

// Assumes connection is a valid SqlConnection to Northwind.

// Create a Connection, DataAdapters, and a DataSet.

SqlDataAdapter custDA = new SqlDataAdapter(

"SELECT CustomerID, CompanyName FROM Customers", connection);

SqlDataAdapter orderDA = new SqlDataAdapter(

"SELECT OrderID, CustomerID FROM Orders", connection);

SqlDataAdapter ordDetDA = new SqlDataAdapter(

"SELECT OrderID, ProductID, Quantity FROM [Order Details]", connection);

DataSet custDS = new DataSet( );

// Open the Connection.

connection.Open( );

// Fill the DataSet with schema information and data.

custDA.MissingSchemaAction = MissingSchemaAction.AddWithKey;

orderDA.MissingSchemaAction = MissingSchemaAction.AddWithKey;

ordDetDA.MissingSchemaAction = MissingSchemaAction.AddWithKey;

custDA.Fill(custDS, "Customers");

orderDA.Fill(custDS, "Orders");

ordDetDA.Fill(custDS, "OrderDetails");

// Close the Connection.

connection.Close( );

// Create relationships.

custDS.Relations.Add("CustomerOrders",

custDS.Tables["Customers"].Columns["CustomerID"],

custDS.Tables["Orders"].Columns["CustomerID"]);

custDS.Relations.Add("OrderDetails",

custDS.Tables["Orders"].Columns["OrderID"],

custDS.Tables["OrderDetails"].Columns["OrderID"]);

// Create default DataView settings.

DataViewManager viewManager = new DataViewManager(custDS);

foreach (DataViewSetting viewSetting in viewManager.DataViewSettings)

viewSetting.ApplyDefaultSort = true;

viewManager.DataViewSettings["Customers"].Sort = "CompanyName";

// Bind to a DataGrid.

System.Windows.Forms.DataGrid grid = new System.Windows.Forms.DataGrid( );

grid.SetDataBinding(viewManager, "Customers");