JPA @OneToMany – >父 – 子参考(外键)

我有一个关于从子实体引用ParentEntities的问题如果我有这样的事情:

Parent.java:

@Entity(name ="Parent") public class Parent { @Id @Generate..... @Column private int id; @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY, mappedBy = "parent") private Set<Child> children; simple ... getter and setter ... } 

和Child.java:

 @Entity(name ="Child") public class Child{ @Id @Generate.... @Column private int id; @ManyToOne private Parent parent; ... simple getter an setter } 

以下表格将被创build:

 Parent: int id Child: int id int parent_id (foreign key: parent.id) 

好的,到目前为止,翻转很好。 但是,当涉及到使用Java的这个引用,我会想,你可以做这样的事情。

  @Transactional public void test() { Parent parent = new Parent(); Child child = new Child(); Set<Child> children = new HashSet<Child>(); children.add(child); parent.setChildren(children); entityManager.persist(parent); } 

这导致在数据库中:

 Parent: id 100 Child id paren_id 101 100 

但事实并非如此,你必须明确地设置Parent to the Child(我认为,这个框架本身也可以)。

那么数据库中真正的是这样的:

 Parent: id 100 Child id paren_id 101 (null) 

因为我没有把父母给孩子。 所以我的问题:

我真的必须做某事吗? 喜欢这个?

Parent.java:

 ... setChildren(Set<Child> children) { for (Child child : children) { child.setParent.(this); } this.children = children; } ... 

编辑:

根据快速回复,我能够通过在引用拥有实体上使用@JoinColumn来解决这个问题。 如果我们从上面看这个例子,我做了某事。 喜欢这个:

Parent.java:

  @Entity(name ="Parent") public class Parent { @Id @Generate..... @Column private int id; @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY) @JoinColumn(name= "paren_id") private Set<Child> children; simple ... getter and setter ... } 

和Child.java:

 @Entity(name ="Child") public class Child{ @Id @Generate.... @Column private int id; ... simple getter an setter } 

现在,如果我们这样做:

  @Transactional public void test() { Parent parent = new Parent(); Child child = new Child(); Set<Child> children = new HashSet<Child>(); children.add(child); parent.setChildren(children); entityManager.persist(parent); } 

参考文献是由父母正确设置的:

 Parent: id 100 Child id paren_id 101 100 

感谢您的答案。

我真的必须做某事吗? 喜欢这个?

这是一个策略,是的。

在双向关系中,关系有一个“拥有”和“非拥有”的一面。 因为在你的情况下拥有的一方是在Child ,所以你需要在那里设置关系来保持它。 拥有的一方通常由您指定@JoinColumn的位置决定,但看起来您并不像使用该注释,所以可能从您在Parent注释中使用了mappedBy的事实推断出来。

你可以在这里阅读更多关于这个 。

是的,情况就是这样。 JPA不关心实体图的一致性。 特别是你必须把它设置为双向关系的所有者(在你的情况下,为Child的父属性)。

在JPA 2.0规范中,用以下词语表示:

请注意,应用程序负责维护运行时间关系的一致性,例如,确保在应用程序更新时双向关系的“一”和“多”方面保持一致在运行时的关系。

我们遇到了一个问题,同时坚持一个简单的对象图,如上图所示。 在H2中运行一切都会工作,但是当我们对MySQL运行时,子表(在@JoinColumn注释中定义的)中的“paren_id”没有用父生成的ID填充 – 即使它被设置为非在数据库中带有外键约束的空列。

我们会得到这样的exception:

org.hibernate.exception.GenericJDBCException:Field'paren_id'没有默认值

对于任何可能遇到这个问题的人来说,我们最终发现的是,我们必须使用@JoinColumn的另一个属性才能使其工作:

@JoinColumn(name =“paren_id”,nullable = false)

如果我正确地得到你,根据EntityManager ,如果你想要它来pipe理交易的插入顺序,你必须“告诉他”,它应该坚持孩子们。 而你没有这样做,所以“他”不知道要坚持什么,但你父母的子女名单不是空的,所以“他”认为它是正确的,但存储的值为空。

所以你应该考虑做一些事情:

 ... begin, etc em.persist(child) em.persist(parent) 

做你想要的父对象在这里然后提交,这也适用于类似的情况。

它似乎仍是如此。 在父Entity你可以有类似的东西

 @PrePersist private void prePersist() { children.forEach( c -> c.setParent(this)); } 

以避免在代码中的其他地方重复设置子/父关系的代码。