• 検索結果がありません。

ファイル操作

N/A
N/A
Protected

Academic year: 2021

シェア "ファイル操作"

Copied!
69
0
0

読み込み中.... (全文を見る)

全文

(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 を呼び出す。

(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 コレクション内のテーブルでの出現順序と同じで有る)。

(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 から継承さ れる。)

(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)

(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.

(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"; }

} }

(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 には、行 に格納された値の変更を識別出来る様に、行の現在の状態と共に、行の現在のバージョンと元のバージ ョンの両方が保持される。

(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 つの列が主キーの列と仕 て設定されて居る。

(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 の使用」を参照され度い。

(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 テーブルからの 値が返された場合に展開された例を次のコード例に示す。

(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"]);

} } }

(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 はテーブルに主キーが有る事が 解ると、主キー列の値がデータソースから返された主キー列の値と一致する行に付いて、データソース

(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 オブジェクトを使用して、各データソースとの通信を行う事が出来る。

(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"]);

(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)

(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 が存在しない場合)は、例外が スローされる。

(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)

(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 では自動インクリメント値と仕て負の数値が生成さ

(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 の主キー 制約に反映される。外部キー制約情報はインクルードされない為、「テーブルへの制約の追加」で示す 様に明示的に作成する必要が有る。

(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 から始まる。

(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 の行の値が使用される。

(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 = ?";

(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#

参照

関連したドキュメント

・今年 1 月より値上げが要請された印刷用紙について、8

スケジュールタスク: StreamFab は登録された YouTube チャンネルから新しく追加されたビデオをダウンロード

WAV/AIFF ファイルから BR シリーズのデータへの変換(Import)において、サンプリング周波 数が 44.1kHz 以外の WAV ファイルが選択されました。.

これらの定義でも分かるように, Impairment に関しては解剖学的または生理学的な異常 としてほぼ続一されているが, disability と

テストが成功しなかった場合、ダイアログボックスが表示され、 Alienware Command Center の推奨設定を確認するように求め

jGrants上にご登録されている内容から自動反

画像の参照時に ACDSee Pro によってファイルがカタログ化され、ファイル プロパティと メタデータが自動的に ACDSee

(採択) 」と「先生が励ましの声をかけてくれなかった(削除) 」 )と判断した項目を削除すること で計 83