修复实验成绩评分方案保存的外键失败

This commit is contained in:
biss committed 2026-08-21 17:44:28 +08:00
1 parent 0e02d446ba
commit bcdb00ee2e
2 files changed
+95 -9

No files matched your search

@@ -568,21 +568,39 @@ public sealed class ExperimentGradesController(
sheet.ContributionWeight = request.ContributionWeight;
sheet.PassScore = request.PassScore;
db.ExperimentGradeItems.RemoveRange(sheet.Items);
var existingItems = sheet.Items.ToList();
var existingItemScores = sheet.Records
.SelectMany(record => record.ItemScores)
.ToList();
// MySQL must see each replacement item before its score rows. Do not
// rely on a single mixed insert/delete batch to infer that order.
await using var transaction =
await db.Database.BeginTransactionAsync(cancellationToken);
db.ExperimentGradeItemScores.RemoveRange(existingItemScores);
db.ExperimentGradeItems.RemoveRange(existingItems);
foreach (var record in sheet.Records)
{
record.ItemScores.Clear();
record.TotalScore = null;
record.IsPassed = null;
}
sheet.Items = replacementItems;
foreach (var record in sheet.Records)
foreach (var item in replacementItems)
record.ItemScores.Add(new ExperimentGradeItemScore
{
ExperimentGradeItemId = item.Id
});
await db.SaveChangesAsync(cancellationToken);
foreach (var item in replacementItems)
item.ExperimentGradeSheetId = sheet.Id;
db.ExperimentGradeItems.AddRange(replacementItems);
await db.SaveChangesAsync(cancellationToken);
db.ExperimentGradeItemScores.AddRange(
sheet.Records.SelectMany(record => replacementItems.Select(item =>
new ExperimentGradeItemScore
{
ExperimentGradeRecordId = record.Id,
ExperimentGradeItemId = item.Id
})));
await db.SaveChangesAsync(cancellationToken);
await transaction.CommitAsync(cancellationToken);
return NoContent();
}
@@ -14,6 +14,74 @@ namespace Jiaowu.Api.Tests;
public sealed class ExperimentGradesControllerTests
{
[Fact]
public async Task UpdateSettings_ReplacesItemsAndRecreatesScores()
{
await using var fixture = await ExperimentGradeFixture.CreateAsync();
var project = new ExperimentProject
{
TeachingTaskId = fixture.Task.Id,
Code = "LAB-SETTINGS",
Name = "评分方案更新实验",
ArrangementMode = ExperimentArrangementMode.Centralized,
StartDate = fixture.Term.StartDate,
EndDate = fixture.Term.EndDate,
Status = ExperimentProjectStatus.Published,
PublishedAt = DateTime.UtcNow
};
fixture.Db.ExperimentProjects.Add(project);
await fixture.Db.SaveChangesAsync();
var administrator = fixture.ExperimentGrades(fixture.AdminScope);
await administrator.CreateSheet(
new ExperimentGradeSheetRequest(
project.Id,
1,
60,
[new ExperimentGradeItemRequest(
"旧评分项",
ExperimentGradeItemKind.Operation,
100)]),
CancellationToken.None);
var sheetId = await fixture.Db.ExperimentGradeSheets
.Select(sheet => sheet.Id)
.SingleAsync();
fixture.Db.ChangeTracker.Clear();
Assert.IsType<NoContentResult>(await administrator.UpdateSettings(
sheetId,
new ExperimentGradeSettingsRequest(
1,
60,
[
new ExperimentGradeItemRequest(
"操作",
ExperimentGradeItemKind.Operation,
60),
new ExperimentGradeItemRequest(
"报告",
ExperimentGradeItemKind.Report,
40)
]),
CancellationToken.None));
fixture.Db.ChangeTracker.Clear();
var updatedSheet = await fixture.Db.ExperimentGradeSheets
.Include(sheet => sheet.Items)
.Include(sheet => sheet.Records)
.ThenInclude(record => record.ItemScores)
.SingleAsync(sheet => sheet.Id == sheetId);
Assert.Equal(["操作", "报告"], updatedSheet.Items
.OrderBy(item => item.SortOrder)
.Select(item => item.Name));
var record = Assert.Single(updatedSheet.Records);
Assert.Equal(2, record.ItemScores.Count);
Assert.All(record.ItemScores, score => Assert.Null(score.Score));
Assert.All(record.ItemScores, score => Assert.Contains(
updatedSheet.Items,
item => item.Id == score.ExperimentGradeItemId));
}
[Fact]
public async Task CollegeAdmin_CanPublishApprovedExperimentGradeSheet()
{