EF Core 7.0(PostgreSQL)build IQueryable with RowNumber concept

ohfgkhjo  于 2023-11-18  发布在  PostgreSQL
关注(0)|答案(1)|浏览(118)

我有一个场景,其中一个学生(由StudentId标识)有许多课程。每个课程都有StudentId(FK)和一个成绩(简单的文本类型)。我想构建一个IQueryable,当按降序排序时,按课程第一个成绩提取10个StudentId(跳过前5个)。
尝试下面的查询,但得到System.InvalidOperationException:LINQ表达式无法翻译

var studentQuery= context.Set<Student>().AsNoTracking().Where(x=>x.IsActive);
    var courseQuery= context.Set<Course>().AsNoTracking()
        .OrderByDescending(x => x.Grade)
        .GroupBy(x => x.StudentId)
        .SelectMany(x => x.Select((b, i) => new { b, rn = i + 1 }))
        .Where(x => x.rn == 1).Select(x => x.b);
    return studentQuery.Join
    (
        courseQuery,
        x => x.StudentId,
        y => y.StudentId,
        (a, b) => b
    )
    .Skip(5)
    .Take(10)
    .Select(x => x.StudentId);

字符串

zphenhs4

zphenhs41#

我能够使用下面的查询解决这个问题。使用GroupJoin(而不是Join)来处理“没有任何课程的学生”用例。当课程没有Grade时,使用null合并运算符来解决这个问题。这样的学生将在分页中排在最后。我很惊讶Max使用text/string数据类型。虽然这是有效的,但我相信有更好的方法来解决这个问题。

var studentQuery= context.Set<Student>().AsNoTracking().Where(x=>x.IsActive);   
var courseQuery= context.Set<Course>().AsNoTracking();

return studentQuery.GroupJoin
(
    courseQuery,
    x => x.StudentId,
    y => y.StudentId,
    (a, courses) => new { a.StudentId, courses }
)
.SelectMany(x => x.courses.DefaultIfEmpty(), (a, b) => new { a, b })
.GroupBy(x => x.a.StudentId)
.OrderByDescending(x => x.Max(y => y.b.Grade ?? string.Empty))
.Skip(5)
.Take(10)
.Select(x => x.Key);

字符串
生成的postgres SQL看起来像

SELECT r.student_id
FROM student AS r
LEFT JOIN (
    SELECT r0.grade, r0.student_id
    FROM course AS r0
) AS t ON r.student_id = t.student_id
WHERE r.is_active
GROUP BY r.student_id
ORDER BY max(COALESCE(t.grade,'')) DESC
LIMIT 10 OFFSET 5

相关问题