Vb.net 使用LINQ在DataTable中查找更新的行
我正在VB.NET中构建一个应用程序,将数据从一个数据库推送到另一个数据库。源数据库是SQL Server,目标数据库是MySQL 我要做的是首先为每个数据库中的每个表创建数据表,我使用这些表进行比较。我以这样的方式编写查询,以便源数据表和目标数据表包含完全相同的列和值,从而使比较更容易 应用程序的这一面工作得很好。接下来我要做的是通过查找不存在的PK来查找目标数据库中不存在的行。然后,我将这些新行毫无问题地插入到目标数据库中 问题 我现在需要做的是查找每个表中已更新的行,即与目标DataTable中的对应行不相同的行。我已尝试使用Vb.net 使用LINQ在DataTable中查找更新的行,vb.net,linq,datatable,Vb.net,Linq,Datatable,我正在VB.NET中构建一个应用程序,将数据从一个数据库推送到另一个数据库。源数据库是SQL Server,目标数据库是MySQL 我要做的是首先为每个数据库中的每个表创建数据表,我使用这些表进行比较。我以这样的方式编写查询,以便源数据表和目标数据表包含完全相同的列和值,从而使比较更容易 应用程序的这一面工作得很好。接下来我要做的是通过查找不存在的PK来查找目标数据库中不存在的行。然后,我将这些新行毫无问题地插入到目标数据库中 问题 我现在需要做的是查找每个表中已更新的行,即与目标DataTab
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个表进行比较,所以这将是一个完全混乱的局面
理想情况下,我需要一个解决方案,其中它将考虑源表中的可变数量列,以便与基本相同的目标表进行比较,并简单地比较数据行是否相等
对于每个源行,目标表中都应该有一个对应的行,因为新行的添加是在检查更新的行之前执行的
我也愿意使用LINQ以外的方法来实现这一点。
解决方案 最后,我实现了一个用于查询的自定义比较器,如下所示。它首先检查第一列的值是否匹配(在我的例子中是PK),如果匹配,则按列检查所有内容是否匹配 任何差异都会将我们返回的标志值设置为FALSE。如果没有任何问题,则返回TRUE。在本例中,我使用
=
来比较值之间的相等,而不是Equals()
,因为我不关心严格的相等
结果数据行集用于使用WHERE
子句中的第一列值(PK)更新数据库
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
您需要一种方法来覆盖GetHashCode和Equals方法,或者提供一个EqualityComparer来成功,当前的方法进行对象引用比较,这将无法正常工作。对于IEnumerable更容易实现。Exception将在内部调用这些方法,因此在这种情况下需要重写DataRow类型谢谢,到目前为止这看起来不错。我可能会在
Equals
中的DataRow
中迭代列,比较它们的值,并设置一个标志,这样它就不会与数据紧密耦合。会让你知道我的进展。是的,你需要定制这个零件,并确保检查各种条件,以便它能够完全符合预期的要求。对于Equals,所有列值都应该进行比较,对于Hashcode,您可以使用位运算符“^如果这有一些问题,那么我有另一种使用Contains的方法,它将精确地给出给定列表中不存在的元素,以便在我将逻辑放入Equals()
后完美地完成这一技巧。我已将答案添加到我的原始问题中以供参考。
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
}
}
ChangedRows = destinationTable.AsEnumerable()
.Except(origTable.AsEnumerable(), MyDataRowComparer)