DataAdapter からの DataSet の読み込み (ADO.NET)

更新 : November 2007

ADO.NET の DataSet は、データ ソースに依存しない一貫したリレーショナル プログラミング モデルを提供するメモリ常駐型のデータ表現です。DataSet はテーブル、制約、およびテーブル間のリレーションシップを含む完全なデータのセットを表します。DataSet はデータ ソースとは独立しているため、DataSet にはそのアプリケーションに固有のデータと複数のデータ ソースからのデータを含めることができます。既存のデータ ソースとの対話は DataAdapter によって制御されます。

DataAdapter の SelectCommand プロパティは、データ ソースからデータを取得する Command オブジェクトです。DataAdapter の InsertCommand、UpdateCommand、DeleteCommand の各プロパティは、DataSet のデータに対して行われた変更に基づいてデータ ソースのデータ更新を管理する Command オブジェクトです。これらのプロパティについては、「DataAdapter によるデータ ソースの更新 (ADO.NET)」でさらに詳しく説明します。

DataAdapter の Fill メソッドは、DataAdapter の SelectCommand の結果を使用して DataSet を設定するために使用します。Fill は、その引数として、設定対象である DataSet と、DataTable オブジェクト (つまり、SelectCommand から返された行を格納する DataTable の名前) を受け取ります。

bh8kx08z.alert_note(ja-jp,VS.90).gifメモ :

DataAdapter を使用してテーブル全体を取得すると、特にテーブルの行数が多い場合は処理に時間がかかります。データベースにアクセスし、データを検索して処理した後、そのデータをクライアントに転送するという時間のかかる処理が伴うためです。また、テーブル全体をクライアントに取得しようとすると、サーバー上ですべての行がロックされます。WHERE 句を使用して、クライアントから返される行数をできるだけ減らすことでパフォーマンスを向上させることができます。また、SELECT ステートメントで必要な列を明示的に指定するだけでもクライアントに返されるデータ量を減らすことができます。それ以外の対策としては、一度に数百行など、行をバッチで取得し、クライアントが現在のバッチの処理を完了した時点で次のバッチを取得する方法も効果的です。

Fill メソッドは、DataReader オブジェクトを暗黙的に使用して DataSet 内でテーブルを作成するための列の名前と型、および DataSet 内のテーブルの行を設定するためのデータを返します。テーブルおよび列は、存在しない場合にのみ作成されます。それ以外の場合、Fill には、既存の DataSet スキーマが使用されます。列の型は、「ADO.NET でのデータ型のマッピング」の表に基づき、.NET Framework の型として作成されます。データ ソースに主キーが存在し、DataAdapter**.MissingSchemaAction が MissingSchemaAction.**AddWithKey に設定されている場合だけ、主キーが作成されますが、それ以外の場合は主キーは作成されません。Fill はテーブルに主キーがあることがわかると、主キー列の値がデータ ソースから返された主キー列の値と一致する行について、データ ソースから返されたデータで DataSet 内のデータを上書きします。主キーが見つからない場合は、DataSet のテーブルの末尾にデータを追加します。Fill は DataSet にデータを読み込むときに存在するすべてのマッピングを使用します (「DataAdapter DataTable と DataColumn のマップ (ADO.NET)」を参照してください)。

bh8kx08z.alert_note(ja-jp,VS.90).gifメモ :

SelectCommand が OUTER JOIN の結果を返す場合、DataAdapter は、生成される DataTable に PrimaryKey 値を設定しません。自分で PrimaryKey を定義して、重複行が正しく解決されるようにする必要があります。詳細については、「主キーの定義 (ADO.NET)」を参照してください。

次のコード サンプルでは、Microsoft SQL Server の Northwind データベースへの SqlConnection を使用する SqlDataAdapter のインスタンスを作成し、DataSet 内の DataTable に顧客リストを読み込みます。SqlDataAdapter コンストラクタに渡される SQL ステートメントおよび SqlConnection 引数は、SqlDataAdapterSelectCommand プロパティを作成するために使用されます。

' 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")
// 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");
bh8kx08z.alert_note(ja-jp,VS.90).gifメモ :

このサンプル コードでは、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 オブジェクトを使用して、各データ ソースとの通信を行うことができます。

次のコード サンプルでは、Microsoft SQL Server 2000 の Northwind データベースおよび Microsoft Access 2000 の Northwind データベースから、それぞれ顧客リストと注文リストを取得します。取得したテーブルを DataRelation で関連付けて、顧客および対応する注文の一覧を表示します。DataRelation オブジェクトの詳細については、「DataRelation の追加 (ADO.NET)」および「DataRelation の移動 (ADO.NET)」を参照してください。

' 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 
// 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"]);
}

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 のイベント処理 (ADO.NET)」を参照してください。SQL Server の decimal 値を取得するために、SqlDataReader オブジェクトを使用し、GetSqlDecimal メソッドを呼び出すこともできます。

ADO.NET 2.0 では、DataSet の System.Data.SqlTypes に対するサポート機能が強化されています。詳細については、「SqlTypes と DataSet (ADO.NET)」を参照してください。

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 内にそのデータを格納します。

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)

Dim customers As DataSet = New DataSet()

adapter.Fill(customers, "Customers")
End Using
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

参照

概念

DbDataAdapter を使用したデータの変更 (ADO.NET)

その他の技術情報

DataAdapter と DataReader (ADO.NET)

ADO.NET でのデータ型のマッピング

複数のアクティブな結果セット (MARS)