测验管理与题库
发布: (2025年12月30日 GMT+8 18:06)
5 min read
原文: Dev.to
Source: Dev.to
数据模型
- One Quiz 有多个 Questions
- One Question 有多个 Options
- One Option 可以标记为正确答案
这些嵌套关系在最初创建数据时看起来很简单,但在进入编辑过程时会变得显著更复杂。
复杂数据编辑
典型的编辑工作流可能如下所示:
- 老师打开测验编辑器。
- 更改测验标题。
- 删除第 2 题。
- 编辑第 5 题的文本。
- 在末尾添加一个新题目。
所有更改在一次 Save(保存)点击后一起发送到后端。后端必须决定如何应用这些修改。
方法
| 方法 | 优点 | 缺点 |
|---|---|---|
| Partial Update (Diffing)(部分更新/差分) | 只更新已更改的部分。 | 复杂,难以维护,嵌套关系中容易出现 bug。 |
| Full Replacement(完整替换) | 实现简单。 | 有丢失数据引用的风险。 |
修改后的完整替换(Academic Suite)
Academic Suite 使用 修改后的完整替换,并将其包装在数据库事务中,以在简洁性、数据一致性和安全性之间取得平衡。整个更新过程原子执行;如果任何一步失败,所有更改都会回滚。
UpdateQuiz 实现 (handlers/quiz.go)
// Go (gorm)
err := database.DB.Transaction(func(tx *gorm.DB) error {
// 1. Update main quiz data (title, duration, etc.)
if err := tx.Save(&quiz).Error; err != nil {
return err
}
// 2. Delete all old questions
if err := tx.Delete(&models.Question{}, "quiz_id = ?", id).Error; err != nil {
return err
}
// 3. Re‑insert questions from request
for _, q := range req.Questions {
q.QuizID = id
if err := tx.Create(&q).Error; err != nil {
return err
}
}
return nil
})
后果
- 问题 ID 在每次编辑时都会更改。
- 如果
answers或attempts表引用question_id,学生成绩数据可能会被破坏。
生产安全措施
- 对于 Active(激活)或已有 Attempts(尝试)的测验应锁定(冻结)。
- 或者,对问题使用 软删除 或 版本控制 以保留考试历史。
Excel 题目导入
在网页表单中手动输入数十道题目效率低下,因此 Academic Suite 提供了从 Excel(.xlsx)文件导入的功能。
- 使用的库:
github.com/xuri/excelize/v2
数据验证挑战
Excel 文件是自由格式的:
- 列可能为空。
- 格式可能不一致。
- 正确答案可能位于错误的位置。
后端会对每一行单独进行验证:
// Go
for i, row := range rows {
if len(row) < 7 {
errors = append(errors, fmt.Sprintf(
"Row %d: Incomplete columns",
i+1,
))
continue
}
// Further parsing and validation...
}
好处
- 有效的行仍会被保存。
- 有问题的行会专门向用户报告,从而提升体验,同时不牺牲数据的一致性。
高效的数据检索
为了显示包含所有问题和答案选项的测验,Academic Suite 使用 GORM 的 eager loading,防止 N+1 查询问题。
// Go (gorm) – eager loading
database.DB.
Preload("Questions").
Preload("Questions.Options").
First(&quiz, "id = ?", id)
使用 eager loading,即使在包含大量问题的测验中,性能也保持稳定。
摘要
在本章中,我们构建了一个稳定且可扩展的 题库 与 测验管理 系统的基础。关键要点包括:
- 嵌套更新的挑战。
- 事务策略以保持数据一致性。
- 编辑进行中测验的风险及其缓解技术。
- 用户友好的 Excel 导入,具备行级验证。
- 用于最佳性能的预加载技术。
接下来: 第 5 章将深入探讨 考试引擎,包括计时器设置、考试状态以及精确的评分机制。