从子集合中获取具有层次结构的父集合

时间:2018-04-05 20:34:45

标签: c# linq

我遇到了问题。

我有一个孙子系列,我想使用LINQ变成祖父母对象的集合。子对象具有父级的导航属性。我曾经用祖父母的名字尝过一组,但后来我被一根绳子困住了。

我的祖父母班级看起来像这样:

GrandParent类

 public class GrandParentBLL
{
    public GrandParentBLL()
    {
        Parents= new List<Parent>();
    }

    public int ID { get; set; }
    public int Number { get; set; }
    public string Name { get; set; }
    public ICollection<ParentBLL> Parents{ get; set; }

}

儿童班:

Child class

 public class ParentBLL
{
    public ParentBLL()
    {
        Children= new List<Child>();
    }

    public int ID { get; set; }
    public int Number { get; set; }
    public string Name { get; set; }
    public GrandParentBLL GrandParent { get; set; }
    public ICollection<ChildBLL> Children { get; set; }

}

GrandChild班:

public class ChildBLL
{
    public ChildBLL()
    {

    }

    public int ID { get; set; }
    public int Number { get; set; }
    public string Name { get; set; }
    public ParentBLL Parent{ get; set; }

}

现在我得到了一个孙子对象列表,其中每个对象可以有不同的父对象或祖父对象。我可以使用navigation属性访问父级。我想获得一个祖父母对象列表,其中包含每个祖父母的相应子集合。

我尝试了以下内容:

var grandparents = Children.GroupBy(x => x.Parent.GrandParent).Select(d=>d.Key).ToList();

然后我为grandChildren集合中的每个对象获得一个祖父对象,尽管只有2个不同的祖父母。

2 个答案:

答案 0 :(得分:1)

如果您想获得唯一的granparent实体,您的查询应该是

 var grandparents = grandChildren
                    .Select(c => c.Parent) // --> get all the grand children's parents
                    .Select(p => p.GrandParent) // --> get all the GrandParents from each of the Parents above
                    .Distinct();

更新:因此,如果父对象不包含子集合,则根据您的注释以及接受的答案。这是一种水合父对象的方法:

IEnumerable<ParentBLL> parents = grandChildren
                       .Select(gc => gc.Parent)
                       .Distinct()
                       .Pipe(p => p.GrandChildren = grandChildren.Where(gc => gc.Parent.ID == p.ID).ToList());

IEnumerable<GrandParentBLL> grandparents = parents
                            .Select(p => p.GrandParent).Distinct()
                            .Pipe( gp => gp.Parents = parents.Where(p => p.GrandParent.ID == gp.ID).ToList());

此解决方案使用.Pipe,“对源序列中的每个元素执行给定的操作并生成它”。这是MoreLinq的扩展方法。所以你需要添加对这个包的引用。

答案 1 :(得分:1)

从您的示例中不清楚每个班级是否有自己的直系孩子的集合。如果他们这样做,答案很简单:

Dictionary<GrandParent,List<Child>> results = grandparents.ToDictionary
(
    g => g,
    g => g.Parents.SelectMany( p => p.Children ).ToList()
);

不太容易

如果父母不了解自己的孩子,并且只有孩子知道他们的直系父母,那么还有更多的工作要做,我将分三步完成:

步骤1.首先获得父母和我们可以重复使用的祖父母的调查员:

var parents = children.Select( c => c.Parent ).Distinct();
var grandParents = parents
    .Select( p => p.GrandParent )
    .Distinct();

步骤2.现在修改代码以将grandParents更改为Dictionary<GrandParent,List<Parent>>

var children = new List<ChildBLL>();
var parents = children.Select( c => c.Parent ).Distinct();
var grandParents = parents
    .Select( p => p.GrandParent )
    .Distinct()
    .ToDictionary
    ( 
        g => g, 
        g => parents.Where( p => p.GrandParent == g )
    );

步骤3.添加代码以将Dictionary<GrandParent,List<Parent>>转换为Dictionary<Grandparent,List<Child>>

var parents = children.Select( c => c.Parent ).Distinct();
var grandParents = parents
    .Select( p => p.GrandParent )
    .Distinct()
    .ToDictionary
    ( 
        g => g, 
        g => parents.Where( p => p.GrandParent == g )
    )
    .ToDictionary
    (
        pair => pair.Key,
        pair => pair.Value.SelectMany
        ( 
            p => children.Where( c => c.Parent == p ) 
        )
    );

当你完成后,你会得到一个字典,其中键是GrandParent,值是其孙子的List<Children>