Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/367.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java Hibernate:合并父项后子项id为空_Java_Hibernate_Jpa - Fatal编程技术网

Java Hibernate:合并父项后子项id为空

Java Hibernate:合并父项后子项id为空,java,hibernate,jpa,Java,Hibernate,Jpa,关于stackoverflow,我已经问了很多类似的问题,但是我找不到正确的答案,所以如果可以的话,我会发布这个问题: 我在Spring引导应用程序中有一个典型的一对多父子实体。因此,我创建了一个新的子级,将其添加到父级,然后合并/刷新/清除实体管理器。子实体使用新ID正确保存在数据库中,但父对象下的子对象ID为零。我遗漏了什么会强制刷新ID 创建新子级的代码位于最初获取父级的同一控制器中,因此它使用相同的DAO和相同的实体管理器 以下是我的代码(实体主要由JPA生成): 家长: @Entity

关于stackoverflow,我已经问了很多类似的问题,但是我找不到正确的答案,所以如果可以的话,我会发布这个问题:

我在Spring引导应用程序中有一个典型的一对多父子实体。因此,我创建了一个新的子级,将其添加到父级,然后合并/刷新/清除实体管理器。子实体使用新ID正确保存在数据库中,但父对象下的子对象ID为零。我遗漏了什么会强制刷新ID

创建新子级的代码位于最初获取父级的同一控制器中,因此它使用相同的DAO和相同的实体管理器

以下是我的代码(实体主要由JPA生成):

家长:

@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
}