修复MySQL问题
This commit is contained in:
@@ -230,12 +230,14 @@ public sealed class ExamArrangementService(AppDbContext db)
|
|||||||
foreach (var id in dbBusyIds) busyTeacherIds.Add(id);
|
foreach (var id in dbBusyIds) busyTeacherIds.Add(id);
|
||||||
foreach (var id in excludeTeacherIds) busyTeacherIds.Add(id);
|
foreach (var id in excludeTeacherIds) busyTeacherIds.Add(id);
|
||||||
|
|
||||||
return await db.Teachers.AsNoTracking()
|
var candidates = await InvigilatorCandidateQuery
|
||||||
.Where(x => x.Status == TeacherStatus.Active)
|
.Create(db, busyTeacherIds)
|
||||||
.WhereNotIn(busyTeacherIds, x => x.Id)
|
|
||||||
.OrderBy(x => Guid.NewGuid())
|
|
||||||
.Take(needed)
|
|
||||||
.ToListAsync(cancellationToken);
|
.ToListAsync(cancellationToken);
|
||||||
|
|
||||||
|
return candidates
|
||||||
|
.OrderBy(_ => Random.Shared.Next())
|
||||||
|
.Take(needed)
|
||||||
|
.ToList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,15 @@
|
|||||||
|
using Jiaowu.Api.Domain.Academic;
|
||||||
|
using Jiaowu.Api.Infrastructure.Persistence;
|
||||||
|
using Microsoft.EntityFrameworkCore;
|
||||||
|
|
||||||
|
namespace Jiaowu.Api.Infrastructure.Exams;
|
||||||
|
|
||||||
|
internal static class InvigilatorCandidateQuery
|
||||||
|
{
|
||||||
|
public static IQueryable<Teacher> Create(
|
||||||
|
AppDbContext db,
|
||||||
|
IEnumerable<Guid> excludedTeacherIds) =>
|
||||||
|
db.Teachers.AsNoTracking()
|
||||||
|
.Where(x => x.Status == TeacherStatus.Active)
|
||||||
|
.WhereNotIn(excludedTeacherIds, x => x.Id);
|
||||||
|
}
|
||||||
@@ -225,11 +225,13 @@ public sealed class MakeupExamArrangementService(AppDbContext db)
|
|||||||
foreach (var id in dbBusyIds) busyTeacherIds.Add(id);
|
foreach (var id in dbBusyIds) busyTeacherIds.Add(id);
|
||||||
foreach (var id in excludeTeacherIds) busyTeacherIds.Add(id);
|
foreach (var id in excludeTeacherIds) busyTeacherIds.Add(id);
|
||||||
|
|
||||||
return await db.Teachers.AsNoTracking()
|
var candidates = await InvigilatorCandidateQuery
|
||||||
.Where(x => x.Status == TeacherStatus.Active)
|
.Create(db, busyTeacherIds)
|
||||||
.WhereNotIn(busyTeacherIds, x => x.Id)
|
|
||||||
.OrderBy(x => Guid.NewGuid())
|
|
||||||
.Take(needed)
|
|
||||||
.ToListAsync(cancellationToken);
|
.ToListAsync(cancellationToken);
|
||||||
|
|
||||||
|
return candidates
|
||||||
|
.OrderBy(_ => Random.Shared.Next())
|
||||||
|
.Take(needed)
|
||||||
|
.ToList();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ namespace Jiaowu.Api.Tests;
|
|||||||
public sealed class ExamArrangementServiceTests
|
public sealed class ExamArrangementServiceTests
|
||||||
{
|
{
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task Normal_arrangement_only_updates_selected_sessions_and_requested_resource()
|
public async Task Normal_arrangement_only_updates_selected_session()
|
||||||
{
|
{
|
||||||
await using var connection = new SqliteConnection("Data Source=:memory:");
|
await using var connection = new SqliteConnection("Data Source=:memory:");
|
||||||
await connection.OpenAsync();
|
await connection.OpenAsync();
|
||||||
@@ -37,21 +37,27 @@ public sealed class ExamArrangementServiceTests
|
|||||||
plan.Id,
|
plan.Id,
|
||||||
[selected.Id],
|
[selected.Id],
|
||||||
assignClassrooms: true,
|
assignClassrooms: true,
|
||||||
assignInvigilators: false,
|
assignInvigilators: true,
|
||||||
CancellationToken.None);
|
CancellationToken.None);
|
||||||
|
|
||||||
var persistedSelected = await db.ExamSessions.FindAsync(selected.Id);
|
var persistedSelected = await db.ExamSessions
|
||||||
var persistedUntouched = await db.ExamSessions.FindAsync(untouched.Id);
|
.Include(x => x.Invigilators)
|
||||||
|
.SingleAsync(x => x.Id == selected.Id);
|
||||||
|
var persistedUntouched = await db.ExamSessions
|
||||||
|
.Include(x => x.Invigilators)
|
||||||
|
.SingleAsync(x => x.Id == untouched.Id);
|
||||||
Assert.True(result.Success);
|
Assert.True(result.Success);
|
||||||
Assert.NotNull(persistedSelected!.ClassroomId);
|
Assert.NotNull(persistedSelected.ClassroomId);
|
||||||
Assert.Null(persistedUntouched!.ClassroomId);
|
Assert.Null(persistedUntouched.ClassroomId);
|
||||||
Assert.Empty(persistedSelected.Invigilators);
|
Assert.Single(persistedSelected.Invigilators);
|
||||||
|
Assert.Empty(persistedUntouched.Invigilators);
|
||||||
Assert.Contains("1个场次处理完成", result.Message);
|
Assert.Contains("1个场次处理完成", result.Message);
|
||||||
|
Assert.Contains("1名监考教师", result.Message);
|
||||||
Assert.Contains("程序设计", result.Message);
|
Assert.Contains("程序设计", result.Message);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public async Task Makeup_arrangement_only_updates_selected_sessions_and_requested_resource()
|
public async Task Makeup_arrangement_only_updates_selected_session()
|
||||||
{
|
{
|
||||||
await using var connection = new SqliteConnection("Data Source=:memory:");
|
await using var connection = new SqliteConnection("Data Source=:memory:");
|
||||||
await connection.OpenAsync();
|
await connection.OpenAsync();
|
||||||
@@ -79,16 +85,22 @@ public sealed class ExamArrangementServiceTests
|
|||||||
plan.Id,
|
plan.Id,
|
||||||
[selected.Id],
|
[selected.Id],
|
||||||
assignClassrooms: true,
|
assignClassrooms: true,
|
||||||
assignInvigilators: false,
|
assignInvigilators: true,
|
||||||
CancellationToken.None);
|
CancellationToken.None);
|
||||||
|
|
||||||
var persistedSelected = await db.MakeupExamSessions.FindAsync(selected.Id);
|
var persistedSelected = await db.MakeupExamSessions
|
||||||
var persistedUntouched = await db.MakeupExamSessions.FindAsync(untouched.Id);
|
.Include(x => x.Invigilators)
|
||||||
|
.SingleAsync(x => x.Id == selected.Id);
|
||||||
|
var persistedUntouched = await db.MakeupExamSessions
|
||||||
|
.Include(x => x.Invigilators)
|
||||||
|
.SingleAsync(x => x.Id == untouched.Id);
|
||||||
Assert.True(result.Success);
|
Assert.True(result.Success);
|
||||||
Assert.NotNull(persistedSelected!.ClassroomId);
|
Assert.NotNull(persistedSelected.ClassroomId);
|
||||||
Assert.Null(persistedUntouched!.ClassroomId);
|
Assert.Null(persistedUntouched.ClassroomId);
|
||||||
Assert.Empty(persistedSelected.Invigilators);
|
Assert.Single(persistedSelected.Invigilators);
|
||||||
|
Assert.Empty(persistedUntouched.Invigilators);
|
||||||
Assert.Contains("1个场次处理完成", result.Message);
|
Assert.Contains("1个场次处理完成", result.Message);
|
||||||
|
Assert.Contains("1名监考教师", result.Message);
|
||||||
Assert.Contains("程序设计", result.Message);
|
Assert.Contains("程序设计", result.Message);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -175,6 +187,13 @@ public sealed class ExamArrangementServiceTests
|
|||||||
CourseId = secondCourse.Id,
|
CourseId = secondCourse.Id,
|
||||||
Status = TeachingTaskStatus.Published
|
Status = TeachingTaskStatus.Published
|
||||||
};
|
};
|
||||||
|
var invigilator = new Teacher
|
||||||
|
{
|
||||||
|
TeacherNumber = $"INVIGILATOR-{suffix}",
|
||||||
|
Name = "监考教师",
|
||||||
|
CollegeId = college.Id,
|
||||||
|
Status = TeacherStatus.Active
|
||||||
|
};
|
||||||
|
|
||||||
db.AddRange(
|
db.AddRange(
|
||||||
term,
|
term,
|
||||||
@@ -186,6 +205,7 @@ public sealed class ExamArrangementServiceTests
|
|||||||
secondCourse,
|
secondCourse,
|
||||||
firstTask,
|
firstTask,
|
||||||
secondTask,
|
secondTask,
|
||||||
|
invigilator,
|
||||||
new ScheduleTimeSlot
|
new ScheduleTimeSlot
|
||||||
{
|
{
|
||||||
AcademicTermId = term.Id,
|
AcademicTermId = term.Id,
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using Jiaowu.Api.Infrastructure.Persistence;
|
using Jiaowu.Api.Infrastructure.Persistence;
|
||||||
|
using Jiaowu.Api.Infrastructure.Exams;
|
||||||
using Jiaowu.Api.Infrastructure.Teaching;
|
using Jiaowu.Api.Infrastructure.Teaching;
|
||||||
using Microsoft.EntityFrameworkCore;
|
using Microsoft.EntityFrameworkCore;
|
||||||
using Microsoft.EntityFrameworkCore.Infrastructure;
|
using Microsoft.EntityFrameworkCore.Infrastructure;
|
||||||
@@ -99,6 +100,21 @@ public sealed class MySqlMigrationTests
|
|||||||
Assert.Contains(ids[1].ToString(), sql, StringComparison.OrdinalIgnoreCase);
|
Assert.Contains(ids[1].ToString(), sql, StringComparison.OrdinalIgnoreCase);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Fact]
|
||||||
|
public void MySql_invigilator_candidate_query_is_translatable_without_uuid_ordering()
|
||||||
|
{
|
||||||
|
using var db = new AppDbContext(CreateMySqlOptions());
|
||||||
|
var excludedTeacherId =
|
||||||
|
Guid.Parse("11111111-1111-1111-1111-111111111111");
|
||||||
|
|
||||||
|
var sql = InvigilatorCandidateQuery
|
||||||
|
.Create(db, [excludedTeacherId])
|
||||||
|
.ToQueryString();
|
||||||
|
|
||||||
|
Assert.Contains("Teachers", sql, StringComparison.OrdinalIgnoreCase);
|
||||||
|
Assert.DoesNotContain("UUID(", sql, StringComparison.OrdinalIgnoreCase);
|
||||||
|
}
|
||||||
|
|
||||||
[Fact]
|
[Fact]
|
||||||
public void MySql_teaching_task_roster_query_is_translatable()
|
public void MySql_teaching_task_roster_query_is_translatable()
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in New Issue
Block a user