JPA不同列名一对一映射Groovy测试保存报错问题咨询
问题分析与解决
映射关系的核心错误
你当前的JPA映射完全搞反了数据库的外键方向:
- 数据库实际是Child表的
child_id字段作为外键,引用Parent表的parent_id - 但你在Parent类的
child字段上配置的@JoinColumn(name="parent_id", referenceColumnName="child_id"),相当于告诉JPA:Parent表的parent_id是外键,引用Child表的child_id,这和数据库的外键约束完全相反。所以保存Parent时,数据库会检查Parent的parent_id是否存在于Child的child_id中,而你的测试代码里没有创建任何Child,自然触发外键约束违规。
修正后的映射代码
Parent.java
String name; String desc; String parent_id; // 由Child端维护关联,mappedBy对应Child类中关联Parent的字段名 @OneToOne(cascade = {CascadeType.ALL}, fetch = FetchType.EAGER, optional = true, mappedBy = "parent") private Child child; // getters & setters
Child.java
String id; Timestamp createdDt; // 配置外键关联:外键字段是child_id,引用Parent的parent_id @ManyToOne(optional = false) @JoinColumn(name = "child_id", referencedColumnName = "parent_id") private Parent parent; // getters & setters
注:如果业务上是严格一对一(一个Parent对应唯一Child,一个Child仅属于一个Parent),可以把Child的
@ManyToOne改成@OneToOne,并添加unique = true属性。
测试代码调整
如果仅需保存Parent而不关联Child,直接运行原测试代码即可(optional = true允许Parent无对应Child);如果需要级联保存Parent和Child,需建立双向关联:
Parent p = new Parent(); p.setParent_id("P123"); p.setName("name"); p.setDesc("desc"); Child c = new Child(); c.setCreatedDt(new Timestamp(System.currentTimeMillis())); c.setParent(p); // 关联Parent p.setChild(c); // 双向关联 parentRepositary.save(p);
关于JUnit测试正常的可能原因
大概率是JUnit测试的数据库环境未启用外键约束,或者测试数据中提前插入了child_id为P123的Child记录,因此未触发约束错误。
内容的提问来源于stack exchange,提问作者usr_11
相关产品推荐
相关产品推荐

