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

时间:2015-04-07 05:46:24

标签: c# linq ef-code-first

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

public class Person
{
    [Key]
    public int Id { get; set; }

    public int? ParentId { get; set; }

    [Required]
    public string Name { get; set; }

    // Navigation

    [ForeignKey("ParentId")]
    public virtual Person Parent { get; set; }

    public virtual ICollection<Person> Children { get; set; }
}

我的目标:

我需要一个创建List<Person>的方法,该方法是(1)由父母聚类,(2)按字母顺序按名称在每个级别上排序

示例输出:

  • 阿尔弗雷德
  • Ben(Alfred的儿子)
  • 马里昂(阿尔弗雷德的女儿)
  • 拉尔夫(阿尔弗雷德的儿子)
  • Ally(Christine的女儿)
  • 戴夫
  • 多丽丝
  • 詹姆斯(多丽丝的儿子)
  • Klaas(多丽丝的儿子)
阿尔弗雷德,克莉丝汀,戴夫和多丽丝都是父母。它们按字母顺序排序。所有人都有孩子(除了戴夫)。孩子们也按字母顺序排序(在列表中他们看起来与他们的父母“分组”)。 “儿子”和“女儿”只是对你们的评论(在结果列表中我不需要这个)。

我可以使用嵌套循环轻松创建这种列表。但我相信这不会非常有效或优雅。但也许我错了。

你们中的任何人都有一个好主意/建议(也许是LINQ)?谢谢!

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

3 个答案:

答案 0 :(得分: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;
}

答案 1 :(得分:2)

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;

答案 2 :(得分:1)

只有在有两个级别并且我不知道这如何转换为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);

此查询首先创建列表,其中每个项目都包含子项及其父项。然后它首先根据父母进行排序,然后按子进行排序。然后有第三个&#34; out&#34;定义行的用途的属性。

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