Reputation: 48522
I have the following result set that was generated as the result of a Linq query. I would like to convert this to a hierarchical result set. The first two columns would represent the 'master' row, columns 3 and 4 would represent a child list of the master row, and column 5 and 6 would represent a second child list of the master row. The columns containing the value 1971 are the joining columns.
The end result should be a master object with a list of containers (G2 columns) and a list of printers (G3 columns).
What would the query look like to convert this to hierarchical form?
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
Upvotes: 6
Views: 1446
Reputation: 4032
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;
haven't test it. but i'm sure its gonna look just like this.
Upvotes: 3
Reputation: 3374
Ok, this is quite a through provoking question. I've done a lot of data flattening in the past, and typically I'd use a Dictionary to keep all the unique values, then marry them up afterwards.
You asked for LINQ, now I cannot think of a single-pass way to do this, so I've got this instead, in 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)
Notice that quite a lot of the work has gone through the Distinct() and ToLookup() extensions. Hope this helps, I'd like to see if there is a more "LINQy" way :D
Upvotes: 1