C# 将层次结构展平为特定排序的列表

C# 将层次结构展平为特定排序的列表,c#,linq,ef-code-first,C#,Linq,Ef Code First,我有一个简单的人员层次结构(EntityFramework Codefirst) 公共类人物 { [关键] 公共int Id{get;set;} public int?ParentId{get;set;} [必需] 公共字符串名称{get;set;} //航行 [ForeignKey(“ParentId”)] 公共虚拟人父项{get;set;} 公共虚拟ICollection子项{get;set;} } 我的目标: 我需要一个方法来创建一个列表,该列表(1)按父级进行聚类,并(2)按名称的字母

我有一个简单的人员层次结构(EntityFramework Codefirst)

公共类人物
{
[关键]
公共int Id{get;set;}
public int?ParentId{get;set;}
[必需]
公共字符串名称{get;set;}
//航行
[ForeignKey(“ParentId”)]
公共虚拟人父项{get;set;}
公共虚拟ICollection子项{get;set;}
}
我的目标:

我需要一个方法来创建一个
列表
,该列表(1)按父级进行聚类,并(2)按名称的字母顺序对每个级别进行排序:

示例输出:

  • 阿尔弗雷德
  • 本(阿尔弗雷德之子)
  • 马里恩(阿尔弗雷德的女儿)
  • 拉尔夫(阿尔弗雷德之子)
  • 克里斯汀
  • 爱丽(克里斯蒂娜的女儿)
  • Dave
  • 多丽丝
  • 詹姆斯(多丽丝之子)
  • 克拉斯(多丽丝之子)
阿尔弗雷德、克里斯汀、戴夫和多丽丝都是父母。它们按字母顺序排列。他们都有孩子(戴夫除外)。子项也按字母顺序排序(在列表中,它们与父项一起显示为“分组”)。“的儿子”和“的女儿”只是你们的评论(我不需要在结果列表中)

我可以很容易地创建这种带有嵌套循环的列表。但我相信这不会是非常有效或优雅的。但也许我错了

你们有没有人有好的想法/建议(也许是LINQ)?谢谢

哦,我应该提到的是,层次结构是2级的。所以,只有父母和孩子(但没有孙子)

这样行吗

List<Person> sortPeople(List<Person> people)
{
    List<Person> result = new List<Person>();

    foreach (Person p in people.OrderBy(_ => _.Name).ToList())
    {
        result.Add(p);
        result.AddRange(p.Children.OrderBy(_ => _.Name).ToList());
    }

    return result;
}
列出排序人员(列出人员)
{
列表结果=新列表();
foreach(people.OrderBy(\u=>\ uu.Name.ToList()中的Person p)
{
结果:添加(p);
result.AddRange(p.Children.OrderBy(=>\u0.Name.ToList());
}
返回结果;
}
这样行吗

List<Person> sortPeople(List<Person> people)
{
    List<Person> result = new List<Person>();

    foreach (Person p in people.OrderBy(_ => _.Name).ToList())
    {
        result.Add(p);
        result.AddRange(p.Children.OrderBy(_ => _.Name).ToList());
    }

    return result;
}
列出排序人员(列出人员)
{
列表结果=新列表();
foreach(people.OrderBy(\u=>\ uu.Name.ToList()中的Person p)
{
结果:添加(p);
result.AddRange(p.Children.OrderBy(=>\u0.Name.ToList());
}
返回结果;
}

这只在有两个级别的情况下有效,我不知道如何将其转换为SQL:

var parents = people.Select(person=>person.Parent == null);
var parentsWithChildrenGrouped = 
    parents
    .SelectMany(parent=>parent.Children.Select(child=>new {Parent = parent, Child = child, Out = child}))
    .Union(parents.Select(parent => new {Parent = parent, Child = null, Out = parent}))
    .OrderBy(x=>x.Parent).ThenBy(x=>x.Child)
    .Select(x=>x.Out);
此查询首先创建一个列表,其中每个项都有子项和父项。然后,它首先根据父对象进行排序,然后根据子对象进行排序。然后是第三个“out”属性,它定义了行的用途


我知道这可以很容易地转换为有效的SQL,但我不确定EF将如何处理它。

这只在有两个级别的情况下有效,我不知道如何转换为SQL:

var parents = people.Select(person=>person.Parent == null);
var parentsWithChildrenGrouped = 
    parents
    .SelectMany(parent=>parent.Children.Select(child=>new {Parent = parent, Child = child, Out = child}))
    .Union(parents.Select(parent => new {Parent = parent, Child = null, Out = parent}))
    .OrderBy(x=>x.Parent).ThenBy(x=>x.Child)
    .Select(x=>x.Out);
var sortedPeople = 
    from p in people
    orderby (p.Parent == null ? p.Name : p.Parent.Name),
      p.Parent == null ? 1 : 2, // this ensures parents appear before children
      p.Name
    select p;
此查询首先创建一个列表,其中每个项都有子项和父项。然后,它首先根据父对象进行排序,然后根据子对象进行排序。然后是第三个“out”属性,它定义了行的用途


我知道这可以很容易地转换为有效的SQL,但我不确定EF将如何处理它。

这正是我想要的!!谢谢你,克林特!这里面有孩子吗?是的,只要他们在“人”里面,那正是我想要的!!谢谢你,克林特!这是孩子们的名单吗?是的,只要他们在“人物”嗨,谢谢你的回答。这就是我会想到的。又好又干净。但我更喜欢克林特的答案。但再次感谢!嗨,阿特姆,谢谢你的回答。这就是我会想到的。又好又干净。但我更喜欢克林特的答案。但再次感谢!嗨,欣快,到目前为止我还没有尝试过你的解决方案。我第一次看到Clint的答案,就知道这就是我一直在寻找的代码。不过你的头发看起来也很棒。非常感谢你的努力!嗨,欣快,到目前为止我还没有尝试过你的解决方案。我第一次看到Clint的答案,就知道这就是我一直在寻找的代码。不过你的头发看起来也很棒。非常感谢你的努力!
var sortedPeople = 
    from p in people
    orderby (p.Parent == null ? p.Name : p.Parent.Name),
      p.Parent == null ? 1 : 2, // this ensures parents appear before children
      p.Name
    select p;