加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 大数据 > 正文

vb.net – 在DataRowState.Modified中合并两个相同的DataTables

发布时间:2020-12-17 00:05:49 所属栏目:大数据 来源:网络整理
导读:我错了,假设如果两个相同的DataTable合并,每行的状态将被保留? 看看这个简单的例子.它创建两个相同的表,并将更新的表与原始表合并.但是original.GetChanges()中返回的表并不像预期的那样是Nothing.此外,原始表中每行的状态更改为“已修改”. 那我错过了什么
我错了,假设如果两个相同的DataTable合并,每行的状态将被保留?

看看这个简单的例子.它创建两个相同的表,并将更新的表与原始表合并.但是original.GetChanges()中返回的表并不像预期的那样是Nothing.此外,原始表中每行的状态更改为“已修改”.

那我错过了什么?我真的必须创建自己的合并方法来实现这一目标吗?

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),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

输出:计数= 2

编辑 – 解决方法

以下代码是针对此奇怪(?)行为的变通方法.

Private Shared Sub Merge(target As DataTable,source As DataTable,preserveChanges As Boolean,msa As MissingSchemaAction)

    target.Merge(source,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
在使用DataTable合并一段时间之后,我找到了合并数据的最佳解决方案,保留了更改,而没有为所有现有行设置RowState为Modified.

我发现,如果使用DataTable Merge并将True传递为preserve更改属性,则原始DataTable中的所有行都将其RowState设置为Modified.如果您传递false,则RowStates保持不变.

回到DataTable.Merge(DataTable,Boolean,MissingSchemaAction) Method的文档,我发现了这个:

…In this scenario,the GetChanges method is first invoked. That method returns a second DataTable optimized for validating and merging. This second DataTable object contains only the DataTable and DataRow objects objects that were changed,resulting in a subset of the original 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,msAction)
    End If


    MessageBox.Show(String.Format("Changes in Change Table: {0} {1}Changes Detected: {2}",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表中,表示保留change = false.因为传递false作为保留更改参数导致原始数据没有RowState更改,所以一切正常!保留我的更改并且不修改RowStates!

快乐的编码!

-Frinny

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读