4

LINQ 让我发疯。为什么以下查询不返回重复项,而它只使用一个标识符?我的错误在哪里?

' generate some test-data '
Dim source As New DataTable
source.Columns.Add(New DataColumn("RowNumber", GetType(Int32)))
source.Columns.Add(New DataColumn("Value1", GetType(Int32)))
source.Columns.Add(New DataColumn("Value2", GetType(Int32)))
source.Columns.Add(New DataColumn("Text", GetType(String)))
Dim rnd As New Random()
For i As Int32 = 1 To 100
    Dim newRow = source.NewRow
    Dim value = rnd.Next(1, 20)
    newRow("RowNumber") = i
    newRow("Value1") = value
    newRow("Value2") = (value + 1)
    newRow("Text") = String.Format("RowNumber{0}-Text", i)
    source.Rows.Add(newRow)
Next
' following query does not work, it always has Count=0 '
' although it works with only one identifier '
Dim dupIdentifiers = From row In source
         Group row By grp = New With {.Val1 = row("Value1"), .Val2 = row("Value2")}
         Into Group
         Where Group.Count > 1
         Select idGroup = New With {grp.Val1, grp.Val2, Group.Count}

编辑:以下是完整的解决方案,感谢@Jon Skeet 的回答:)

Dim dupKeys = From row In source
        Group row By grp = New With {Key .Val1 = CInt(row("Value1")), Key .Val2 = CInt(row("Value2"))}
        Into Group Where Group.Count > 1
        Select RowNumber = CInt(Group.FirstOrDefault.Item("RowNumber"))

Dim dupRows = From row In source
        Join dupKey In dupKeys 
        On row("RowNumber") Equals dupKey 
        Select row

If dupRows.Any Then
    ' create a new DataTable from the first duplicate rows '
    Dim dest = dupRows.CopyToDataTable
End If

分组的主要问题是我必须使它们成为key属性。我上面代码中的下一个问题是从原始表中获取重复的行。因为几乎每一行都有重复(根据两个字段),结果 DataTable 包含 100 行中的 99 行,而不仅仅是 19 个重复值。我只需要选择第一个重复行并将它们与 PK 上的原始表连接起来。

Select RowNumber = CInt(Group.FirstOrDefault.Item("RowNumber"))

虽然这在我的情况下有效,但如果我只有复合键,也许有人可以解释我如何从原始表中只选择重复项。


编辑:我自己已经回答了问题的最后一部分,所以这就是我所需要的:

Dim dups = From row In source
         Group By grp = New With {Key .Value1 = CInt(row("Value1")), Key .Value2 = CInt(row("Value2"))}
         Into Group Where Group.Count > 1
         Let Text = Group.First.Item("Text")
         Select Group.First

If dups.Any Then
      Dim dest = dups.CopyToDataTable
End If

我需要Let-Keyword以将其他列保持在相同的上下文中并仅返回分组副本的第一行。通过这种方式,我可以使用CopyToDataTable从重复行创建 DataTable。

总体上只需几行代码(我可以保存第二个查询以查找原始表中的行)来查找多列上的重复项并创建它们的 DataTable。

4

1 回答 1

6

问题在于匿名类型在 VB 中的工作方式——默认情况下它们是可变的;仅Key包含用于散列和相等的属性。试试这个:

Group row By grp = New With {Key .Val1 = row("Value1"), Key .Val2 = row("Value2")}

(在 C# 中这不是问题 - C# 中的匿名类型在所有属性中始终是不可变的。)

于 2011-09-23T14:52:43.117 回答