【问题标题】:LINQ to SQL - order by, group by and order by each group with skip and takeLINQ to SQL - 按每个组排序、分组和排序,并带有跳过和取走功能
【发布时间】:2018-05-31 18:29:50
【问题描述】:

这是 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() 和 Take()。但要执行 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 查询中完成所有这些操作。

【问题讨论】:

  • @IvanStoev 一切都好,不用担心

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


【解决方案1】:

您可以使用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 支持所有这些方法,因此您应该得到您想要的结果。

【讨论】:

  • 这行不通,因为您必须在 Skip 子句之前有 OrderBy。
  • @JakubHolovsky 并且在Skip 之前有OrderBy,但它不必在它之前。此限制存在于 SQL 中,因为对于 OFFSET FETCH 子句,它之前必须有 ORDER BY 并且对于从上述查询转换而来的 SQL,这是正确的。只是测试它。它会起作用的。
  • 确实有效。只是一个小的修正 - 第一个订单 (.OrderBy(s => s.MaxGrade)) 必须是降序的。
  • 确实有效,非常棒,谢谢。希望有一天有人在我之后阅读它时会理解它。
【解决方案2】:

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

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

【讨论】:

  • 明天试试听起来很有希望,希望它能与 LINQ to SQL 一起工作
  • 没有承诺 :) 您可能需要考虑使用存储过程来将数据传输降至最低。
猜你喜欢
  • 2012-02-11
  • 2013-06-21
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多