# 关系映射示例 / JPA Relationship Examples 这 6 个文件夹**不属于 VolunteerHub 那道题**,是单独准备的“关系映射参考”。 它们不参与主工程编译(放在 `src` 之外),只作为看代码 / 背切换写法用。 每个 `.java` 文件头部都有**中英双语**说明:关系是什么、外键在哪张表、会生成什么表、考试里什么信号对应这种写法。 --- ## 一、决策表 / Decision table | 基数 | 关系上有属性 | 写法 | 外键位置 | 示例目录 | |---|---|---|---|---| | 1:N / N:1 | — | `@OneToMany(mappedBy)` + `@ManyToOne` | “多”侧 | `01-one-to-many/` | | M:N | 无 | `@ManyToMany` + 一端 `@JoinTable`,另一端 `mappedBy` | 中间表(两列) | `02-many-to-many/` | | M:N | **有**(日期/数量/角色/评分) | 拆中间实体 + 两个 `@ManyToOne` | 中间实体表 | `03-many-to-many-with-attributes/` | | 1:1 | — | `@OneToOne` + `@JoinColumn(unique = true)` | 拥有端 | `04-one-to-one/` | | 自关联 | — | `@ManyToOne` 指向自己 + `@JoinColumn("parent_id")` | 本表 | `05-self-reference/` | | 同一对实体两条关系 | — | 两个字段 + 两个不同 `@JoinColumn` | 本表两列 | `06-two-relations/` | 一句话记:**有属性就拆实体;没属性才用 `@ManyToMany`;1:N 永远在“多”的那侧放外键。** --- ## 二、目录索引 / Index | 目录 | 类 | 生成的表 | 与真题的关系 | |---|---|---|---| | `01-one-to-many` | `Post`, `Comment` | `post`, `comment(post_id)` | Paper 2 真题 Book → Review 就是这种 | | `02-many-to-many` | `Student`, `Course` | 三张表,中间表两列 | Paper 2 真题 Author ↔ Book | | `03-many-to-many-with-attributes` | `Employee`, `Project`, `Assignment` | 三张表,中间表带 role/hours | **与 VolunteerHub 的 `Signup` 同构** | | `04-one-to-one` | `Employee`, `Desk` | `employee(desk_id UNIQUE)` | 样卷里 Employee ↔ Address 的 1:1 变体 | | `05-self-reference` | `Category` | `category(parent_id)` | Paper 2 真题 B 的 Course 先修课自连接 | | `06-two-relations` | `Doctor`, `Department` | `doctor(head_dept_id, member_dept_id)` | 需求里“主任/成员”这类双重身份 | --- ## 三、考试里的四个判断信号 / Four cues in the question paper 1. **“each Y belongs to one X”** → 1:N,不要中间实体。 2. **“many X … many Y”** 且**没提额外信息** → `@ManyToMany`。 3. **“many X … many Y”** 且提到**日期 / 数量 / 角色 / 评分 / 状态** → 拆中间实体(`03`)。 4. **“a course may have a prerequisite course”** → 自关联(`05`)。 --- ## 四、三个通用坑 / Three pitfalls | 坑 | 后果 | 正确做法 | |---|---|---| | 两端都写 `@JoinColumn` | 生成两个外键或两张中间表 | 只在拥有端(`@ManyToOne`)写 | | `mappedBy` 填列名(`event_id`) | 启动报 `unknown target entity property` | 填**字段名**(`event`) | | 两端都 `orphanRemoval = true` | `deleted object would be re-saved by cascade` | 只让语义上的父端管生命周期 | --- ## 五、怎么用这些文件 / How to use them - **看**:每个文件头部的注释就是“这一种关系该怎么讲”。 - **背**:考试前只看每类的 `@ManyToOne / @OneToMany / @ManyToMany / @OneToOne` 四行。 - **对**:做真题时先判断属于 6 种中的哪一种,再照抄对应文件夹里的注解组合。