JPA @OneToOne能否通过子表存外键实现父表到子表单向关联?
结论
上述配置需求在JPA中完全可以实现,不需要调整现有表结构,仅通过实体注解配置即可满足全部要求。
具体配置方案
1. B实体配置
B实体不需要定义任何指向A实体的关联属性,仅需要将B表存储外键的a_id字段作为普通字段映射即可,查询B实体时不会触发任何对A表的关联查询:
@Entity @Table(name = "B") public class B { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; // 仅做普通字段映射外键列,不要添加任何关联注解 @Column(name = "a_id") private Long aId; // 其余B表自身业务字段、getter/setter方法省略 }
注意:为了符合OneToOne一对一的语义约束,需要给B表的
a_id字段添加唯一约束,避免同一个A对应多条B记录时出现查询报错。
2. A实体配置
在A实体中定义B类型的关联属性,通过@OneToOne+@JoinColumn注解指定外键存储位置,OneToOne默认是急加载策略,查询A时会自动关联查询出对应的B实体:
@Entity @Table(name = "A") public class A { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @OneToOne // 默认fetch = FetchType.EAGER,查询A时同步加载B;需要懒加载可手动配置为FetchType.LAZY // 指定关联外键在B表,字段名为a_id,关联A表的主键字段id @JoinColumn(name = "a_id", referencedColumnName = "id", table = "B") private B b; // 其余A表自身业务字段、getter/setter方法省略 }
配置逻辑说明
- 上述配置是完全单向的关联关系,B侧没有任何和A相关的关联定义,查询B的逻辑不会关联A表,完全符合需求。
- 如果需要实现级联新增、更新、删除B实体的能力,只需要在A侧的
@OneToOne注解上添加对应的cascade配置即可,例如@OneToOne(cascade = CascadeType.ALL)。 - 该配置生成的关联查询SQL逻辑为
SELECT * FROM A LEFT JOIN B ON A.id = B.a_id WHERE A.id = ?,和预期的表关联逻辑完全匹配。
内容的提问来源于stack exchange,提问作者顏啟倫
相关产品推荐
相关产品推荐

