你们的关系不一定是双向的。这里的评论中有一些错误信息。
您还说您已将字段“parentId”添加到 Child 实体中,因为您假设 JPA 需要“了解”父字段,以便它可以设置值。根据您提供的注释,问题不在于 JPA 不了解该字段。问题是您提供了有关该领域的“太多”信息,但该信息内部不一致。
将 Parent 中的字段和注释更改为:
@OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.PERSIST)
@JoinColumn(name = "parent_id")
private List<Child> children;
然后从子实体中完全删除“parentId”。
您之前已指定了 JoinTable 注释。然而,您想要的不是JoinTable。 JoinTable 将创建一个额外的第三个表,以便将两个实体相互关联。你想要的只是一个 JoinColumn 。将 JoinColumn 注释添加到也使用 OneToMany 注释的字段后,您的 JPA 实现将知道您正在将 FK 添加到 CHILD 表中。问题是 JPA 有一个已经定义了列 Parent_id 的 CHILD 表。
想象一下,您为 CHILD 表的函数和 Parent_id 列提供了两个相互冲突的定义。在一种情况下,您已经告诉 JPA 它是一个实体,而parent_id 只是该实体中的一个值。另一方面,您告诉 JPA 您的 CHILD 表不是实体,而是用于在 CHILD 和 PARENT 表之间创建外键关系。问题是您的 CHILD 表已经存在。然后,当您持久化实体时,您已经告诉它parent_id 显式为空(未设置),但您还告诉它您的parent_id 应该更新以设置对父表的外键引用。
我用上面描述的更改修改了您的代码,并且我还称为“坚持”而不是“合并”。
这导致了 3 个 SQL 查询
insert into PARENT (ID) values (default)
insert into CHILD (ID) values (default)
update CHILD set parent_id=? where ID=?
这完美地反映了您想要的。父条目已创建。创建 CHILD 条目,然后更新 CHILD 记录以正确设置外键。
如果您改为添加注释
@OneToMany(fetch = FetchType.EAGER, cascade = CascadeType.PERSIST)
@JoinColumn(name = "parent_id", nullable = false)
private List<Child> children;
然后,当插入子项时,它将运行以下查询
insert into CHILD (ID, parent_id) values (default, ?)
因此从一开始就正确设置你的 FK。