次の方法で共有


DataSet コンテンツのマージ

Merge メソッドを使用して、DataSetDataTable、またはDataRow配列の内容を既存のDataSetにマージできます。 新しいデータを既存の DataSetにマージする方法には、いくつかの要因とオプションが影響します。

主キー

マージから新しいデータとスキーマを受け取るテーブルに主キーがある場合、受信データの新しい行は、受信データと同じ Original 主キー値を持つ既存の行と照合されます。 受信スキーマの列が既存のスキーマの列と一致する場合は、既存の行のデータが変更されます。 既存のスキーマと一致しない列は無視されるか、 MissingSchemaAction パラメーターに基づいて追加されます。 既存の行と一致しない主キー値を持つ新しい行が、既存のテーブルに追加されます。

入力または既存の行の状態が Added の場合、Original行バージョンが存在しないため、Added行のCurrent主キー値を使用して主キー値が照合されます。

受信テーブルと既存のテーブルに同じ名前で異なるデータ型の列が含まれている場合は、例外がスローされ、DataSetMergeFailed イベントが発生します。 受信テーブルと既存のテーブルの両方にキーが定義されているが、主キーが異なる列用である場合は、例外がスローされ、DataSetMergeFailed イベントが発生します。

マージから新しいデータを受信するテーブルに主キーがない場合、受信データの新しい行をテーブル内の既存の行と照合できず、代わりに既存のテーブルに追加されます。

テーブル名と名前空間

DataTable オブジェクトには、必要に応じて Namespace プロパティ値を割り当てることができます。 Namespace値が割り当てられると、DataSetには同じTableName値を持つ複数のDataTable オブジェクトを含めることができます。 マージ操作では、 TableNameNamespace の両方を使用してマージのターゲットを識別します。 Namespaceが割り当てられていない場合は、マージのターゲットを識別するためにTableNameのみが使用されます。

この動作は、.NET Framework のバージョン 2.0 で変更されました。 バージョン 1.1 では、名前空間はサポートされていましたが、マージ操作中は無視されていました。 このため、Namespaceプロパティ値を使用するDataSetは、実行している .NET Framework のバージョンによって動作が異なります。 たとえば、同じTableNameプロパティ値を持ち、Namespaceプロパティ値が異なるDataTablesを含む 2 つのDataSetsがあるとします。 .NET Framework のバージョン 1.1 では、2 つのDataSet オブジェクトをマージするときに、異なるNamespace名は無視されます。 ただし、バージョン 2.0 以降では、マージにより、ターゲット DataSetに 2 つの新しいDataTablesが作成されます。 元の DataTables はマージの影響を受けません。

PreserveChanges

Merge メソッドにDataSetDataTable、またはDataRow配列を渡すときに、既存のDataSetの変更を保持するかどうかを指定する省略可能なパラメーターと、受信データで見つかった新しいスキーマ要素を処理する方法を含めることができます。 受信データの後の最初のパラメーターは、既存のDataSetの変更を保持するかどうかを指定するブール型のフラグであるPreserveChangesです。 PreserveChanges フラグが true に設定されている場合、受信値は既存の行のCurrent行バージョンの既存の値を上書きしません。 PreserveChanges フラグが false に設定されている場合、受信値は既存の行のCurrent行バージョンの既存の値を上書きします。 PreserveChanges フラグが指定されていない場合は、既定でfalseに設定されます。 行のバージョンの詳細については、「行の 状態と行のバージョン」を参照してください。

PreserveChangestrueされると、既存の行のデータは既存の行のCurrent行バージョンに保持されますが、既存の行のOriginal行バージョンのデータは、受信行のOriginal行バージョンのデータで上書きされます。 既存の行の RowStateModifiedに設定されます。 適用される例外を次に示します。

  • 既存の行にDeletedRowStateがある場合、このRowStateDeletedのままであり、Modifiedに設定されません。 この場合、受信行のデータは既存の行の Original 行バージョンに保存され、既存の行の Original 行バージョンが上書きされます (受信行に RowStateAddedがない限り)。

  • 受信行にAddedRowStateがある場合、既存の行のOriginal行バージョンのデータは、受信行にOriginal行バージョンがないため、受信行のデータで上書きされません。

PreserveChangesfalseされると、既存の行のCurrentバージョンとOriginal行バージョンの両方が受信行のデータで上書きされ、既存の行のRowStateが受信行のRowStateに設定されます。 適用される例外を次に示します。

  • 入力行にUnchangedRowStateがあり、既存の行にModifiedDeleted、またはAddedRowStateがある場合、既存の行のRowStateModifiedに設定されます。

  • 入力行にAddedRowStateがあり、既存の行にUnchangedModified、またはDeletedRowStateがある場合、既存の行のRowStateModifiedに設定されます。 また、受信行にはOriginal行バージョンがないため、既存の行のOriginal行バージョンのデータは、受信行のデータで上書きされません。

MissingSchemaAction

Merge メソッドの省略可能な MissingSchemaAction パラメーターを使用して、既存のDataSetに含まれていない受信データのスキーマ要素Merge処理方法を指定できます。

次の表では、 MissingSchemaActionのオプションについて説明します。

