有没有办法将分离的对象传递给 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 个实体:Account
和 AccountRole
。
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 持久化? (分离的实体传递给坚持)的主要内容,如果未能解决你的问题,请参考以下文章