使用LINQ在DataTable

时间:2015-07-31 08:25:19

标签: vb.net linq datatable

我正在VB.NET中构建一个应用程序,我将数据从一个数据库推送到另一个数据库。源数据库是SQL Server,目标是MySQL。

我正在做的是首先为每个数据库中的每个表创建DataTables,我用它来进行比较。我以这样的方式编写了查询,以便源和目标DataTable包含完全相同的列和值,以便于比较。

该应用程序的这一面工作正常。我接下来要做的是通过查找不存在的PK来查找目标数据库中不存在的行。然后我将这些新行插入到目标数据库中,没有任何问题。

问题

我现在需要做的是在每个表中查找已更新的行,即与目标DataTable中的相应行不同。我尝试按照以下示例使用Except()

Public Function GetUpdates(ByVal DSDataSet As MSSQLQuery, ByVal AADataSet As MySQLQuery, Optional ByVal PK As String = Nothing) As List(Of DataRow)
    ' Determines records to be updated in the AADB and returns list of new Rows
    ' Param DSDataSet - MSSQLQuery Object for source table
    ' Param AADataSet - MySQLQuery Object for destination table
    ' Optional Param PK - String of name common columns to treat as PK
    ' Returns List(Of DataRow) containing rows to update in table

    Dim orig = DSDataSet.GetDataset()
    Dim origTable = orig.Tables(0).AsEnumerable()
    Dim destination = AADataSet.GetDataset()
    Dim destinationTable = destination.Tables(0).AsEnumerable()

    ' Get Records which are not in destination table
    Dim ChangedRows = Nothing

    If IsNothing(PK) Then
        ChangedRows = destinationTable.AsEnumerable().Except(origTable.AsEnumerable(), DataRowComparer.Default)
    End If

    Dim List As New List(Of DataRow)

    For Each addRow In ChangedRows
        List.Add(addRow)
    Next

    Return List
End Function

麻烦的是它最终只返回整组源行。

如何检查这些已更改的行?我总是可以对查询进行硬编码以返回我想要的内容,但这会引入问题,因为我需要对15个表进行比较,这样就完全搞砸了。

理想情况下,我需要一个解决方案,它将考虑源表中的变量数列,以便与基本相同的目标表进行比较,并简单地比较DataRows的相等性。

每个源行的目标表中都应该有一个对应的行,因为在检查更新的行之前会执行新行的添加。

我也愿意使用LINQ以外的方法来实现这一目标。

解决方案

最后,我实现了一个自定义比较器,用于查询,如下所示。它首先检查第一列值是否匹配(在我的情况下是PK),如果它匹配,那么我们按列检查所有内容是否匹配。

任何差异都会将标志值设置为FALSE,我们返回。如果没有任何问题,则返回TRUE。在这种情况下,我使用=来比较值之间的相等而不是Equals(),因为我并不关心严格的相等。

使用UPDATE子句中的第一个列值(PK),生成的DataRows集用于WHERE数据库。

Imports System.Data

Class MyDataRowComparer
  Inherits EqualityComparer(Of DataRow)

Public Overloads Overrides Function Equals(x As DataRow, y As DataRow) As Boolean
    If x.Item(0).ToString().Equals(y.Item(0).ToString()) Then
        ' If PK matches then check column-wise.
        Dim Flag As Boolean = True
        For Counter As Integer = 0 To x.ItemArray.Count - 1
            If Not x.Item(Counter) = y.Item(Counter) Then
                Flag = False
            End If
        Next
        Return Flag
    Else
        ' Otherwise don't bother and just skip.
        Return False
    End If
End Function

...
End Class

1 个答案:

答案 0 :(得分:1)

class MyDataRowComparer : IEqualityComparer<DataRow>
{      

    public bool Equals(DataRow x, DataRow y)
    {
        return x["ColumnName"].Equals(y["ColumnName"]);
        // Can add more columns to the Comparison
    }

    public int GetHashCode(DataRow obj)
    {
        return obj["ColumnName"].GetHashCode();
       // Can add more columns to calculate HashCode
    }    
}

现在,Except语句将如下:

ChangedRows = destinationTable.AsEnumerable()
             .Except(origTable.AsEnumerable(), MyDataRowComparer)