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

发现核心问题:
- 考试(Exam)和试卷(Paper)共用同一数据对象
- et_exam_exampaper_and_editexampaper 视图合并了两个独立概念
- 字段混用:时间属性和试题属性在同一表
- 无法支持'同一试卷用于多次考试'的业务场景

输出文件:EXAM_PAPER_MODEL_ANALYSIS.md
This commit is contained in:
liyuchen 2026-04-16 17:34:52 +08:00
parent 512d57c5d9
commit bdba4a37fe

View File

@ -0,0 +1,260 @@
# 考试与试卷数据模型问题分析报告
## 一、问题概述
当前系统中,**考试(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
-- 在 SQL 映射中大量使用
select * from et_exam_exampaper_and_editexampaper
```
这个视图/表包含了考试和试卷的所有字段,导致两个概念完全混在一起。
---
## 三、核心问题分析
### 3.1 问题一:考试与试卷概念混淆
| 维度 | 考试(Exam) | 试卷(Paper) |
|------|-----------|-------------|
| **本质** | 一次考试活动 | 一份试题集合 |
| **属性** | 时间、人数、时长 | 题目、总分、及格分 |
| **生命周期** | 有开始/结束时间 | 可长期存在、复用 |
| **关联** | 关联培训计划 | 可关联多个考试 |
**当前问题**:考试和试卷共用同一张表,无法体现"同一份试卷可用于多次考试"的业务场景。
### 3.2 问题二:字段冗余与混用
`exampaper_edit.ftl` 中,同一个表单同时包含:
```html
<!-- 考试属性 -->
开放时间startdate / enddate
考试时长sc (小时)
<!-- 试卷属性 -->
试卷名称name
试卷描述description
及格分数passpoints
试卷类别category
```
这导致:
- 一份试卷不能同时用于多场考试(因为考试时间不同)
- 修改考试时间会影响试卷本身
### 3.3 问题三:题型统计字段冗余
`et_exam_exampaper` 表中有 `sum1~sum4` 字段存储各题型数量:
```sql
`sum1` int -- 单选题数量
`sum2` int -- 多选题数量
`sum3` int -- 判断题数量
`sum4` int -- 问答题数量
```
**问题**:这些统计值应该通过 SQL 动态计算,而不是冗余存储。试题数量变化时需要手动同步更新。
### 3.4 问题四:关联表使用不一致
`et_exam_limitation.map.xml` 中可以看到:
```sql
-- 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*