Java JPA@OneToMany->;父-子引用(外键)
我有一个关于从子实体引用父实体的问题 如果我有这样的东西:Java JPA@OneToMany->;父-子引用(外键),java,hibernate,jpa,parent-child,one-to-many,Java,Hibernate,Jpa,Parent Child,One To Many,我有一个关于从子实体引用父实体的问题 如果我有这样的东西: org.hibernate.exception.GenericJDBCException: Field 'paren_id' doesn't have a default value Parent.java: @Entity(name ="Parent") public class Parent { @Id @Generate..... @Column private int id;
org.hibernate.exception.GenericJDBCException: Field 'paren_id' doesn't have a default value
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 ...
}
...
setChildren(Set<Child> children) {
for (Child child : children) {
child.setParent.(this);
}
this.children = children;
}
...
@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 ...
}
将创建以下表格:
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 (null)
因为我没有将父对象设置为子对象。因此,我的问题是:
我真的必须这样做吗?
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 ...
}
...
setChildren(Set<Child> children) {
for (Child child : children) {
child.setParent.(this);
}
this.children = children;
}
...
@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 ...
}
现在如果我们这样做:
@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);
}
是的,就是这样。JPA并不关心实体图的一致性。特别是,您必须将其设置为双向关系的所有者端(在您的情况下,设置为Child的parent属性) 在JPA 2.0规范中,这用以下词语表示: 请注意,应用程序负责 维护运行时关系的一致性,例如, 为了确保一个政党的“一”和“多”面 当应用程序 在运行时更新关系 我真的必须这样做吗 这是一个策略,是的 在双向关系中,关系有“拥有”和“不拥有”两个方面。因为您案例中的拥有方位于
Child
,所以您需要在那里设置关系,以便将其持久化。拥有方通常由指定@JoinColumn
的位置决定,但它看起来不像是在使用该注释,因此它很可能是从您在父注释中使用mappedBy
这一事实推断出来的
您可以。我们在保存上面所示的简单对象图时遇到了问题。在H2中运行一切都可以,但是当我们在MySQL上运行时,子表(在@JoinColumn注释中定义)中的“paren_id”没有被父表的生成id填充,即使它在DB中被设置为带有外键约束的非空列
我们会得到这样一个例外:
org.hibernate.exception.GenericJDBCException: Field 'paren_id' doesn't have a default value
对于其他可能遇到这种情况的人,我们最终发现我们必须为@JoinColumn
添加另一个属性才能使其正常工作:
@JoinColumn(name="paren_id", nullable=false)
根据EntityManager
,如果我没有弄错,如果你想让它管理事务的插入顺序,你必须“告诉他”它也应该保留子事务。您没有这样做,所以“他”不知道要保存什么,但是您父母的子列表不是空的,所以“他”认为它是正确的,但是存储的值是空的
所以你应该考虑这样做:
... begin, etc
em.persist(child)
em.persist(parent)
在这里对父对象执行您想要的操作,然后提交,这也适用于类似的情况。情况似乎仍然如此。在父级实体中
可以有
@PrePersist
private void prePersist() {
children.forEach( c -> c.setParent(this));
}
为了避免在代码中的其他位置重复设置子/父关系的代码。是否有子实体上的父实体?如果是,它们是如何配置的。没有父级时,我收到错误(StaleStateException:批更新从更新[0]返回意外的行数;实际行数:0;应为1)。如果我添加没有注释的父对象,它也会显示错误(映射错误)。在子项的父字段上设置@manytoone时,我在保存时出现错误(ORA-00904:“报告”报告ID:“报告”。我的fk和它在id上的pk名为report_id,但我不知道report_report_id从哪里来(使用EclipseLink JPA实现)。值得注意的是,您仍然需要@Column(name=“paren\u id”)私有长parenId;为您的孩子映射此wot工作。!!在我孤独了两个星期之后,他是个好人。我尝试从客户端发送json,并使用spring的@RequestBody转换为对象,然后保存到db,我不想自己管理关系(将父对象设置为子对象——对我来说没有意义)!!!更新!!!关于@PrePersist的链接(您可以由@EntityListener管理)请参见--Nice man!!这节省了大量的精力,也优化了性能。出于某种原因,我在@PrePersist
的子级上得到了NullPointerException
。forEach
@guneetgstar可能您的子级
就是空的。首先初始化它?将nullable=false
也修复了我在OneToMany上的问题。然而,对于我的一个人来说,我仍然得到了例外。关于如何处理这种情况,有什么建议吗?我也尝试过这个,但运气不好,如果有问题的话,我也在使用MySQL。你能分享代码吗?