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 | Ana Trujillo Emparedados y helados | 1 |
TableName: CustomersOrders
顧客ID | 注文ID | CustomersOrders |
---|---|---|
ALFKI | 10643 | 0 |
ALFKI | 10692 | 0 |
ANATR | 10308 | 1 |
ANATR | 10625 | 1 |