2011-09-29 4 views
6

Ho una lista enumerabile che contiene un appiattita rapporto genitore-figlio:proiezione Linq del tavolo appiattito nella genitore e bambino oggetto grafico

ParentGuid1, ParentName1, ChildGuid1, ChildName1 
ParentGuid1, ParentName1, ChildGuid2, ChildName2 
ParentGuid2, ParentName2, ChildGuid3, ChildName3 
ParentGuid2, ParentName2, ChildGuid4, ChildName4 

Ho definito una classe figlia e una classe genitore che include una proprietà List<Child> chiamato bambini.

Posso usare linq per creare sul grafico oggetto con un'istanza della classe Parent per ParentGuid univoco, facendo riferimento a un elenco popolato dai figli associati a quel genitore.

Qualcosa sulla falsariga di questo (nota, questo codice non viene compilato):

myFlattenedHierarchy.Select(p => new Parent 
    {Guid = p.ParentGuid, 
    Name = p.ParentName, 
    Children = myFlattenedHierarchy.Where(c => c.ParentGuid == p.ParentGuid).Select(c => new Child{Guid = c.ChildGuid, Name = c.ChildName}) 
    }); 
+0

Questo grafico ha solo 2 livelli di profondità, ad esempio 'Parent 1- * Child' senza cicli? O il GUID è globale e ogni 'ChildGuid' potrebbe essere un' ParentGuid'? – user7116

risposta

5
myFlattenedHierarchy.Select(p => new Parent 
    {Guid = p.ParentGuid, 
    Name = p.ParentName, 
    Children = myFlattenedHierarchy.Where(c => c.ParentGuid == p.ParentGuid).Select(c => new Child{Guid = c.ChildGuid, Name = c.ChildName}) 
    }); 

Si dovrebbe essere in grado di farlo, ma la Children non può essere un elenco, che deve essere IEnumerable.

2

io credo che si possa utilizzare GroupBy() (full disclosure: non compilato):

myFlattenedHierarchy.GroupBy(row => row.ParentGuid) 
    .Select(group => new Parent 
     { 
      Guid = group.Key.ParentGuid, 
      Name = group.Key.ParentName, 
      Children = myFlattenedHierarchy.Where(c => c.ParentGuid == group.Key.ParentGuid) 
       .Select(c => new Child{ Guid = c.ChildGuid, Name = c.ChildName }) 
       .ToList() 
     }); 
0

Devi affrontare con ricorsività e ricorsività infinita se hai un loop all'interno della tua collezione flat. Linq non può essere utilizzato per il problema completo ma può aiutare a restituire il figlio di un nodo specifico.

3

Ecco il modo pre-Linq per farlo con un semplice ciclo.

Dictionary<Guid, Parent> parents = new Dictionary<Guid, Parent>(); 
foreach(RowType row in myFlattenedHierarchy) //just enumerate once 
{ 
    if (!parents.ContainsKey(row.ParentGuid) 
    { 
    Parent newParent = new Parent(row); 
    parents[row.ParentGuid] = newParent; 
    } 

    Child newChild = new Child(row); 

    Parent theParent = parents[row.ParentGuid]; 
    theParent.Children.Add(newChild); 
} 

List<Parent> result = parents.Values.ToList(); 

Oppure si potrebbe usare GroupBy per ottenere un risultato simile.

from row in myFlattenedHierarchy 
group row by row.ParentGuid into g 
select new Parent() 
{ 
    Guid = g.Key, 
    Name = g.First().ParentName, 
    Children = 
    (
    from childRow in g 
    select new Child() 
    { 
     Guid = childrow.ChildGuid, 
     Name = childrow.ChildName 
    } 
).ToList() 
} 

È un problema che è più manutenibile. In ogni caso, non ri-enumerare myFlattenedHierarchy all'interno del ciclo/query.

+0

Penso che il tuo secondo esempio abbia bisogno di qualche ritocco, 'ParentGuid' e' ParentName' non sono proprietà di 'row', o mi manca qualcosa? –

+0

@DogEars sì, la riga non era compresa nell'ambito in cui la stavo usando, modificata per utilizzare g invece. ParentGuid e ParentName ci sono poiché si tratta di una gerarchia piatta (informazioni padre e figlio in ogni riga). –

+0

Puoi aiutarmi con questa query linq: http: //stackoverflow.com/questions/38120664/how-to-group-by-on-2-child-entities-and-get-total-of-both-this -child-entità –

0

Questo dovrebbe funzionare, molto simile al secondo esempio di David B, ma non sono riuscito a farlo funzionare senza un po 'di correzione (raggruppamento per colonna multipla) quindi l'ho aggiunto qui per la registrazione.

from row in myFlattenedHierarchy 
group row by new { row.ParentGuid, row.ParentName } into g 
select new Parent() 
{ 
    Guid = g.Key.ParentGuid, 
    Name = g.Key.ParentName, 
    Children = 
    (
    from childRow in g 
    select new Child() 
    { 
     Guid = childRow.ChildGuid, 
     Name = childRow.ChildName 
    } 
).ToList() 
}; 
Problemi correlati