提问人:sarvpk 提问时间:11/2/2023 最后编辑:sarvpk 更新时间:11/3/2023 访问量:140
EF Core 7.0 (PostgresSQL) 生成 IQueryable with RowNumber concept
EF Core 7.0 (PostgresSQL) build IQueryable with RowNumber concept
问:
我有一个场景,一个学生(由 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);
答:
0赞
sarvpk
11/3/2023
#1
我能够使用下面的查询来解决问题。使用 GroupJoin(而不是 Join)来处理“没有任何课程的学生”用例。当课程没有成绩时,请使用 null 合并运算符来修复此问题。这些学生将在分页中排在最后。我很惊讶 Max 在文本/字符串数据类型上工作。虽然这正在起作用,但我相信有更好的方法可以解决这个问题。
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
评论