etms/EXAM_PAPER_MODEL_ANALYSIS.md
liyuchen bdba4a37fe Add: 分析考试与试卷数据模型问题报告
发现核心问题:
- 考试(Exam)和试卷(Paper)共用同一数据对象
- et_exam_exampaper_and_editexampaper 视图合并了两个独立概念
- 字段混用:时间属性和试题属性在同一表
- 无法支持'同一试卷用于多次考试'的业务场景

输出文件:EXAM_PAPER_MODEL_ANALYSIS.md
2026-04-16 17:34:52 +08:00

9.6 KiB
Raw Permalink Blame History

考试与试卷数据模型问题分析报告

一、问题概述

当前系统中,考试(Exam)试卷(Paper) 被设计为同一个数据对象,导致两个本应独立的概念混在一起,造成功能边界模糊和数据冗余。


二、当前数据模型分析

2.1 现有数据库表结构

et_exam_examination          -- 考试信息表(独立)
    ├── id                   -- 考试ID
    ├── planid               -- 关联培训计划ID
    ├── name                 -- 考试名称
    ├── starttime/endtime    -- 考试时间窗口
    ├── duration             -- 考试时长
    ├── isonline             -- 是否在线
    └── shouldJoin/realJoin  -- 应考/实考人数

et_exam_exampaper            -- 试卷表有examid字段关联考试
    ├── id                   -- 试卷ID
    ├── examid               -- 关联考试ID外键
    ├── name                 -- 试卷名称
    ├── totalpoints          -- 总分
    ├── passpoint            -- 及格分数
    ├── description          -- 描述
    ├── category             -- 所属知识点
    ├── state                -- 状态(是否可编辑)
    └── sum1~sum4            -- 各题型数量统计

et_exam_question             -- 试题题库表
    ├── id
    ├── type                 -- 题型1单选2多选3判断4问答
    ├── subject              -- 题目内容
    ├── answer               -- 正确答案
    └── optionA~F            -- 选项

et_exam_exampaper_question   -- 试卷-题目关联表
    ├── id
    ├── examid               -- 考试ID
    ├── questionid           -- 试题ID
    ├── score                -- 分值
    ├── isMust               -- 是否必答
    └── num                  -- 题目序号

2.2 实际使用的数据源

代码中实际使用的是 et_exam_exampaper_and_editexampaper 视图/联合表,将考试和试卷合并:

-- 在 SQL 映射中大量使用
select * from et_exam_exampaper_and_editexampaper

这个视图/表包含了考试和试卷的所有字段,导致两个概念完全混在一起。


三、核心问题分析

3.1 问题一:考试与试卷概念混淆

维度 考试(Exam) 试卷(Paper)
本质 一次考试活动 一份试题集合
属性 时间、人数、时长 题目、总分、及格分
生命周期 有开始/结束时间 可长期存在、复用
关联 关联培训计划 可关联多个考试

当前问题:考试和试卷共用同一张表,无法体现"同一份试卷可用于多次考试"的业务场景。

3.2 问题二:字段冗余与混用

exampaper_edit.ftl 中,同一个表单同时包含:

<!-- 考试属性 -->
开放时间startdate / enddate
考试时长sc (小时)

<!-- 试卷属性 -->
试卷名称name
试卷描述description
及格分数passpoints
试卷类别category

这导致:

  • 一份试卷不能同时用于多场考试(因为考试时间不同)
  • 修改考试时间会影响试卷本身

3.3 问题三:题型统计字段冗余

et_exam_exampaper 表中有 sum1~sum4 字段存储各题型数量:

`sum1` int -- 单选题数量
`sum2` int -- 多选题数量
`sum3` int -- 判断题数量
`sum4` int -- 问答题数量

问题:这些统计值应该通过 SQL 动态计算,而不是冗余存储。试题数量变化时需要手动同步更新。

3.4 问题四:关联表使用不一致

et_exam_limitation.map.xml 中可以看到:

-- limitation 表使用 exam_id 关联
select * from et_exam_limitation where exam_id = ?

