将扁平化表格的Linq投影到父子对象图中

6

我有一个包含扁平化的父子关系的可枚举列表:

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

我已经定义了一个子类和一个父类,其中包括一个名为Children的List<Child>属性。

我能否使用LINQ创建一个对象图,每个唯一的ParentGuid实例引用一个由与该父级关联的子级填充的列表的父级类。

类似于这样的代码(请注意,此代码不能编译):

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

这个图仅有两个层级,即Parent 1-* Child且没有环路吗?还是GUID是全局的,每个ChildGuid都可以是一个ParentGuid - user7116
5个回答

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

你应该能够做到这一点,但是Children不能是列表,它必须是IEnumerable

3

以下是使用简单循环的Linq之前的方法。

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

或者您可以使用GroupBy来获得类似的结果。
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()
}

很难说哪种方式更易维护。无论如何,在循环/查询中不要重新枚举myFlattenedHierarchy。

我认为你的第二个例子需要稍微调整一下,ParentGuidParentName不是row的属性,或者我漏掉了什么? - Dog Ears
@DogEars 是的,在我使用它的地方,行不在范围内 - 已编辑为使用 g。ParentGuid 和 ParentName 存在,因为这是一个扁平化层次结构(每行中包含父级和子级信息)。 - Amy B
你能帮我解决这个linq查询吗:http://stackoverflow.com/questions/38120664/how-to-group-by-on-2-child-entities-and-get-total-of-both-this-child-entities - Learning-Overthinker-Confused

2
我相信你可以使用GroupBy()函数(完整的披露:未编译):
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

这应该可以工作,与David B的第二个示例非常相似,但我无法在没有一些修复(按多列分组)的情况下使其工作,因此我在此添加了它以备记录。

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

0
如果您的平面集合中存在循环,您需要处理递归和无限递归。Linq不能用于解决完整的问题,但可以帮助返回特定节点的子节点。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接