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

时间:2020-03-05 18:44:10  来源:igfitidea点击:

分离通过EntityManager获取的特定JPA实体Bean的最简单方法是什么。或者,我是否可以首先通过查询返回分离的对象,使它们本质上充当"只读"对象?

之所以要执行此操作,是因为我只想在应用程序中修改Bean中的数据,但从未将其持久化到数据库中。在我的程序中,我最终不得不在EntityManager上调用flush(),该操作将保留从连接的实体到底层数据库的所有更改,但是我想排除特定的对象。

解决方案

回答

据我所知,唯一的直接方法是:

  • 提交TXN-可能不是一个合理的选择
  • 清除持久性上下文-EntityManager.clear()-这很残酷,但是会清除它
  • 复制对象-大多数时候,JPA对象是可序列化的,因此这应该很容易(如果不是特别有效)。

回答

如果Bean中没有太多属性,则可以只创建一个新实例,然后从持久化的Bean中手动设置其所有属性。

可以将其实现为副本构造函数,例如:

public Thing(Thing oldBean) {
  this.setPropertyOne(oldBean.getPropertyOne());
  // and so on
}

然后:

Thing newBean = new Thing(oldBean);

回答

不幸的是,在当前的JPA实现AFAIR中,无法从实体管理器断开一个对象的连接。

EntityManager.clear()将断开所有JPA对象的连接,因此,如果我们确实计划保持其他连接,则在所有情况下这都不是一个合适的解决方案。

因此,最好的选择是克隆对象,并将克隆传递给更改对象的代码。由于默认克隆机制会以适当的方式处理原始和不可变的对象字段,因此我们无需编写大量的管道代码(除了深克隆可能具有的任何聚合结构之外)。

回答

(可能为时已晚,但对其他人可能有用)

我现在正在用JPA开发我的第一个系统。不幸的是,当这个系统几乎完成时,我面临着这个问题。

简单的说。使用Hibernate,或者等待JPA 2.0。

在Hibernate中,我们可以使用'session.evict(object)'从会话中删除一个对象。在JPA 2.0的当前草案中,有一个'EntityManager.detach(object)'方法,用于从持久性上下文中分离一个对象。

回答

毛里西奥·卡纳达(Mauricio Kanada),感谢建议,方法evict()很好用。我使用来自SEAM的JPA,内置了对JPA实体管理器的支持,并且可以访问休眠委托Session,因此可以使用此方法"退出"。

非常感谢,Zmicer

回答

这既快速又肮脏,但是我们也可以序列化和反序列化对象。

回答

我认为如果实体的主键没有更改,我们也可以使用EntityManager.refresh(Object o)方法。此方法将恢复实体的原始状态。

回答

如果需要从EntityManager分离对象,并且将Hibernate用作基础ORM层,则可以访问Hibernate Session对象,并使用上面Mauricio Kanada提到的Session.evict(Object)方法。

public void detach(Object entity) {
    org.hibernate.Session session = (Session) entityManager.getDelegate();
    session.evict(entity);
}

当然,如果我们切换到另一个ORM提供程序,则可能会中断,但是我认为这最好是尝试制作深层副本。