-- usertest 表也使用 exam_id 关联
select * from et_exam_usertest where exam_id = ?

这里的 exam_id 实际存储的是试卷ID(因为 et_exam_exampaper_and_editexampaper 视图本身就是考试+试卷的合并),命名语义混乱。

3.5 问题五:考试和问卷共用一套表

从代码中可以看到,pg 参数区分:

pg值 类型 说明
1 考试/试卷 需要评分
2 调研问卷 不评分

但底层共用同一套表结构,只是业务逻辑不同。这种设计虽然灵活,但缺乏清晰的边界。


四、业务场景冲突示例

场景1同一试卷用于多次考试

业务需求某课程结业考试3月份和6月份各举办一次但使用同一份试卷。

当前限制

方案A创建两份试卷内容完全相同但ID不同→ 数据冗余
方案B使用同一试卷修改时间 → 影响历史考试记录

理想设计

试卷表(不变) ← 考试表(每次考试独立)

场景2考试延期

当前问题

  • 用户需要修改考试时间,但操作入口在"编辑试卷"
  • 修改后影响所有关联记录

理想设计

  • 考试时间在考试表中独立管理
  • 试卷表只负责试题内容

五、建议的数据模型重构

5.1 分离考试和试卷表

┌─────────────────────────────────────────────────────────────┐
│                      当前设计(混用)                        │
├─────────────────────────────────────────────────────────────┤
│  et_exam_exampaper_and_editexampaper                        │
│  ├── 考试属性(时间、人数)                                  │
│  └── 试卷属性(题目、总分)                                   │
└─────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────┐
│                      建议设计(分离)                        │
├─────────────────────────────────────────────────────────────┤
│  et_exam_exampaper试卷表                                 │
│  ├── id, name, description, category                       │
│  ├── totalpoints, passpoint                                │
│  └── creatperson, edittime                                │
├─────────────────────────────────────────────────────────────┤
│  et_exam_examination考试表                              │
│  ├── id, paper_id关联试卷                               │
│  ├── name, starttime, endtime, duration                    │
│  ├── shouldJoin, realJoin                                  │
│  └── state, leader                                         │
├─────────────────────────────────────────────────────────────┤
│  et_exam_exampaper_question关联表                        │
│  ├── id, paper_id, question_id                             │
│  ├── score每场考试可单独设置分值                         │
│  └── num, isMust                                           │
└─────────────────────────────────────────────────────────────┘

5.2 关键改进点

改进项 当前 建议
试卷复用 同一试卷不能用于多场考试 一份试卷可关联多场考试
时间独立 考试时间绑定试卷 考试时间独立管理
题目分值 固定分值 每场考试可单独设置
题型统计 冗余字段 sum1~sum4 动态 SQL 计算

六、重构风险评估

风险项 等级 说明
历史数据迁移 现有数据需要重新整理
业务逻辑修改 涉及多个控制器和页面
关联表改动 limitation、usertest 等表需同步修改
测试工作量 需要全面回归测试

七、建议执行步骤

  1. 分析阶段:梳理所有使用 et_exam_exampaper_and_editexampaper 的代码
  2. 设计阶段:完成新的数据模型设计
  3. 开发阶段
    • 新建考试表相关逻辑
    • 保留试卷表
    • 修改关联表
  4. 数据迁移:编写迁移脚本
  5. 测试验证:全面回归测试
  6. 上线部署:灰度发布

八、附录:涉及文件清单

SQL 映射文件

  • et_exam_exampaper_and_editexampaper.map.xml
  • et_exam_editexampaper.map.xml
  • et_exam_usertest.map.xml
  • et_exam_limitation.map.xml

前端模板

  • exam/exampaper.ftl
  • exam/exampaper_edit.ftl
  • exam/exampaper_list.ftl
  • exam/exampaper_detail.ftl
  • exam/exam.ftl
  • exam/exam_list.ftl

Java 控制器

  • ExamController.class
  • ExampaperController.class
  • ExamResultController.class
  • ExampaperServiceImpl.class
  • ExamServiceImpl.class

报告生成时间2026-04-16