MissingSchemaAction オプション 説明
Add 新しいスキーマ情報を DataSet に追加し、新しい列に受信値を設定します。 これが既定値です。
AddWithKey 新しいスキーマと主キーの情報を DataSet に追加し、新しい列に受信値を設定します。
Error スキーマ情報が一致しない場合は例外をスローします。
Ignore 新しいスキーマ情報は無視します。

制約

Mergeメソッドでは、すべての新しいデータが既存のDataSetに追加されるまで、制約はチェックされません。 データが追加されると、 DataSetの現在の値に制約が適用されます。 制約違反が原因でスローされる可能性のある例外をコードで処理する必要があります。

DataSet内の既存の行が、主キー値が 1 のUnchanged行である場合を考えてみましょう。 Original主キー値が 2 で、Current主キー値が 1 のModified入力行を含むマージ操作では、Original主キーの値が異なるため、既存の行と受信行は一致しないと見なされます。 ただし、マージが完了し、制約がチェックされると、 Current 主キー値が主キー列の一意制約に違反するため、例外がスローされます。

ID 列などの自動インクリメント列を含むデータベース テーブルに行が挿入されると、挿入によって返される ID 列の値が DataSetの値と一致せず、返された行がマージされる代わりに追加される可能性があります。 詳細については、「 ID またはオートナンバー型の値の取得」を参照してください。

次のコード例では、スキーマが異なる 2 つのDataSet オブジェクトを、2 つの受信DataSet オブジェクトの結合されたスキーマを使用して 1 つのDataSetにマージします。

using (SqlConnection connection =
           new(connectionString))
{
    SqlDataAdapter adapter =
        new(
        "SELECT CustomerID, CompanyName FROM dbo.Customers",
        connection);

    connection.Open();

    DataSet customers = new();
    adapter.FillSchema(customers, SchemaType.Source, "Customers");
    adapter.Fill(customers, "Customers");

    DataSet orders = new();
    orders.ReadXml("Orders.xml", XmlReadMode.ReadSchema);
    orders.AcceptChanges();

    customers.Merge(orders, true, MissingSchemaAction.AddWithKey);
}
Using connection As SqlConnection = New SqlConnection(
   connectionString)

    Dim adapter As New SqlDataAdapter(
      "SELECT CustomerID, CompanyName FROM Customers", connection)

    connection.Open()

    Dim customers As New DataSet()
    adapter.FillSchema(customers, SchemaType.Source, "Customers")
    adapter.Fill(customers, "Customers")

    Dim orders As New DataSet()
    orders.ReadXml("Orders.xml", XmlReadMode.ReadSchema)
    orders.AcceptChanges()

    customers.Merge(orders, True, MissingSchemaAction.AddWithKey)
End Using

次のコード例では、更新プログラムを含む既存の DataSet を取得し、それらの更新をデータ ソースで処理する DataAdapter に渡します。 結果は元の DataSetにマージされます。 エラーが発生した変更を拒否すると、マージされた変更は AcceptChangesでコミットされます。

DataTable customers = dataSet.Tables["Customers"]!;

// Make modifications to the Customers table.

// Get changes to the DataSet.
DataSet dataSetChanges = dataSet.GetChanges() ?? new();

// Add an event handler to handle the errors during Update.
adapter.RowUpdated += OnRowUpdated;

connection.Open();
adapter.Update(dataSetChanges, "Customers");
connection.Close();

// Merge the updates.
dataSet.Merge(dataSetChanges, true, MissingSchemaAction.Add);

// Reject changes on rows with errors and clear the error.
DataRow[] errRows = dataSet.Tables["Customers"]!.GetErrors();
foreach (DataRow errRow in errRows)
{
    errRow.RejectChanges();
    errRow.RowError = null;
}

// Commit the changes.
dataSet.AcceptChanges();

Dim customers As DataTable = dataSet.Tables("Customers")

' Make modifications to the Customers table.

' Get changes to the DataSet.
Dim dataSetChanges As DataSet = dataSet.GetChanges()

' Add an event handler to handle the errors during Update.
AddHandler adapter.RowUpdated, New SqlRowUpdatedEventHandler(
  AddressOf OnRowUpdated)

connection.Open()
adapter.Update(dataSetChanges, "Customers")
connection.Close()

' Merge the updates.
dataSet.Merge(dataSetChanges, True, MissingSchemaAction.Add)

' Reject changes on rows with errors and clear the error.
Dim errRows() As DataRow = dataSet.Tables("Customers").GetErrors()
Dim errRow As DataRow
For Each errRow In errRows
    errRow.RejectChanges()
    errRow.RowError = Nothing
Next

' Commit the changes.
dataSet.AcceptChanges()

protected static void OnRowUpdated(
    object sender, SqlRowUpdatedEventArgs args)
{
    if (args.Status == UpdateStatus.ErrorsOccurred)
    {
        args.Row.RowError = args.Errors!.Message;
        args.Status = UpdateStatus.SkipCurrentRow;
    }
}
Private Sub OnRowUpdated(
    ByVal sender As Object, ByVal args As SqlRowUpdatedEventArgs)
    If args.Status = UpdateStatus.ErrorsOccurred Then
        args.Row.RowError = args.Errors.Message
        args.Status = UpdateStatus.SkipCurrentRow
    End If
End Sub

こちらも参照ください