Java Hibernate:合并父项后子项id为空
关于stackoverflow,我已经问了很多类似的问题,但是我找不到正确的答案,所以如果可以的话,我会发布这个问题: 我在Spring引导应用程序中有一个典型的一对多父子实体。因此,我创建了一个新的子级,将其添加到父级,然后合并/刷新/清除实体管理器。子实体使用新ID正确保存在数据库中,但父对象下的子对象ID为零。我遗漏了什么会强制刷新ID 创建新子级的代码位于最初获取父级的同一控制器中,因此它使用相同的DAO和相同的实体管理器 以下是我的代码(实体主要由JPA生成): 家长:Java Hibernate:合并父项后子项id为空,java,hibernate,jpa,Java,Hibernate,Jpa,关于stackoverflow,我已经问了很多类似的问题,但是我找不到正确的答案,所以如果可以的话,我会发布这个问题: 我在Spring引导应用程序中有一个典型的一对多父子实体。因此,我创建了一个新的子级,将其添加到父级,然后合并/刷新/清除实体管理器。子实体使用新ID正确保存在数据库中,但父对象下的子对象ID为零。我遗漏了什么会强制刷新ID 创建新子级的代码位于最初获取父级的同一控制器中,因此它使用相同的DAO和相同的实体管理器 以下是我的代码(实体主要由JPA生成): 家长: @Entity
@Entity
public class Parent implements Serializable {
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private int id;
@OneToMany(mappedBy="parent", fetch=FetchType.EAGER, cascade={CascadeType.MERGE})
private List<Child> children;
public List<Child> getChildren() {
return this.Children;
}
public void setChildren(List<Child> children) {
this.children = children;
}
public Child addChild(Child child) {
getChildren().add(child);
child.setParent(this);
return child;
}
}
道:
控制器:
@Autowired
private ParentDao parentDao;
. . . createChild() {
Child child = new Child();
// Set the link on both sides of the relationship
parent.addChild(child);
parentDao.update(parent);
// --> child.getId() == 0
}
merge()在新实体(在您的案例中是子实体)上调用时的工作方式,它执行persist()调用,但有一点不同
它只创建所传递实体的副本,并对副本调用persist()
因此,您的父实体无法看到id的更改,因为它持有子实体的“旧”实例,该实例未被持久化,并最终使用新id更新
希望能把事情弄清楚
更新
要获取新状态,您需要:
1)更改事务存储库方法以返回merge()值:
2)更改您的服务:
@Autowired
private ParentDao parentDao;
. . . createChild() {
Child child = new Child();
// Set the link on both sides of the relationship
parent.addChild(child);
Parent newParent = parentDao.update(parent);
// --> newParent.getChildren(0).getId() == 0
}
我的印象是flush()会刷新对象并将其级联,但我猜它不会。。。那么,答案是什么呢?我如何刷新新添加的子项?我也需要冲洗吗?谢谢你,maciej。因此,虽然这看起来很有效,但我仍然有一个问题-在hibernate中根本没有刷新原始父对象的选项吗?我想基本上我想把对象管理卸载到orm中,如果我不得不用这么多(容易出错)的努力来管理它们,这会有点违背目的,不是吗?我可以想象,如果不是大多数的话,很多用户都会想要同样的东西——只需将我的对象及其新的子对象存储在数据库中,然后刷新它。如果我在整个项目中都有对父对象的引用,我将如何持续更新它们呢?我上面评论中的第二个问题是修辞性的——我只是认为ORM强迫我更新对我对象的所有引用只是为了获得新创建的子对象的ID是没有意义的。另外,在我的例子中,父对象是我的用户对象,即通过应用程序身份验证的对象。每次我给它添加一个孩子时,都会替换这个对象,这让我有点紧张和不安……用我的方法,你不必更新任何东西。。您只需获取merge()操作后返回的新实例即可。Parent newParent=entityManager.merge(Parent);
@Autowired
private ParentDao parentDao;
. . . createChild() {
Child child = new Child();
// Set the link on both sides of the relationship
parent.addChild(child);
parentDao.update(parent);
// --> child.getId() == 0
}
@Transactional
public Parent update(Parent parent) {
Parent newParent = entityManager.merge(parent);
entityManager.flush();
entityManager.clear();
return newParent
}
@Autowired
private ParentDao parentDao;
. . . createChild() {
Child child = new Child();
// Set the link on both sides of the relationship
parent.addChild(child);
Parent newParent = parentDao.update(parent);
// --> newParent.getChildren(0).getId() == 0
}