DataAdapter を使用したバッチ操作

適用対象: .NET Framework .NET .NET Standard

ADO.NET のダウンロード

ADO でのバッチサポート.NETではDataAdapterは、一度に 1 つの操作を送信するのではなく、INSERTまたはUPDATEからサーバーにDELETE、DataSet、およびDataTable操作をグループ化できます。 こうすることで、サーバーへのラウンド トリップの回数が減少し、大幅なパフォーマンスの向上が期待できます。 バッチ更新は、Microsoft SqlClient data provider for SQL Server (Microsoft.Data.SqlClient) でサポートされています。

以前のバージョンの ADO.NET では、DataSet に格納されている変更内容をデータベースに反映する場合、Update の DataAdapter メソッドを実行して、1 行ずつデータベースを更新していました。 このメソッドは、指定された DataTable 内の行を反復処理すると、各 DataRow を調べ、行が変更されたことを確認します。 行が変更されている場合、その行の UpdateCommand プロパティの値に基づいて、適切な InsertCommand、DeleteCommand、または RowState のいずれかを呼び出します。 各行の更新では、データベースへのネットワーク ラウンドトリップが発生します。

Microsoft SqlClient Data Provider SQL Server では、SqlDataAdapter によって UpdateBatchSize プロパティが公開されます。 UpdateBatchSize を正の整数値に設定すると、データベースの更新が指定されたサイズのバッチとして送信されます。 たとえば、UpdateBatchSize を 10 に設定すると、10 個の個別のステートメントがグループ化され、単一のバッチとして送信されます。 UpdateBatchSize を 0 に設定すると、SqlDataAdapter は、サーバーが処理できる最大のバッチ サイズを使用します。 1 に設定すると、バッチ更新が無効になり、1 行ずつ送信されます。

注

サイズの大きいバッチを実行すると、パフォーマンスが低下する可能性があります。 そのため、アプリケーションを実装する前に、バッチの最適なサイズ設定をテストする必要があります。

UpdateBatchSize プロパティの使用

バッチ更新を有効にする場合、DataAdapter の UpdatedRowSource、UpdateCommand および InsertCommand の DeleteCommand プロパティ値を、None または OutputParameters に設定する必要があります。 バッチ更新を実行する際、UpdatedRowSource または FirstReturnedRecord のコマンドの Both プロパティ値は、無効になります。

UpdateBatchSize プロパティを使用するプロシージャを次に示します。 このプロシージャは、2 つの引数を受け取ります。1 つは、DataSet テーブル内の ProductCategoryID フィールドと Name フィールドを表す列を持つ オブジェクトで、もう 1 つは、バッチ サイズ (バッチ ファイル内の行数) を表す整数です。 このコードにより、新しい SqlDataAdapter オブジェクトが作成され、その UpdateCommand プロパティ、InsertCommand プロパティ、および DeleteCommand プロパティが設定されます。 このコードは、DataSet オブジェクトによって行が変更済みになっていることを前提としています。 このオブジェクトは、UpdateBatchSize プロパティを設定し、更新を実行します。

public static void BatchUpdate(DataTable dataTable, Int32 batchSize)
{
    // Assumes GetConnectionString() returns a valid connection string.
    string connectionString = GetConnectionString();

    // Connect to the AdventureWorks database.
    using (SqlConnection connection = new SqlConnection(connectionString))
    {
        // Create a SqlDataAdapter.  
        SqlDataAdapter adapter = new SqlDataAdapter();

        // Set the UPDATE command and parameters.  
        adapter.UpdateCommand = new SqlCommand(
            "UPDATE Production.ProductCategory SET "
            + "Name=@Name WHERE ProductCategoryID=@ProdCatID;",
            connection);
        adapter.UpdateCommand.Parameters.Add("@Name",
        SqlDbType.NVarChar, 50, "Name");
        adapter.UpdateCommand.Parameters.Add("@ProdCatID",
        SqlDbType.Int, 4, "ProductCategoryID");
        adapter.UpdateCommand.UpdatedRowSource = UpdateRowSource.None;

        // Set the INSERT command and parameter.  
        adapter.InsertCommand = new SqlCommand(
            "INSERT INTO Production.ProductCategory (Name) VALUES (@Name);",
            connection);
        adapter.InsertCommand.Parameters.Add("@Name",
        SqlDbType.NVarChar, 50, "Name");
        adapter.InsertCommand.UpdatedRowSource = UpdateRowSource.None;

        // Set the DELETE command and parameter.  
        adapter.DeleteCommand = new SqlCommand(
            "DELETE FROM Production.ProductCategory "
            + "WHERE ProductCategoryID=@ProdCatID;", connection);
        adapter.DeleteCommand.Parameters.Add("@ProdCatID",
        SqlDbType.Int, 4, "ProductCategoryID");
        adapter.DeleteCommand.UpdatedRowSource = UpdateRowSource.None;

        // Set the batch size.  
        adapter.UpdateBatchSize = batchSize;

        // Execute the update.  
        adapter.Update(dataTable);
    }
}

DataAdapter には、次の 2 つの更新関連イベントがあります: RowUpdating と RowUpdated。 詳細については、「DataAdapter イベントの処理」を参照してください。

バッチ更新によるイベントの動作の変更

バッチ処理が有効になっている場合、1 度のデータベース操作で複数の行が更新されます。 このため、RowUpdated イベントは処理された各行ごとに発生しますが、RowUpdating イベントは各バッチ処理につき、1 つしか発生しません。 バッチ処理が無効になっている場合、1 対 1 のインターリーブを伴う 2 つのイベントが発生します。つまり、1 つの行に対し、RowUpdating イベントが 1 つ、RowUpdated イベントが 1 つ発生します。すべての行が処理されるまで、次の行に対して RowUpdating イベントが 1 つ、RowUpdated イベントが 1 つ発生します。

更新された行へのアクセス

バッチ処理が無効になっている場合、更新された行には、Row クラスの RowUpdatedEventArgs プロパティを使用してアクセスできます。

バッチ処理が有効になっている場合、複数の行に対して 1 つの RowUpdated イベントが生成されます。 つまり、各行の Row プロパティ値は null ですが、 RowUpdating イベントは各行に対して引き続き生成されます。 処理された行にアクセスするには、CopyToRows クラスの RowUpdatedEventArgs メソッドにより、配列に行への参照をコピーします。 処理中の行がない場合、CopyToRows は ArgumentNullException をスローします。 RowCount メソッドを呼び出す前に、CopyToRows プロパティを使用して、処理されている行数を取得できます。

データ エラーの処理

ステートメントを個別に実行した場合とバッチ処理を実行した場合では効果は同じです。 ステートメントはバッチに追加された順序と同じ順序で実行されます。 エラーは、バッチ モードでも、バッチ モードが無効な場合と同様に処理されます。 つまり、各行が個別に処理されます。 データベース内で正常に処理された行だけが、DataRow 内の対応する DataTable で更新されます。

注

Microsoft SqlClient Data Provider for SQL Server とバックエンド データベース サーバーによって、バッチ実行でサポートされる SQL コンストラクトが決まります。 サポートされていないステートメントが実行時に送信されると、例外がスローされる場合があります。