综合练习
为 Track/Lesson 画 ER 并写 Repository。
40 分钟
综合练习
把本 track 串起来:画 ER → 对照 schema → 写 JPA Entity 与 Repository → 可选 MyBatis 复杂查询。
学习目标
- 独立完成
cf_track/cf_lesson域建模 - 实现按 slug 查课含课时列表(无 N+1)
- 说明迁移与事务如何配合发布流程
任务 1:ER 与表
- 画出
cf_track1—Ncf_lesson1—Ncf_exerciseER 图 - 标出 PK、FK、
uk_track_slug - 对照
backend/src/main/resources/schema.sql核对
复习:orm-er、sql-design
任务 2:JPA 实现
// 需实现
public interface TrackRepository extends JpaRepository<Track, Long> {
@EntityGraph(attributePaths = {"lessons"})
Optional<Track> findBySlug(String slug);
}
public interface LessonRepository extends JpaRepository<Lesson, Long> {
List<Lesson> findByTrackIdAndStatusOrderByOrderIndexAsc(
Long trackId, String status);
}
Service 方法:
@Transactional(readOnly = true)
public TrackDetailDto getPublishedTrack(String slug);
TrackDetailDto 只暴露 API 需要的字段,勿直接返回 Entity 图。
任务 3:MyBatis 加分
写 Mapper:统计每门 track 的已发布 lesson 数,按 category 过滤:
SELECT t.slug, t.title, COUNT(l.id) AS lesson_count
FROM cf_track t
LEFT JOIN cf_lesson l ON l.track_id = t.id AND l.status = 'published'
WHERE t.category = #{category}
GROUP BY t.id
ORDER BY t.sort_order;
对照 sql-aggregate。
任务 4:发布事务
实现 publishTrack(trackId):
- 将 track 下所有
draftlesson 改为published - 任一步失败全部回滚
- 说明与
ON DELETE CASCADE的关系
见 orm-transactions、sb-transaction。
自检清单
- ER 图与 schema.sql 一致