有没有办法将分离的对象传递给 JPA 持久化? (分离的实体传递给坚持)

Posted

技术标签:

【中文标题】有没有办法将分离的对象传递给 JPA 持久化? (分离的实体传递给坚持)【英文标题】:Is there a way to pass detached object to JPA persist? (detached entity passed to persist) 【发布时间】:2012-11-29 22:25:06 【问题描述】:

我有 2 个实体:AccountAccountRole

public class Account 
   private AccountRole accountRole;

   @ManyToOne(cascade = CascadeType.PERSIST, fetch = FetchType.EAGER)
   public AccountRole getAccountRole() 
      return accountRole;
   

.

public class AccountRole 
    private Collection<Account> accounts = new ArrayList<Account>();

    @OneToMany(mappedBy = "accountRole", fetch = FetchType.EAGER)
    public Collection<Account> getAccounts() 
         return accounts;
    

当我从数据库中获取 accountRole 并尝试持久化我的 Account 时,问题就来了。 此时我刚刚创建了我的帐户,并且角色已经存在于 db 中。

AccountRole role = accountService.getRoleFromDatabase(AccountRoles.ROLE_USER);
account.setAccountRole(role);

//setting both ways, as suggested
public void setAccountRole(AccountRole accountRole) 
    accountRole.addAccount(this);
    this.accountRole = accountRole;


entityManager.persist(account); // finally in my DAO

我读到这个:JPA/Hibernate: detached entity passed to persist 我的理解是,我必须从两个方向设置实体值,以便我在我的设置器中做的事情。

还是报错。

 org.hibernate.PersistentObjectException: detached entity passed to persist: foo.bar.pojo.AccountRole

【问题讨论】:

【参考方案1】:

只需更换

entityManager.persist(account);

与:

entityManager.merge(account);

并允许合并级联:

@ManyToOne(cascade =  CascadeType.PERSIST, CascadeType.MERGE , fetch = FetchType.EAGER)
public AccountRole getAccountRole() 
    return accountRole;

因为合并是这样做的:

如果您的实体是新的,它与persist() 相同。 但如果你的实体已经存在,它会更新它。

【讨论】:

另请注意,persist() 将使您传递的对象成为托管实体,但是,合并将返回您传递的对象的托管副本。所以如果你在合并后需要一个托管实体,你应该做account = entityManager.merge(account) 也看看here【参考方案2】:

看起来您在处理过程中离开了事务,因此accountRole 被分离,或者由于其他原因它已经被分离。

在调用entityManager.persist(account) 之前调用entityManager.merge(accountRole) 应该可以修复它。

编辑:不幸的是,如果您不能确定accountRole 是否已经存在于数据库中,您将不得不通过查询来检查它。如果存在 - 合并,如果不存在 - 坚持。这确实很麻烦,但我还没有看到更好的解决方法。

EDIT2:您传递给merge 方法的实体将保持分离 - 托管实体将由merge 返回,因此您需要先合并,然后将account 上的引用设置为merge 的返回值。

【讨论】:

在极少数情况下AccountRole 不存在于数据库中,因此在执行em.persist 时,它会保留帐户和帐户角色,并且一切正常。现在,当我发现自己在这种情况下使用您的代码时,它会尝试将AccountRole 两次添加到数据库中,首先是合并,成功,然后是持久化,因此给了我duplicate key value violation error,有什么建议吗?问题是,有时角色不存在。 一个解决方案可能是,如果Role 不存在,persist 整个该死的事情,但如果角色确实存在,merge 首先,但这似乎太过分了麻烦,不是吗? @Jaanus - 唉,你是对的 :) 我已经相应地编辑了答案。 刚刚试过,同样的事情.. entityManager.merge(account.getAccountRole()); entityManager.persist(account); 和同样的错误:detached entity passed to persist: ee.sellin.vahvagame.pojo.AccountRole .. 哦男孩 @Jaanus - JPA 中有一个与合并有关的怪癖 - 我忘了提,抱歉。请参阅第二次编辑。【参考方案3】:

你不能传递一个数据实体来持久化,没有办法。但你不需要。

您希望独立于AccountRole(已被持久化)持久化一个Account。为了实现这一点,只需从子实体中的@ManyToOne 中删除级联(在本例中为Account):

public class Account 
    private AccountRole accountRole;

    @ManyToOne // no cascading here!
    public AccountRole getAccountRole() 
        return accountRole;
    

在这里查看我的解释,为什么:https://***.com/a/54271569/522578

【讨论】:

以上是关于有没有办法将分离的对象传递给 JPA 持久化? (分离的实体传递给坚持)的主要内容,如果未能解决你的问题,请参考以下文章

有没有办法避免将所有参数传递给函数[重复]

从 JPA/EJB3 持久性上下文中分离实体

c++ 在创建时将构造函数参数从父对象传递给子对象

使用 @Query JPA 注释将空参数传递给本机查询

有没有办法将多个参数传递给jquery函数[重复]

有没有办法将参数传递给Runnable? [复制]