2011-09-29 12 views
6

Tengo una lista enumerable que contenga un aplanado relación padre-hijo:LINQ proyección de mesa aplanado en los padres y objeto secundario gráfico

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

he definido una clase para niños y una clase de padres que incluye una propiedad List<Child> llamado Niños.

¿Puedo utilizar linq para crear en el gráfico de objetos con una instancia de la clase Parent por ParentGuid única, haciendo referencia a una lista poblada por los elementos secundarios asociados con ese elemento primario.

Algo a lo largo de las líneas de este (nota, este código no compila):

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

¿Este gráfico tiene solo 2 niveles de profundidad, es decir, 'Parent 1- * Child' sin ciclos? ¿O son los GUID globales y cada 'ChildGuid' podría ser un' ParentGuid'? – user7116

Respuesta

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}) 
    }); 

Usted debe ser capaz de hacer eso, pero el Children no puede ser una lista, que tiene que ser IEnumerable.

2

Creo que se puede utilizar GroupBy() (divulgación completa: no compilado):

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

Es necesario hacer frente con recursividad y recursividad infinita si tiene un bucle desde dentro de su colección plana. Linq no se puede usar para el problema completo, pero puede ayudar a regresar al hijo de un nodo específico.

3

Esta es la forma pre-Linq de hacerlo con un simple bucle.

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(); 

O usted podría utilizar GroupBy para conseguir un resultado similar.

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() 
} 

Es un lanzamiento que es más fácil de mantener. De cualquier manera, no vuelva a enumerar myFlattenedHierarchy dentro del bucle/consulta.

+0

Creo que su segundo ejemplo necesita un poco de ajuste, 'ParentGuid' y' ParentName' no son propiedades de 'row', ¿o me falta algo? –

+0

@DogEars sí, la fila no estaba en el alcance donde la estaba usando, editada para usar g en su lugar. ParentGuid y ParentName están allí ya que esta es una jerarquía aplanada (información principal y secundaria en cada fila). –

+0

¿Puede ayudarme con esta consulta de linq: http: //stackoverflow.com/questions/38120664/how-to-group-by-on-2-child-entities-and-get-total-of-both-this -child-entities –

0

Esto debería funcionar, muy similar al segundo ejemplo de David B pero no pude hacer que funcione sin un poco de fijación (agrupación por columna múltiple) así que lo he agregado aquí para el registro.

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() 
}; 
Cuestiones relacionadas