发布课表投影改为数据库端删除旧数据、每 2,000 条分批写入并及时释放 EF 跟踪对象,避免大规模发布时内存持续增长。

为“空闲教室/预约占用”新增 学期 + 周次 + 星期 + 节次 + 场地 查询索引;新发布课表的该查询已优先走课次明细投影。
This commit is contained in:
2026-08-09 16:05:57 +08:00 Unverified
parent e39ab4579f
commit 8ef7fc9f9a
5 changed files with 6796 additions and 3 deletions
@@ -6,6 +6,7 @@ namespace Jiaowu.Api.Infrastructure.Timetables;
public sealed class PublishedTimetableProjectionService(AppDbContext db)
{
private const int WriteBatchSize = 2_000;
public async Task RebuildPublishedPlansForTaskAsync(Guid teachingTaskId, CancellationToken cancellationToken)
{
var plans = await db.SchedulePlans
@@ -19,10 +20,11 @@ public sealed class PublishedTimetableProjectionService(AppDbContext db)
public async Task RebuildAsync(SchedulePlan plan, CancellationToken cancellationToken)
{
var previous = db.PublishedScheduleOccurrences.Where(x => x.SchedulePlanId == plan.Id);
db.PublishedScheduleOccurrences.RemoveRange(previous);
await db.PublishedScheduleOccurrences
.Where(x => x.SchedulePlanId == plan.Id)
.ExecuteDeleteAsync(cancellationToken);
var rows = new List<PublishedScheduleOccurrence>();
var rows = new List<PublishedScheduleOccurrence>(WriteBatchSize);
foreach (var entry in plan.Entries)
for (var week = entry.StartWeek; week <= entry.EndWeek; week++)
{
@@ -41,8 +43,21 @@ public sealed class PublishedTimetableProjectionService(AppDbContext db)
PeriodCount = entry.PeriodCount,
Kind = entry.Kind
});
if (rows.Count == WriteBatchSize)
await WriteBatchAsync(rows, cancellationToken);
}
if (rows.Count > 0)
await WriteBatchAsync(rows, cancellationToken);
}
private async Task WriteBatchAsync(
List<PublishedScheduleOccurrence> rows,
CancellationToken cancellationToken)
{
db.PublishedScheduleOccurrences.AddRange(rows);
await db.SaveChangesAsync(cancellationToken);
foreach (var row in rows)
db.Entry(row).State = EntityState.Detached;
rows.Clear();
}
}