我正在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
答案 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)