JPA会尝试级联持久化已经持久化的实体吗?

4

JPA会尝试在已经持久化(非脱离状态)的实体上进行级联持久化吗?

为了让事情更清晰明了,这是我的情况:我想将一个新的用户持久化:

public void addUser(){
    //User is an entity that is related to many Groups
    //The relationship on User side is marked with cascade persist
    User user = new User();
    user.setName("foo");
    user.setGroups(new ArrayList<Groups>());

    //selectedGroups is an List of Groups previously created with persistent Groups
    for(Group g : this.selectedGroups){
        user.getGroups().add(this.groupDao.find(g.getId()));
    }
    //At this point, User.getGroups() is a list of Managed Entities

    //What happens on the following line?
    userDao.persist(user);
}

那么,会发生什么呢?JPA会尝试重新持久化user.getGroups()中的每个组吗?还是它会检测到这些组已经存在并且只更新新的关系?

如果回答是“是的,它会重新持久化”,我该如何注释这个关系才能使代码正常工作?


当你尝试它时会发生什么? - JB Nizet
就我所测试的情况来看,它似乎再次持久化了实体。但我不知道我是否做错了什么... - Pedro Peixoto
JPA 2规范在第3.2.2节中指出:“如果X是一个已存在的托管实体,则它将被持久化操作忽略”。因此,您正在做错了什么。 - JB Nizet
1个回答

3
JPA将检测新组和已持久化组之间的差异,并仅持久化新组。
编辑:响应评论
JPA可能会尝试再次持久化它们,因为它们已被分离。这意味着您需要使用merge重新附加它们,或者防止它们被分离。
它们变得分离的最可能原因是它们所在的事务结束了。假设您正在使用JTA并且没有进行额外操作,那么如果addUser不是EJB方法而groupDao是EJB,则通过groupDao.find调用开始事务,并在find返回时结束。因为默认情况下,如果没有正在运行的事务,则EJB方法会启动一个事务。如果addUser是EJB方法,则一切都应该正常,因为然后addUser将启动事务,groupDao.find将使用现有事务,因此一切都发生在一个事务中。

就我进行的测试来看,它似乎尝试再次持久化实体。但我不知道我是否做错了什么... - Pedro Peixoto
扩展了我的答案以解决您问题的最可能原因。 - Eelke
问题在于我正在使用持久化实体,但在EntityManager事务之外,因此,正如你所说,它们是分离的。感谢您提供的信息。 - Pedro Peixoto

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接