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)); }
以避免在代码中的其他地方重复设置子/父关系的代码。