Linq-如何从平面转换为层次?

Linq-如何从平面转换为层次?,linq,Linq,我有以下作为Linq查询结果生成的结果集。我想将其转换为分层结果集。前两列表示“主”行,第3列和第4列表示主行的子列表,第5列和第6列表示主行的第二个子列表。包含值1971的列是连接列 最终结果应该是一个主对象,包含容器列表(G2列)和打印机列表(G3列) 要将其转换为层次结构形式,查询会是什么样子 G1_ID G1_CellName G2_ContainerID G2_ID G2_SerialNumber G3_ID G3_PrinterName 1971 Defau

我有以下作为Linq查询结果生成的结果集。我想将其转换为分层结果集。前两列表示“主”行,第3列和第4列表示主行的子列表,第5列和第6列表示主行的第二个子列表。包含值1971的列是连接列

最终结果应该是一个主对象,包含容器列表(G2列)和打印机列表(G3列)

要将其转换为层次结构形式,查询会是什么样子

G1_ID   G1_CellName  G2_ContainerID G2_ID   G2_SerialNumber G3_ID      G3_PrinterName
1971    Default Cell    1935           1971    1101929         1971       PBG-PrtEmulator1
1971    Default Cell    1936           1971    1101930         1971       PBG-PrtEmulator1
1971    Default Cell    2189           1971    1102183         1971       PBG-PrtEmulator1

好的,这是一个非常发人深省的问题。我过去做过很多数据扁平化工作,通常我会使用字典保留所有唯一的值,然后将它们合并

你问LINQ,现在我想不出一个单一的传球方式来做这件事,所以我得到了这个,用VB

Private Class FlatObj
    Public Property G1_ID As Integer
    Public Property G1_CellName As String
    Public Property G2_ContainerID As Integer
    Public Property G2_ID As Integer
    Public Property G2_SerialNumber As Integer
    Public Property G3_ID As Integer
    Public Property G3_PrinterName As String
End Class

Private Class G1
    Public Property ID As Integer
    Public Property CellName As String
    Public Property Containers As New List(Of G2)()
    Public Property PrinterNames As New List(Of G3)()
    Public Overrides Function Equals(ByVal obj As Object) As Boolean
        Return ID.Equals(CType(obj, G1).ID)
    End Function
    Public Overrides Function GetHashCode() As Integer
        Return ID.GetHashCode()
    End Function
End Class

Private Class G2
    Public Property fID As Integer
    Public Property ContainerID As Integer
    Public Property SerialNumber As Integer
    Public Overrides Function Equals(ByVal obj As Object) As Boolean
        Return ContainerID.Equals(CType(obj, G2).ContainerID)
    End Function
    Public Overrides Function GetHashCode() As Integer
        Return ContainerID.GetHashCode()
    End Function
End Class

Private Class G3
    Public Property fID As Integer
    Public Property PrinterName As String
    Public Overrides Function Equals(ByVal obj As Object) As Boolean
        Return PrinterName.Equals(CType(obj, G3).PrinterName)
    End Function
    Public Overrides Function GetHashCode() As Integer
        Return PrinterName.GetHashCode()
    End Function
End Class

Dim fromDb As New List(Of FlatObj) From
    {
        New FlatObj() With {.G1_ID = 1971, .G1_CellName = "Default Cell", .G2_ContainerID = 1935, .G2_ID = 1971, .G2_SerialNumber = 1101929, .G3_ID = 1971, .G3_PrinterName = "PBG-PrtEmulator1"},
        New FlatObj() With {.G1_ID = 1971, .G1_CellName = "Default Cell", .G2_ContainerID = 1936, .G2_ID = 1971, .G2_SerialNumber = 1101930, .G3_ID = 1971, .G3_PrinterName = "PBG-PrtEmulator1"},
        New FlatObj() With {.G1_ID = 1971, .G1_CellName = "Default Cell", .G2_ContainerID = 2189, .G2_ID = 1971, .G2_SerialNumber = 1102183, .G3_ID = 1971, .G3_PrinterName = "PBG-PrtEmulator1"}
    }

Dim g1s = fromDb.Select(Function(x) New G1 With
                                    {
                                        .ID = x.G1_ID,
                                        .CellName = x.G1_CellName
                                    }).Distinct().ToList()
Dim g2s = fromDb.Select(Function(x) New G2 With
                                    {
                                        .fID = x.G2_ID,
                                        .ContainerID = x.G2_ContainerID,
                                        .SerialNumber = x.G2_SerialNumber
                                    }).Distinct().ToLookup(Function(x) x.fID)
Dim g3s = fromDb.Select(Function(x) New G3 With
                                    {
                                        .fID = x.G3_ID,
                                        .PrinterName = x.G3_PrinterName
                                    }).Distinct().ToLookup(Function(x) x.fID)
g1s.ForEach(Sub(g)
                g.Containers.AddRange(g2s(g.ID))
                g.PrinterNames.AddRange(g3s(g.ID))
            End Sub)
注意,相当多的工作都是通过Distinct()和ToLookup()扩展完成的。希望这有帮助,我想看看是否有更“灵巧”的方法:d

groupby

var result = from eachData in data
group eachData by new{ eachData .G1_ID, eachData .G1_CellName }
into g1
from eachG1 in g1
group eachG1 by new { eachG1.G2_..., eachG1.G2_... }
into g2
for eachG2 in g2
group eachG2 by new { eachG2.G3_... }
into g3
select g3;

我还没有测试过。但我确信它看起来会像这样。

只是为了澄清一下。。。您想要一个类似于object-Cell>的层次结构,其中包含Cell.Containers、Cell.SerialNumber、Cell.PrinterNames(作为集合)?这是Linq到Sql、Linq到EF、Linq到对象还是其他什么?@Tom-我想要一个类似于Cell->Cell.Containers和Cell->PrinterNames的层次结构。序列号列是容器的一个属性。@DoctaJonez-stright Linq。执行L2S查询后,此查询将在客户端上执行。我将把结果转换成IEnumerable,然后创建分层结果。我考虑过GroupBy,但这不会产生分组到每个g1元素中的g2和g3数据集合。我认为你必须在原来的名单上通过3次,但也许我错了:)