LINQ to SQL - 按每个组排序,分组和排序,并跳过

时间:2018-05-31 18:29:50

标签: c# linq linq-to-sql entity-framework-6

这是Jon Skeet已经回答的问题的扩展,你可以find here.

所需的结果如下:

A 100
A 80
B 80
B 50
B 40
C 70
C 30

考虑到你有以下课程:

public class Student
{
    public string Name { get; set; } 
    public int Grade { get; set; }
}

获得结果(在理想情况下)可以使用Jon Skeet的答案来完成:

var query = grades.GroupBy(student => student.Name)
                  .Select(group => 
                        new { Name = group.Key,
                              Students = group.OrderByDescending(x => x.Grade) })
                  .OrderBy(group => group.Students.FirstOrDefault().Grade);

但是在我的情况下,我还必须在查询中支持分页。这意味着执行 SelectMany(),然后执行跳过()执行()。但要做 Skip(),您必须应用 OrderBy()。这是我的订单再次破坏的地方,因为我需要保留我在 SelectMany()之后获得的订单。

如何实现这一目标?

var query = grades.GroupBy(student => student.Name)
                  .Select(group => 
                        new { Name = group.Key,
                              Students = group.OrderByDescending(x => x.Grade) })
                  .OrderBy(group => group.Students.FirstOrDefault().Grade).SelectMany(s => s.Students).OrderBy(something magical that doesn't break ordering).Skip(s => skip).Take(t => take);

我知道我可以在我的查询具体化时再次手动排序记录,但我想避免这种情况,并在从LINQ翻译的一个SQL查询中完成所有这些操作。

2 个答案:

答案 0 :(得分:2)

您可以使用Max采用其他方法,而不是对每个组进行排序并获取第一个值。之后,您可以按最高等级,姓名(如果两名学生具有相同的最高成绩)和成绩订购:

var query = c.Customers
    .GroupBy(s => s.Name, (k, g) => g
        .Select(s => new { MaxGrade = g.Max(s2 => s2.Grade), Student = s }))
    .SelectMany(s => s)
    .OrderBy(s => s.MaxGrade)
    .ThenBy(s => s.Student.Name)
    .ThenByDescending(s => s.Student.Grade)
    .Select(s => s.Student)
    .Skip(toSkip)
    .Take(toTake)
    .ToList();

EF6支持所有这些方法,因此您应该得到所需的结果。

答案 1 :(得分:0)

只需重新索引列表结果并在返回之前删除索引。

var query = grades.GroupBy(student => student.Name)
       .Select(group => 
               new { Name = group.Key, 
                    Students = group.OrderByDescending(x => x.Grade)
                   })
       .OrderBy(group => group.Students.FirstOrDefault().Grade)
       .SelectMany(s => s.Students)
       .Select((obj,index) => new {obj,index})
       .OrderBy(newindex => newindex.index)
       .Skip(s => skip).Take(t => take)
       .Select(final=> final.obj);