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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/31446/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 07:22:48  来源:igfitidea点击:

Detach an entity from JPA/EJB3 persistence context

javaormjpa

提问by Matthew Ruston

What would be the easiest way to detach a specific JPA Entity Bean that was acquired through an EntityManager. Alternatively, could I have a query return detached objects in the first place so they would essentially act as 'read only'?

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

The reason why I want to do this is becuase I want to modify the data within the bean - with in my application only, but not ever have it persisted to the database. In my program, I eventually have to call flush() on the EntityManager, which would persist all changes from attached entities to the underyling database, but I want to exclude specific objects.

我想要这样做的原因是因为我想修改 bean 中的数据 - 仅在我的应用程序中使用,但从未将其持久化到数据库中。在我的程序中,我最终必须在 EntityManager 上调用 flush(),这会将所有更改从附加实体保存到底层数据库,但我想排除特定对象。

采纳答案by Andrei

Unfortunately, there's no way to disconnect one object from the entity manager in the current JPA implementation, AFAIR.

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

EntityManager.clear() will disconnect allthe JPA objects, so that might not be an appropriate solution in all the cases, if you have other objects you do plan to keep connected.

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

So your best bet would be to clone the objects and pass the clones to the code that changes the objects. Since primitive and immutable object fields are taken care of by the default cloning mechanism in a proper way, you won't have to write a lot of plumbing code (apart from deep cloning any aggregated structures you might have).

因此,最好的办法是克隆对象并将克隆传递给更改对象的代码。由于默认克隆机制以适当的方式处理原始和不可变对象字段,因此您不必编写大量管道代码(除了深度克隆您可能拥有的任何聚合结构)。

回答by jsight

As far as I know, the only direct ways to do it are:

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

  1. Commit the txn - Probably not a reasonable option
  2. Clear the Persistence Context - EntityManager.clear() - This is brutal, but would clear it out
  3. Copy the object - Most of the time your JPA objects are serializable, so this should be easy (if not particularly efficient).
  1. 提交交易 - 可能不是一个合理的选择
  2. 清除持久化上下文 - EntityManager.clear() - 这很残酷,但会清除它
  3. 复制对象 - 大多数时候您的 JPA 对象是可序列化的,所以这应该很容易(如果不是特别有效的话)。

回答by tonygambone

If there aren't too many properties in the bean, you might just create a new instance and set all of its properties manually from the persisted bean.

如果 bean 中没有太多属性,您可能只需创建一个新实例并从持久化 bean 手动设置其所有属性。

This could be implemented as a copy constructor, for example:

这可以实现为复制构造函数,例如:

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

Then:

然后:

Thing newBean = new Thing(oldBean);

回答by Andrei

(may be too late to answer, but can be useful for others)

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

I'm developing my first system with JPA right now. Unfortunately I'm faced with this problem when this system is almost complete.

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

Simply put. Use Hibernate, or wait for JPA 2.0.

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

In Hibernate, you can use 'session.evict(object)' to remove one object from session. In JPA 2.0, in draft right now,there is the 'EntityManager.detach(object)' method to detach one object from persistence context.

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

回答by Davide Consonni

this is quick and dirty, but you can also serialize and deserialize the object.

这既快速又脏,但您也可以序列化和反序列化对象。

回答by trunikov

I think you can also use method EntityManager.refresh(Object o) if primary key of the entity has not been changed. This method will restore original state of the entity.

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

回答by James McMahon

If you need to detach an object from the EntityManager and you are using Hibernate as your underlying ORM layer you can get access to the Hibernate Sessionobject and use the Session.evict(Object)method that Mauricio Kanada mentioned above.

如果您需要从 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);
}

Of course this would break if you switched to another ORM provider but I think this is preferably to trying to make a deep copy.

当然,如果您切换到另一个 ORM 提供程序,这会中断,但我认为这最好是尝试进行深度复制。

回答by David Faulstich

Since I am using SEAM and JPA 1.0 and my system has a fuctinality that needs to log all fields changes, i have created an value object or data transfer object if same fields of the entity that needs to be logged. The constructor of the new pojo is:

由于我使用的是 SEAM 和 JPA 1.0,并且我的系统具有需要记录所有字段更改的功能,如果需要记录实体的相同字段,我创建了一个值对象或数据传输对象。新 pojo 的构造函数是:

    public DocumentoAntigoDTO(Documento documentoAtual) {
    Method[] metodosDocumento = Documento.class.getMethods();
    for(Method metodo:metodosDocumento){
        if(metodo.getName().contains("get")){
            try {
                Object resultadoInvoke = metodo.invoke(documentoAtual,null);
                Method[] metodosDocumentoAntigo = DocumentoAntigoDTO.class.getMethods();
                for(Method metodoAntigo : metodosDocumentoAntigo){
                    String metodSetName = "set" + metodo.getName().substring(3);
                    if(metodoAntigo.getName().equals(metodSetName)){
                        metodoAntigo.invoke(this, resultadoInvoke);
                    }
                }
            } catch (IllegalArgumentException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InvocationTargetException e) {
                e.printStackTrace();
            }
        }
    }
}

回答by James

If using EclipseLinkyou also have the options,

如果使用EclipseLink你也有选择,

Use the Query hint, eclipselink.maintain-cache"="false- all returned objects will be detached.

使用查询提示,eclipselink.maintain-cache"="false- 所有返回的对象都将被分离。

Use the EclipseLinkJpaEntityManagercopy()API to copy the object to the desired depth.

使用EclipseLinkJpaEntityManagercopy()API 将对象复制到所需深度。

回答by Warren Crossing

If you get here because you actually want to pass an entity across a remote boundary then you just put some code in to fool the hibernazi.

如果你来到这里是因为你真的想通过一个远程边界来传递一个实体,那么你只需输入一些代码来欺骗冬眠者。

for(RssItem i : result.getChannel().getItem()){
}

Cloneable wont work because it actually copies the PersistantBag across.

Cloneable 不起作用,因为它实际上复制了 PersistantBag。

And forget about using serializable and bytearray streams and piped streams. creating threads to avoid deadlocks kills the entire concept.

忘记使用可序列化和字节数组流以及管道流。创建线程来避免死锁会扼杀整个概念。