课表查询中最明显的性能优化。

将混合考场查询从“加载整个学期的考场、座位、教师、班级后在内存筛选”,改为在数据库中按班级、教师或教室直接筛选。
改为窄字段投影,避免创建大量 EF 实体和关系对象。
添加查询标签,便于后续在 MySQL 慢查询和链路追踪中定位。
保留现有 HybridCache/可选 Redis 缓存体系,无需新增依赖或数据库迁移。
增加教室、无关教室、监考教师三种回归场景。
This commit is contained in:
2026-07-31 07:56:30 +08:00 Unverified
parent 7bcfa1a7a4
commit a369b4fe02
2 changed files with 103 additions and 76 deletions
@@ -1,6 +1,7 @@
using Jiaowu.Api.Domain.Academic;
using Jiaowu.Api.Infrastructure.Exams;
using Jiaowu.Api.Infrastructure.Persistence;
using Jiaowu.Api.Infrastructure.Timetables;
using Microsoft.Data.Sqlite;
using Microsoft.EntityFrameworkCore;
@@ -55,6 +56,48 @@ public sealed class ExamArrangementServiceTests
Assert.Contains("1个教学班场次处理完成", result.Message);
Assert.Contains("1名监考教师", result.Message);
Assert.Contains("程序设计", result.Message);
plan = await db.ExamPlans.SingleAsync(x => x.Id == plan.Id);
plan.Status = ExamPlanStatus.Published;
await db.SaveChangesAsync();
db.ChangeTracker.Clear();
var timetableService = new TimetableDataService(db);
var classroomTimetable = await timetableService.BuildAsync(
TimetableResourceType.Classroom,
seed.LargeClassroom.Id,
seed.Term.Id,
null,
false,
null,
null,
CancellationToken.None);
var unrelatedClassroomTimetable = await timetableService.BuildAsync(
TimetableResourceType.Classroom,
seed.SmallClassroom.Id,
seed.Term.Id,
null,
false,
null,
null,
CancellationToken.None);
var invigilatorTimetable = await timetableService.BuildAsync(
TimetableResourceType.Teacher,
room.Invigilators.Single().TeacherId,
seed.Term.Id,
null,
false,
null,
null,
CancellationToken.None);
Assert.Equal(
"程序设计",
Assert.Single(classroomTimetable!.ExamEntries).CourseName);
Assert.Empty(unrelatedClassroomTimetable!.ExamEntries);
Assert.Contains(
"监考:监考教师",
Assert.Single(invigilatorTimetable!.ExamEntries).TeacherNames);
}
[Fact]