2010-11-29 13 views
5

Tengo el siguiente conjunto de resultados que se generó como resultado de una consulta de Linq. Me gustaría convertir esto a un conjunto de resultados jerárquico. Las primeras dos columnas representarían la fila 'maestra', las columnas 3 y 4 representarían una lista secundaria de la fila maestra, y las columnas 5 y 6 representarían una segunda lista secundaria de la fila maestra. Las columnas que contienen el valor 1971 son las columnas de unión.Linq - ¿Cómo convertir de plano a jerárquico?

El resultado final debe ser un objeto maestro con una lista de contenedores (columnas G2) y una lista de impresoras (columnas G3).

¿Cómo sería la consulta para convertir esto a una forma jerárquica?

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 
+0

Solo para aclarar ... ¿Desea una jerarquía que se parece a un objeto - Cell> con Cell.Containers, Cell.SerialNumbers, Cell.PrinterNames (como colecciones)? – Tom

+0

¿Esto es Linq a Sql, Linq a EF, Linq a objetos o algo más? –

+0

@Tom - Quiero una jerarquía que se parece a Cell -> Cell.Containers and Cell -> PrinterNames. La columna del número de serie es una propiedad del contenedor. –

Respuesta

2

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; 

no lo he probado. pero estoy seguro de que se verá así.

+0

Había considerado GroupBy, pero eso no produciría las colecciones de datos g2 y g3 agrupados en cada elemento g1. Creo que tienes que hacer 3 pases en la lista original, pero tal vez estoy equivocado :) – Tom

1

Ok, esta es una pregunta bastante provocadora. He hecho un montón de acopio de datos en el pasado, y normalmente usaría un diccionario para mantener todos los valores únicos, y luego casarlos después.

Pediste LINQ, ahora no puedo pensar en un modo de un solo paso para hacer esto, así que tengo esto en su lugar, en 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) 

en cuenta que un buen montón de la el trabajo ha pasado por las extensiones Distinct() y ToLookup(). Espero que esto ayude, me gustaría ver si hay una forma más "LINQy": D

Cuestiones relacionadas