Bjø*_*sjå 5 vb.net datatable winforms
我错了,假设如果两个相同DataTables
的合并,每行的状态将被保留?
看看这个简单的例子.它创建两个相同的表并将updated
表与original
表合并.但是返回的表格original.GetChanges()
并不Nothing
像预期的那样.此外,original
表中每行的状态也更改为Modified
.
那我错过了什么?我真的必须创建自己的合并方法来实现这一目标吗?
Public Sub Test()
Dim original As DataTable = Me.CreateTableWithData()
Dim updated As DataTable = Me.CreateTableWithData()
Dim preserveChanges As Boolean = True
Dim msAction As MissingSchemaAction = MissingSchemaAction.Ignore
original.Merge(updated, preserveChanges, msAction)
Dim changes As DataTable = original.GetChanges()
MessageBox.Show(String.Format("Count={0}", If((changes Is Nothing), 0, changes.Rows.Count)), Me.Text, MessageBoxButtons.OK, MessageBoxIcon.Information)
If (Not changes Is Nothing) Then changes.Dispose() : changes = Nothing
updated.Dispose() : updated = Nothing
original.Dispose() : original = Nothing
End Sub
Private Function CreateTableWithData() As DataTable
Dim table As New DataTable("TEST")
table.Columns.Add("ID", GetType(Integer))
table.Columns.Add("VALUE", GetType(String))
table.PrimaryKey = New DataColumn() {table.Columns(0)}
table.Rows.Add(1, "Value 1")
table.Rows.Add(2, "Value 2")
table.AcceptChanges()
Return table
End Function
Run Code Online (Sandbox Code Playgroud)
输出: Count=2
编辑 - 解决方法
以下代码是针对此奇怪(?)行为的变通方法.
Private Shared Sub Merge(target As DataTable, source As DataTable, preserveChanges As Boolean, msa As MissingSchemaAction)
target.Merge(source, preserveChanges, msa)
Dim row As DataRow
Dim column As DataColumn
Dim acceptChanges As Boolean
For Each row In target.Rows
If ((row.RowState = DataRowState.Modified) AndAlso ((row.HasVersion(DataRowVersion.Original)) AndAlso (row.HasVersion(DataRowVersion.Default)))) Then
acceptChanges = True
For Each column In target.Columns
If (Not Object.Equals(row.Item(column, DataRowVersion.Original), row.Item(column, DataRowVersion.Default))) Then
acceptChanges = False
Exit For
End If
Next
If (acceptChanges) Then
row.AcceptChanges()
End If
End If
Next
acceptChanges = Nothing
column = Nothing
row = Nothing
End Sub
Run Code Online (Sandbox Code Playgroud)
使用 DataTable 合并一段时间后,我找到了合并数据、保留更改以及不将所有现有行的 RowState 设置为 Modified 的最佳解决方案。
我发现,如果您使用 DataTable Merge 并传递 True 作为保留更改属性,则原始 DataTable 中的所有行的 RowState 都会设置为 Modified。如果您传递 false,则 RowState 保持不变。
回到DataTable.Merge(DataTable, Boolean, MissingSchemaAction) 方法的文档,我发现了这个:
...在这种情况下,首先调用 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
Run Code Online (Sandbox Code Playgroud)
因此,在 MergeTables 方法中,我对 _table2 中的第一行进行了更改,并对 _table1 中的第二行进行了更改。
因为我对 _table1 中的第一行进行了更改,所以 _table1.GetChanges 方法返回一个包含所有已更改行的 DataTable(在本例中仅是第一行)。
然后,我将包含更改的表与 _table2 合并,并指示我要保留更改。
合并完成后,我知道结果将保留合并之前所做的更改,并且该表也将包含新数据(只要不存在冲突)。将传入数据合并到更改表中的结果将解决数据中的任何冲突。
获得已解析的表后,我可以安全地合并到原始 _table1 表中,指示保留更改 = false。因为传递 false 作为保留更改参数会导致原始数据的 RowState 没有更改,所以一切都工作得很好!我的更改被保留并且 RowStates 没有被修改!
快乐编码!
-弗林尼
归档时间: |
|
查看次数: |
2613 次 |
最近记录: |