使用 DataTable 合并一段时间后,我找到了合并数据、保留更改以及不将所有现有行的 RowState 设置为 Modified 的最佳解决方案。
我发现,如果您使用 DataTable Merge 并传递 True 作为保留更改属性,则原始 DataTable 中的所有行的 RowState 都会设置为 Modified。如果您传递 false,则 RowState 保持不变。
回到文档DataTable.Merge(DataTable, Boolean, MissingSchemaAction) 方法 http://msdn.microsoft.com/en-us/library/wtk78t63%28v=vs.110%29.aspx我找到了这个:
...在这种情况下,首先调用 GetChanges 方法。该方法返回针对验证和合并而优化的第二个 DataTable。第二个 DataTable 对象仅包含已更改的 DataTable 和 DataRow 对象,从而生成原始 DataTable 的子集...
从那里我开始意识到这个合并并不是真的打算直接与原始数据一起使用...相反,您应该合并 GetChanges 方法返回的表(在保留更改时传递 true ),然后合并更改表到原始源中传递 false 以保留更改参数。
为了证明这一点,我创建了以下类:
Class TableManger
Implements ComponentModel.INotifyPropertyChanged
Private _table1 As System.Data.DataTable
Private _table2 As System.Data.DataTable
Private _changesDetected As Integer = 0
Public ReadOnly Property Table1
Get
Return _table1
End Get
End Property
Public ReadOnly Property ChangesDetected As Integer
Get
Return _changesDetected
End Get
End Property
Public Sub New()
_table1 = CreateTableWithData()
_table1.AcceptChanges()
AddHandler _table1.RowChanged, New System.Data.DataRowChangeEventHandler(AddressOf Row_Changed)
End Sub
Public Sub MergeTables()
_table2 = _table1.Clone
Dim tableRows As New List(Of System.Data.DataRow)
For Each r In _table1.Rows
Dim dr2 = _table2.NewRow
For Each col As System.Data.DataColumn In _table1.Columns
dr2(col.ColumnName) = r(col.ColumnName)
Next
_table2.Rows.Add(dr2)
tableRows.Add(dr2)
Next
_table2.AcceptChanges()
If _table2.Rows.Count > 0 Then
_table2.Rows(0)(1) = "TB2 Changed"
End If
If _table1.Rows.Count > 0 Then
'_table1.Rows(0)(1) = "TB1 Change"'
_table1.Rows(1)(1) = "TB1 Change"
End If
_changesDetected = 0
Dim perserveChanges As Boolean = True
Dim msAction As System.Data.MissingSchemaAction = System.Data.MissingSchemaAction.Ignore
Dim changes As System.Data.DataTable = _table1.GetChanges()
If changes IsNot Nothing Then
changes.Merge(_table2, perserveChanges, msAction)
_table1.Merge(changes, False, msAction)
Else
_table1.Merge(_table2, False, msAction)
End If
MessageBox.Show(String.Format("Changes in Change Table: {0} {1}Changes Detected: {2}", If((changes Is Nothing), 0, changes.Rows.Count), System.Environment.NewLine, _changesDetected), "Testing")
RaiseEvent PropertyChanged(Me, New ComponentModel.PropertyChangedEventArgs("Table1"))
RaiseEvent PropertyChanged(Me, New ComponentModel.PropertyChangedEventArgs("ChangesDetected"))
End Sub
Private Sub Row_Changed(ByVal sender As Object, ByVal e As System.Data.DataRowChangeEventArgs)
Select Case e.Action
Case System.Data.DataRowAction.Change
If e.Row.RowState <> System.Data.DataRowState.Unchanged Then
_changesDetected += 1
End If
End Select
End Sub
Private Function CreateTableWithData() As System.Data.DataTable
Dim newTable As New System.Data.DataTable
Dim columnID As New System.Data.DataColumn("ID", GetType(Guid))
Dim columnA As New System.Data.DataColumn("ColumnA", GetType(String))
Dim columnB As New System.Data.DataColumn("ColumnB", GetType(String))
newTable.Columns.AddRange({columnID, columnA, columnB})
newTable.PrimaryKey = {newTable.Columns(0)}
For i = 0 To 5
Dim dr = newTable.NewRow
dr("ID") = Guid.NewGuid
dr("ColumnA") = String.Format("Column A Row {0}", i.ToString)
dr("ColumnB") = String.Format("Column B Row {0}", i.ToString)
newTable.Rows.Add(dr)
Next
Return newTable
End Function
Public Event PropertyChanged(sender As Object, e As System.ComponentModel.PropertyChangedEventArgs) Implements System.ComponentModel.INotifyPropertyChanged.PropertyChanged
End Class
因此,在 MergeTables 方法中,我对 _table2 中的第一行进行了更改,并对 _table1 中的第二行进行了更改。
因为我对 _table1 中的第一行进行了更改,所以 _table1.GetChanges 方法返回一个包含所有更改行的 DataTable(在本例中仅是第一行)。
然后,我将包含更改的表与 _table2 合并,并指示我要保留更改。
合并完成后,我知道结果将保留合并之前所做的更改,并且该表也将包含新数据(只要不存在冲突)。将传入数据合并到更改表中的结果将解决数据中的任何冲突。
获得已解析的表后,我可以安全地合并到原始 _table1 表中,指示保留更改 = false。因为传递 false 作为保留更改参数会导致原始数据的 RowState 没有更改,所以一切都工作得很好!我的更改被保留并且 RowStates 没有被修改!
快乐编码!
-Frinny