合併 DataSet 內容
您可以使用 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。下列情況則例外:
如果現有資料列的 RowState 為 Deleted,則這個 RowState 會維持為 Deleted,而不會被設定為 Modified。這種情況下,來自內送資料列的資料仍然會儲存在現有資料列的 Original 資料列版本中,並將現有資料列的 Original 資料列版本覆寫 (除非內送資料列的 RowState 為 Added)。
如果內送資料列的 RowState 為 Added,則來自現有資料列 Original 資料列版本的資料不會被來自內送資料列的資料覆寫,因為內送資料列沒有 Original 資料列版本。
PreserveChanges 為 false 時,現有資料列的 Current 和 Original 資料列版本會被來自內送資料列的資料覆寫,而且現有資料列的 RowState 會被設定為內送資料列的 RowState,下列情況則例外:
如果內送資料列的 RowState 為 Unchanged,且現有資料列的 RowState 為 Modified、Deleted 或 Added,則現有資料列的 RowState 會設定為 Modified。
如果內送資料列的 RowState 為 Added,且現有資料列的 RowState 為 Unchanged、Modified 或 Deleted,則現有資料列的 RowState 會設定為 Modified;此外,來自現有資料列 Original 資料列版本的資料不會被來自內送資料列的資料覆寫,因為內送資料列沒有 Original 資料列版本。
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 主索引鍵值違反了主索引鍵資料行 unique 條件約束。
下列程式碼範例將兩個具有不同結構描述的 DataSet 物件合併入一個 DataSet,這個 DataSet 將具有上述兩個內送 DataSet 物件的合併條件約束。
Using connection As SqlConnection = New SqlConnection( _
connectionString)
Dim adapter As SqlDataAdapter = New SqlDataAdapter( _
"SELECT CustomerID, CompanyName FROM Customers", connection)
connection.Open()
Dim customers As DataSet = New DataSet()
adapter.FillSchema(customers, SchemaType.Source, "Customers")
adapter.Fill(customers, "Customers")
Dim orders As DataSet = New DataSet()
orders.ReadXml("Orders.xml", XmlReadMode.ReadSchema)
orders.AcceptChanges()
customers.Merge(orders, True, MissingSchemaAction.AddWithKey)
End Using
using (SqlConnection connection =
new SqlConnection(connectionString))
{
SqlDataAdapter adapter =
new SqlDataAdapter(
"SELECT CustomerID, CompanyName FROM dbo.Customers",
connection);
connection.Open();
DataSet customers = new DataSet();
adapter.FillSchema(customers, SchemaType.Source, "Customers");
adapter.Fill(customers, "Customers");
DataSet orders = new DataSet();
orders.ReadXml("Orders.xml", XmlReadMode.ReadSchema);
orders.AcceptChanges();
customers.Merge(orders, true, MissingSchemaAction.AddWithKey);
下列程式碼範例取得經過更新的現有 DataSet,並將這些更新傳遞至 DataAdapter 並在資料來源處理。接著結果會合併入原始 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()
DataTable customers = dataSet.Tables["Customers"];
// Make modifications to the Customers table.
// Get changes to the DataSet.
DataSet dataSetChanges = dataSet.GetChanges();
// Add an event handler to handle the errors during Update.
adapter.RowUpdated += new SqlRowUpdatedEventHandler(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();
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
protected static void OnRowUpdated(
object sender, SqlRowUpdatedEventArgs args)
{
if (args.Status == UpdateStatus.ErrorsOccurred)
{
args.Row.RowError = args.Errors.Message;
args.Status = UpdateStatus.SkipCurrentRow;
}
}