可以使用 DataSet 的 Merge 方法将 DataSet、DataTable 或 DataRow 数组的内容并入现有 DataSet。以下几个因素和选项会影响新数据并入现有 DataSet 的方式。
主键
如果从合并中接收新数据和架构的表具有主键,则传入数据中的新行将与相应的现有行进行匹配,这些现有行与传入数据中的行具有相同的 Original 主键值。如果传入架构中的列匹配现有架构的相应列,则会修改现有行中的数据。对于不匹配现有架构的列,将根据 MissingSchemaAction 参数(请参阅本主题后面部分的“MissingSchemaAction”)来将其忽略或添加。如果新行的主键值不匹配任何现有行,则会将新行追加到现有表。
如果传入行或现有行的行状态为 Added,由于不存在 Original 行版本,所以会使用 Added 行的 Current 主键值匹配这些行的主键值。
如果传入表和现有表包含名称相同但数据类型不同的列,则将引发异常并引发 DataSet 的 MergeFailed 事件。如果传入表和现有表都已定义主键,但主键用于不同的列,则将引发异常并引发 DataSet 的 MergeFailed 事件。
如果从合并中接收新数据的表不具有主键,传入数据中的新行将无法与该表中的现有行匹配,而这些新行则会追加到现有表。
preserveChanges
当您将 DataSet、DataTable 或 DataRow 数组传递给 Merge 方法时,可以包含一些可选参数,它们指定是否在现有 DataSet 中保留更改以及如何处理传入数据中的新架构元素。传入数据之后第一个这样的参数为 Boolean 标志 preserveChanges,它指定是否在现有 DataSet 中保留更改。如果 preserveChanges 标志设置为 true,传入值将不会改写现有行 Current 行版本中的现有值。如果 preserveChanges 标志设置为 false,传入值则将改写现有行 Current 行版本中的现有值。如果未指定 preserveChanges 标志,它将设置为默认值 false。有关行版本的更多信息,请参阅行状态与行版本。
当 preserveChanges 为 true 时,现有行中的数据在现有行的 Current 行版本中进行维护,而传入行 Original 行版本中的数据将改写现有行 Original 行版本中的数据。现有行的 RowState 设置为 Modified。存在以下例外:
当 preserveChanges 为 false 时,传入行中的数据将改写当前行中的 Current 和 Original 行版本,而现有行的 RowState 将设置为传入行的 RowState。存在以下例外:
MissingSchemaAction
可以使用 Merge 方法的可选 MissingSchemaAction 参数来指定 Merge 如何处理传入数据中不属于现有 DataSet 的架构元素。
下表描述 MissingSchemaAction 的选项。
| MissingSchemaAction | 说明 |
|---|---|
| Add | 将新的架构信息添加到 DataSet 中并使用传入值填充新列。这是默认值。 |
| AddWithKey | 将新架构和主键信息添加到 DataSet 中并使用传入值填充新列。 |
| Error | 如果遇到不匹配的架构信息,则引发异常。 |
| Ignore | 忽略新的架构信息。 |
约束
当使用 Merge 方法时,直到所有新数据都已添加到现有 DataSet 中后,才会检查约束。该数据一旦添加,将对 DataSet 中的当前值强制约束。您必须确保您所编写的代码可以处理可能因约束冲突而引发的任何异常。
请考虑以下示例:DataSet 中的现有行是主键值为 1 的 Unchanged 行。在将 Original 主键值为 2 与 Current 主键值为 1 的 Modified 传入行合并的过程中,由于 Original 主键值不同,因此不认为现有行与传入行匹配。不过,当完成合并并检查约束后,由于 Current 主键值违反主键列的唯一约束,因此将引发异常。
以下代码示例将两个具有不同架构的 DataSet 对象合并到一个 DataSet 中,后者包含两个传入 DataSet 对象的组合架构。
[Visual Basic]
Dim nwindConn As SqlConnection = New SqlConnection("Data Source=localhost;Integrated
Security=SSPI;Initial Catalog=northwind")
Dim custDA As SqlDataAdapter = New SqlDataAdapter("SELECT CustomerID,
CompanyName FROM Customers", nwindConn)
nwindConn.Open()
Dim custDS As DataSet = New DataSet()
custDA.FillSchema(custDS, SchemaType.Source, "Customers")
custDA.Fill(custDS, "Customers")
Dim orderDS As DataSet = New DataSet()
orderDS.ReadXml("Orders.xml", XmlReadMode.ReadSchema)
orderDS.AcceptChanges()
nwindConn.Close()
custDS.Merge(orderDS, True, MissingSchemaAction.AddWithKey)
[C#]
SqlConnection nwindConn = new SqlConnection("Data Source=localhost;Integrated
Security=SSPI;Initial Catalog=northwind");
SqlDataAdapter custDA = new SqlDataAdapter("SELECT CustomerID, CompanyName
FROM Customers", nwindConn);
nwindConn.Open();
DataSet custDS = new DataSet();
custDA.FillSchema(custDS, SchemaType.Source, "Customers");
custDA.Fill(custDS, "Customers");
DataSet orderDS = new DataSet();
orderDS.ReadXml("Orders.xml", XmlReadMode.ReadSchema);
orderDS.AcceptChanges();
nwindConn.Close();
custDS.Merge(orderDS, true, MissingSchemaAction.AddWithKey);
以下代码示例采用包含更新的现有 DataSet,并将这些更新传递到一个 DataAdapter,以便在数据源中进行处理。然后,所得结果将并入初始 DataSet。当拒绝已导致错误的更改后,将通过 AcceptChanges 提交合并的更改。
[Visual Basic]
Dim custTable As DataTable = custDS.Tables("Customers")
' Make modifications to the Customers table.
' Get changes to the DataSet.
Dim updDS As DataSet = custDS.GetChanges()
' Add an event handler to handle the errors during Update.
AddHandler custDA.RowUpdated, New SqlRowUpdatedEventHandler(AddressOf
OnRowUpdated)
nwindConn.Open()
custDA.Update(updDS, "Customers")
nwindConn.Close()
' Merge the updates.
custDS.Merge(updDS, true, MissingSchemaAction.Add)
' Reject changes on rows with errors and clear the error.
Dim errRows() As DataRow = custDS.Tables("Customers").GetErrors()
Dim errRow As DataRow
For Each errRow In errRows
errRow.RejectChanges()
errRow.RowError = Nothing
Next
' Commit the changes.
custDS.AcceptChanges()
Private Shared Sub OnRowUpdated(sender As Object, args As SqlRowUpdatedEventArgs)
If args.Status = UpdateStatus.ErrorsOccurred
args.Row.RowError = args.Errors.Message
args.Status = UpdateStatus.SkipCurrentRow
End If
End Sub
[C#]
DataTable custTable = custDS.Tables["Customers"];
// Make modifications to the Customers table.
// Get changes to the DataSet.
DataSet updDS = custDS.GetChanges();
// Add an event handler to handle the errors during Update.
custDA.RowUpdated += new SqlRowUpdatedEventHandler(OnRowUpdated);
nwindConn.Open();
custDA.Update(updDS, "Customers");
nwindConn.Close();
// Merge the updates.
custDS.Merge(updDS, true, MissingSchemaAction.Add);
// Reject changes on rows with errors and clear the error.
DataRow[] errRows = custDS.Tables["Customers"].GetErrors();
foreach (DataRow errRow in errRows)
{
errRow.RejectChanges();
errRow.RowError = null;
}
// Commit the changes.
custDS.AcceptChanges();
protected static void OnRowUpdated(object sender, SqlRowUpdatedEventArgs args)
{
if (args.Status == UpdateStatus.ErrorsOccurred)
{
args.Row.RowError = args.Errors.Message;
args.Status = UpdateStatus.SkipCurrentRow;
}
}