2016-04-15 30 views
3

我正在编写一个简单的测试应用程序来演示如何对从EF上下文获取的列表进行排序。Linq在多个层上对IEnumerable进行排序

的 “目标” 是获取一个列表,通过Student.Name排序,然后Subject.Name

public class Student 
{ 
    public string Name {get;set;} 
    public List<ExamScore> ExamScores{get;set;} 
} 

public class Subject 
{ 
    public string Name{get;set;} 
} 

public class ExamScore 
{ 
    public Subject Subject{get;set;} 
    public int Score{get;set;} 
} 

第一级排序很简单:

var list = con.Students 
    .Include(e => e.ExamScores 
     .Select(s => s.Subjects)) 
    .OrderBy(x => x.Name) //student.Name 
    .ToList(); 

但添加了一个新的水平令我困惑。

var list = con.Students 
    .Include(e => e.ExamScores 
     .Select(s => s.Subjects)) 
    .OrderBy(x => x.Name) //student.Name 
    .ThenBy(y => y.ExamScores.???) //subject name??? 
    .ToList(); 

输入

Student{"Jannie", ExamScore{ Subject{"Math"}, 90}} 
Student{"Jannie", ExamScore{ Subject{"History"}, 70}} 
Student{"Jannie", ExamScore{ Subject{"Science"}, 90}} 

Student{"Koos", ExamScore{ Subject{"Xhosa"}, 83}} 
Student{"Koos", ExamScore{ Subject{"Afrikaans"}, 74}} 
Student{"Koos", ExamScore{ Subject{"English"}, 78}} 

Student{"Pieter", ExamScore{ Subject{"Afrikaans"}, 65}} 
Student{"Pieter", ExamScore{ Subject{"History"}, 80}} 
Student{"Pieter", ExamScore{ Subject{"Math"}, 70}} 

Student{"Sannie", ExamScore{ Subject{"Science"}, 60}} 
Student{"Sannie", ExamScore{ Subject{"Math"}, 55}} 
Student{"Sannie", ExamScore{ Subject{"Biology"}, 75}} 

Student{"Magriet", ExamScore{ Subject{"Biology"}, 75}} 
Student{"Magriet", ExamScore{ Subject{"English"}, 80}} 
Student{"Magriet", ExamScore{ Subject{"Science"}, 90}} 

预计输出

Student{"Jannie", ExamScore{ Subject{"History"}, 70}} 
Student{"Jannie", ExamScore{ Subject{"Math"}, 90}} 
Student{"Jannie", ExamScore{ Subject{"Science"}, 90}} 

Student{"Koos", ExamScore{ Subject{"Afrikaans"}, 74}} 
Student{"Koos", ExamScore{ Subject{"English"}, 78}} 
Student{"Koos", ExamScore{ Subject{"Xhosa"}, 83}} 

Student{"Magriet", ExamScore{ Subject{"Biology"}, 75}} 
Student{"Magriet", ExamScore{ Subject{"English"}, 80}} 
Student{"Magriet", ExamScore{ Subject{"Science"}, 90}} 

Student{"Pieter", ExamScore{ Subject{"Afrikaans"}, 65}} 
Student{"Pieter", ExamScore{ Subject{"History"}, 80}} 
Student{"Pieter", ExamScore{ Subject{"Math"}, 70}} 

Student{"Sannie", ExamScore{ Subject{"Biology"}, 75}} 
Student{"Sannie", ExamScore{ Subject{"Math"}, 55}} 
Student{"Sannie", ExamScore{ Subject{"Science"}, 60}} 
+1

你能举一个预期产出的例子吗? – bit

+0

收集的学生*包含*科目的集合,所以不可能根据得分过滤学生收集 –

+0

@bit已完成。 –

回答

7

你需要做的是首先拼合的学生为>主题的关系,然后你就可以在排序两者:

var list = con.Students.Include(e => e.ExamScores.Select(s => s.Subjects)) 
    .SelectMany(student => student.ExamScores.Select(score => new { Student = student, Score = score })) 
    .OrderBy(x => x.Student.Name) 
    .ThenBy(x => x.Score.Subject.Name); 

这将生成一个匿名对象的枚举,其中包含按学生名称和主题名称排序的Student和Score。

+0

谢谢!完美工作。 –

1

您可以按照Dmitri的建议使用.SelectMany()。这里有一个编译工作的例子来说明他的回答(我在做这个,而他回答,所以我不想浪费它,但他是正确的答案,我当然有upvoted它):

using System; 
using System.Collections.Generic; 
using System.Linq; 

namespace Demo 
{ 
    public class Student 
    { 
     public string Name { get; set; } 
     public List<ExamScore> ExamScores { get; set; } 
    } 

    public class Subject 
    { 
     public string Name { get; set; } 
    } 

    public class ExamScore 
    { 
     public Subject Subject 
     { 
      get; 
      set; 
     } 

     public int Score { get; set; } 
    } 

    static class Program 
    { 
     static void Main() 
     { 
      var students = new List<Student> 
      { 
       new Student 
       { 
        Name = "C", 
        ExamScores = new List<ExamScore> 
        { 
         new ExamScore {Subject = new Subject {Name = "Z"}, Score = 1}, 
         new ExamScore {Subject = new Subject {Name = "Y"}, Score = 2}, 
         new ExamScore {Subject = new Subject {Name = "X"}, Score = 3}, 
        } 
       }, 

       new Student 
       { 
        Name = "B", 
        ExamScores = new List<ExamScore> 
        { 
         new ExamScore {Subject = new Subject {Name = "Z"}, Score = 4}, 
         new ExamScore {Subject = new Subject {Name = "Y"}, Score = 5}, 
         new ExamScore {Subject = new Subject {Name = "X"}, Score = 6}, 
        } 
       }, 

       new Student 
       { 
        Name = "A", 
        ExamScores = new List<ExamScore> 
        { 
         new ExamScore {Subject = new Subject {Name = "Z"}, Score = 7}, 
         new ExamScore {Subject = new Subject {Name = "Y"}, Score = 8}, 
         new ExamScore {Subject = new Subject {Name = "X"}, Score = 9}, 
        } 
       } 
      }; 

      var orderedStudents = 
       students.SelectMany(s => s.ExamScores.Select(e => new {Student = s, ExamScore = e})) 
       .OrderBy(x => x.Student.Name) 
       .ThenBy(x => x.ExamScore.Subject.Name); 

      foreach (var item in orderedStudents) 
      { 
       Console.WriteLine($"{item.Student.Name} {item.ExamScore.Subject.Name} {item.ExamScore.Score}"); 
      } 
     } 
    } 
} 
+0

我可以看到的唯一区别是,“.include(x => x.ExamScores.Select(s => s.Subject))”将从您的示例中删除。答案似乎相同,否则。那是对的吗。 –

+0

请解释“Console.WriteLine($”{item.Student.Name} ...“部分,这不会在我身上编译 –

+1

@AtronSeige这是C#6特性(Visual Studio 2015)。对于早期版本,使用'Console.WriteLine(“{0} {1} {2}”,item.Student.Name,item.ExamScore.Subject.Name,item.ExamScore.Score);'。 –

相关问题