Language

DataAdapter からの DataSet の読み込み

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

SelectCommand の DataAdapter プロパティは、データ ソースからデータを取得する Command オブジェクトです。 InsertCommandの UpdateCommand、 DeleteCommand 、 DataAdapter の各プロパティは、 Command のデータに対して行われた変更に基づいてデータ ソースのデータ更新を管理する DataSetオブジェクトです。 これらのプロパティの詳細については、「 DataAdapters を使用したデータ ソースの更新」を参照してください。

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

注

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

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

注

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

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

例

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

注

このサンプル コードでは、 Connectionの開始と終了を明示的に行っていません。 Fill メソッドは、接続がまだ開いていないことを認識すると Connection が使用している DataAdapter を暗黙的に開きます。 Fill が接続を開いた場合は、Fill の終了時に Fill が接続を終了します。 これにより、 Fill や Updateなどの単一の操作を扱う場合にコードを簡略化できます。 これに対し、開いている接続を必要とする複数の操作を実行する場合は、 Open の Connectionメソッドを明示的に呼び出し、データ ソースに対する操作の実行後に Close の Connectionメソッドを呼び出すことでアプリケーションのパフォーマンスを改善できます。 リソースを解放して他のクライアント アプリケーションが使用できるようにするために、データ ソースへの接続を開いたままにする時間は最小限にすることをお勧めします。

複数の結果セット

DataAdapter は複数の結果セットを検出すると、 DataSetに複数のテーブルを作成します。 これらのテーブルには、Table0 のように、"Table" で始まるインクリメンタル既定名 TableNが割り当てられます。 テーブル名を引数として Fill メソッドに渡すと、TableName0 を表す "TableName" で始まるインクリメンタル既定名 TableNameNが割り当てられます。

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

1 つの DataAdapter で、任意の数の DataSet オブジェクトを使用できます。 それぞれの DataAdapter で 1 つ以上の DataTable オブジェクトにデータを格納し、関連するデータ ソースに更新を反映させることができます。 DataRelation に対して Constraint オブジェクトおよび DataSet オブジェクトを部分的に追加できるため、複数の異なるデータ ソースから取得したデータを関連付けることができます。 たとえば、 DataSet には、Microsoft SQL Server データベースからのデータ、OLE DB を介して公開されている IBM DB2 データベース、および XML をストリーミングするデータ ソースを含めることができます。 1 つ以上の DataAdapter オブジェクトを使用して、各データ ソースとの通信を行うことができます。

例

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

' 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 桁になります。 SqlDataAdapter が動作している間に、 Fill が、SQL Server の decimal フィールドの有効桁数が 28 文字を超えていると判断した場合、現在の行は DataTableに追加されません。 その代わりに FillError イベントが発生し、精度の低下が起こるかどうかを判断し、どのように適切に対応するかを決めることができます。 FillError イベントの詳細については、「DataAdapter イベントの処理」を参照してください。 SQL Server の decimal 値を取得するために、 SqlDataReader オブジェクトを使用し、 GetSqlDecimal メソッドを呼び出すこともできます。

ADO.NET 2.0 では、System.Data.SqlTypesでDataSetのサポートが強化されました。 詳細については、「 SqlTypes and the DataSet」を参照してください。

OLE DB の章

階層行セットまたは章 (OLE DB 型 DBTYPE_HCHAPTER、ADO 型 adChapter) を使用して、 DataSetの内容を入力できます。 OleDbDataAdapter操作中にFillが章付き列を検出すると、その章の列に対してDataTableが作成され、そのテーブルにチャプターの列と行が入力されます。 章付き列に対して作成されたテーブルには、親テーブル名と、"ParentTableNameChapteredColumnName" という形式の章付き列名の両方を使用して名前が付けられます。 DataSetにチャプター列の名前と一致するテーブルが既に存在する場合は、現在のテーブルにチャプター データが入力されます。 章で見つかった列と一致する列が既存のテーブルにない場合は、新しい列が追加されます。

DataSetのテーブルにチャプター列のデータが格納される前に、親テーブルと子テーブルの両方に整数列を追加し、親列を自動インクリメントに設定し、両方のテーブルから追加された列を使用してDataRelationを作成することで、階層行セットの親テーブルと子テーブルの間にリレーションシップが作成されます。 追加されたリレーションの名前は、親テーブルとチャプター列名を使用して "ParentTableNameChapterColumnName" という形式で指定します。

関連する列は、 DataSetにのみ存在します。 データ ソースからの後続の入力によって、変更が既存の行にマージされるのではなく、新しい行がテーブルに追加される可能性があります。

また、DataAdapter.Fillを受け取るDataTableオーバーロードを使用すると、データが入るのはそのテーブルのみであることに注意してください。 自動インクリメント整数列は引き続きテーブルに追加されますが、子テーブルは作成または塗りつぶされません。また、リレーションシップは作成されません。

次の例では、MSDataShape プロバイダーを使用して、顧客の一覧で各顧客の注文の章列を生成します。 その後、 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 テーブルに追加されます。 Orders テーブルのCustomers列は自動インクリメントに設定されます。 親テーブルである DataRelationテーブルに追加された列を使用して、 CustomersOrdersという Customers が作成されます。 次の表に、いくつかのサンプル結果を示します。

テーブル名: 顧客

顧客ID カンパニーネーム 注文
ALFKI アルフレッドス・フターキステ 0
ANATR アナ・トルヒーリョのサンドイッチとアイスクリーム 1

TableName: 顧客注文

顧客ID 注文ID 顧客注文
ALFKI 10643 0
ALFKI 10692 0
ANATR 10308 1
ANATR 10625 1

こちらも参照ください