Merge メソッドを使用して、DataSet、DataTable、またはDataRow配列の内容を既存のDataSet
にマージできます。 新しいデータを既存の DataSet
にマージする方法には、いくつかの要因とオプションが影響します。
主キー
マージから新しいデータとスキーマを受け取るテーブルに主キーがある場合、受信データの新しい行は、受信データと同じ Original 主キー値を持つ既存の行と照合されます。 受信スキーマの列が既存のスキーマの列と一致する場合は、既存の行のデータが変更されます。 既存のスキーマと一致しない列は無視されるか、 MissingSchemaAction パラメーターに基づいて追加されます。 既存の行と一致しない主キー値を持つ新しい行が、既存のテーブルに追加されます。
入力または既存の行の状態が Added の場合、Original
行バージョンが存在しないため、Added
行のCurrent主キー値を使用して主キー値が照合されます。
受信テーブルと既存のテーブルに同じ名前で異なるデータ型の列が含まれている場合は、例外がスローされ、DataSet
のMergeFailed イベントが発生します。 受信テーブルと既存のテーブルの両方にキーが定義されているが、主キーが異なる列用である場合は、例外がスローされ、DataSet
のMergeFailed
イベントが発生します。
マージから新しいデータを受信するテーブルに主キーがない場合、受信データの新しい行をテーブル内の既存の行と照合できず、代わりに既存のテーブルに追加されます。
テーブル名と名前空間
DataTable オブジェクトには、必要に応じて Namespace プロパティ値を割り当てることができます。 Namespace値が割り当てられると、DataSetには同じTableName値を持つ複数のDataTable オブジェクトを含めることができます。 マージ操作では、 TableName と Namespace の両方を使用してマージのターゲットを識別します。 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
メソッドにDataSet
、DataTable
、またはDataRow
配列を渡すときに、既存のDataSet
の変更を保持するかどうかを指定する省略可能なパラメーターと、受信データで見つかった新しいスキーマ要素を処理する方法を含めることができます。 受信データの後の最初のパラメーターは、既存のDataSet
の変更を保持するかどうかを指定するブール型のフラグであるPreserveChangesです。
PreserveChanges
フラグが true
に設定されている場合、受信値は既存の行のCurrent
行バージョンの既存の値を上書きしません。
PreserveChanges
フラグが false
に設定されている場合、受信値は既存の行のCurrent
行バージョンの既存の値を上書きします。
PreserveChanges
フラグが指定されていない場合は、既定でfalse
に設定されます。 行のバージョンの詳細については、「行の 状態と行のバージョン」を参照してください。
PreserveChanges
がtrue
されると、既存の行のデータは既存の行のCurrent行バージョンに保持されますが、既存の行のOriginal行バージョンのデータは、受信行のOriginal
行バージョンのデータで上書きされます。 既存の行の RowState は Modifiedに設定されます。 適用される例外を次に示します。
既存の行に
Deleted
のRowState
がある場合、このRowState
はDeleted
のままであり、Modified
に設定されません。 この場合、受信行のデータは既存の行のOriginal
行バージョンに保存され、既存の行のOriginal
行バージョンが上書きされます (受信行にRowState
のAdded
がない限り)。受信行に
Added
のRowState
がある場合、既存の行のOriginal
行バージョンのデータは、受信行にOriginal
行バージョンがないため、受信行のデータで上書きされません。
PreserveChanges
がfalse
されると、既存の行のCurrent
バージョンとOriginal
行バージョンの両方が受信行のデータで上書きされ、既存の行のRowState
が受信行のRowState
に設定されます。 適用される例外を次に示します。
入力行に
Unchanged
のRowState
があり、既存の行にModified
、Deleted
、またはAdded
のRowState
がある場合、既存の行のRowState
はModified
に設定されます。入力行に
Added
のRowState
があり、既存の行にUnchanged
、Modified
、またはDeleted
のRowState
がある場合、既存の行のRowState
はModified
に設定されます。 また、受信行には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