java 复制实体集合并保留在 Hibernate/JPA 中

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1973877/
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-10-29 18:46:38  来源:igfitidea点击:

Duplicate a collection of entities and persist in Hibernate/JPA

javahibernateormcollectionsjpa

提问by Michael Bavin

I want to duplicate a collection of entities in my database. I retreive the collection with:

我想在我的数据库中复制一组实体。我用以下方法检索集合:

CategoryHistory chNew = new CategoryHistory();
CategoryHistory chLast =  (CategoryHistory)em.createQuery("SELECT ch from CategoryHistory ch WHERE ch.date = MAX(date)").getSingleResult;
List<Category> categories = chLast.getCategories();
chNew.addCategories(categories)// Should be a copy of the categories: OneToMany

Now i want to duplicate a list of 'categories' and persist it with EntityManager. I'm using JPA/Hibernate. UPDATE

现在我想复制一个“类别”列表并将其与 EntityManager 一起保存。我正在使用 JPA/Hibernate。 更新

After knowing how to detach my entities, i need to know what to detach: current code:

知道如何分离我的实体后,我需要知道要分离的内容:当前代码:

    CategoryHistory chLast =  (CategoryHistory)em.createQuery("SELECT ch from CategoryHistory ch WHERE ch.date=(SELECT MAX(date) from CategoryHistory)").getSingleResult();
    Set<Category> categories =chLast.getCategories();

    //detach
    org.hibernate.Session session = ((org.hibernate.ejb.EntityManagerImpl) em.getDelegate()).getSession();
    session.evict(chLast);//detaches also its child-entities?       

    //set the realations
    chNew.setCategories(categories);
    for (Category category : categories) {
        category.setCategoryHistory(chNew);
    }
    //set now create date
    chNew.setDate(Calendar.getInstance().getTime());

    //persist
    em.persist(chNew);

This throws a failed to lazily initialize a collection of role: entities.CategoryHistory.categories, no session or session was closedexception.

这会引发failed to lazily initialize a collection of role: entities.CategoryHistory.categories, no session or session was closed异常。

I think he wants to lazy load the categories again, as i have them detached. What should i do now?

我认为他想再次延迟加载类别,因为我已经将它们分开了。我现在应该怎么办?

回答by Aaron Digulla

You need to detach your instances from the session. There are three ways to do this:

您需要从会话中分离您的实例。有三种方法可以做到这一点:

  1. Close the session (probably not possible in your case).
  2. Serialize the object and deserialize it again.
  3. Clone the object and clear/null the primary key/id field.
  1. 关闭会话(在您的情况下可能不可能)。
  2. 序列化对象并再次反序列化它。
  3. 克隆对象并清除/清空主键/id 字段。

Then you must change the business key (so the new instances will return falsewhen calling equals()with an unmodified instance). This is the important step: Without it, Hibernate will reattach the instances to the existing ones in the DB or you'll get other, strange errors.

然后您必须更改业务键(因此falseequals()使用未修改的实例调用时新实例将返回)。这是重要的一步:没有它,Hibernate 会将实例重新附加到数据库中的现有实例,否则您会遇到其他奇怪的错误。

After that, you can save the new copies just like any other instance.

之后,您可以像保存任何其他实例一样保存新副本。

回答by Pascal Thivent

Aaron Diguila's answeris the way to go here, i.e. you need to detachyour instances, set the business key to nulland then persistthem.

Aaron Diguila 的答案是这里的方法,即您需要到detach您的实例,null然后将业务密钥设置为persist它们。

Sadly, there is no way to disconnect one object from the entity manager with JPA 1.x (JPA 2.0 will have EntityManager.detach(Object)and fix this). So, either wait for JPA 2.x (not an option I guess) or use Hibernate's underlying Session.

遗憾的是,无法使用 JPA 1.x 将一个对象与实体管理器断开连接(JPA 2.0 将具有EntityManager.detach(Object)并修复此问题)。因此,要么等待 JPA 2.x(我猜不是一个选项),要么使用 Hibernate 的底层Session.

To do so, you can cast the delegate of an EntityManager to an Hibernate Session.

为此,您可以将 EntityManager 的委托转换为 Hibernate Session。

Session session = (Session) em.getDelegate();

Of course, this only works if you use Hibernate as a Java Persistence provider, because the delegate is the Session API.

当然,这仅在您使用 Hibernate 作为 Java 持久性提供程序时才有效,因为委托是会话 API。

Then, to detach your object:

然后,要分离您的对象:

session.evict(object);

UPDATE:According to Be careful while using EntityManager.getDelegate(), with GlassFish one should actually use (and likely in your case too) :

更新:根据使用 EntityManager.getDelegate() 时要小心,GlassFish 应该实际使用(并且可能在您的情况下也是如此):

org.hibernate.Session session = ((org.hibernate.ejb.EntityManagerImpl) em.getDelegate()).getSession();

But this would notwork in JBoss that suggestto use the code previously mentioned.

但是,这会不会在JBoss中的工作,建议使用前面提到的代码。

org.hibernate.Session session = (Session) em.getDelegate();

While I understand that using getDelegate()makes JPA code non-portable, I must admit that I was not expecting the result of this method call to be implementation specific.

虽然我知道使用getDelegate()会使 JPA 代码不可移植,但我必须承认我不期望此方法调用的结果是特定于实现的。

UPDATE2:To answer the updated part of the question, I'm not sure that you eagerly loaded the categories. This is not the best way to do this but what happens if you call categories.get(0)before eviction? Also, I may be missing that part but, where do you nullify the key of categories?

UPDATE2:要回答问题的更新部分,我不确定您是否急切地加载了类别。这不是执行此操作的最佳方法,但如果您categories.get(0)在驱逐前致电会怎样?另外,我可能会遗漏那部分,但是,您在哪里取消类别的键?

回答by Michael Bavin

Ok,

行,

Since I'm using glassfish v3, and JPA2.0 is final, i used the EntityManager.detach() Strangely ejb3-persistence.jar was included in my lib, so i throwed it out and used javax.persistence of the glassfish jar. The detach method is there but my hibernate version has no implementation yet

由于我使用的是 glassfish v3,并且 JPA2.0 是最终版本,因此我使用了 EntityManager.detach() 奇怪的是 ejb3-persistence.jar 包含在我的库中,所以我将其扔掉并使用了 glassfish jar 的 javax.persistence。分离方法在那里,但我的休眠版本还没有实现

回答by Victor Lyuboslavsky

  1. Clone or copy properties of each object. You can use Apache BeanUtils.copyProperties(copy, orig)
  2. In OpenJPA, manually remove monitoring of entity using Apache BeanUtils:

    BeanUtils.setProperty(copy, "pcVersionInit", false);

  3. Set the primary key to default/null.

  4. Persist each copy.
  1. 克隆或复制每个对象的属性。你可以使用阿帕奇BeanUtils.copyProperties(copy, orig)
  2. 在 OpenJPA 中,使用 Apache BeanUtils 手动删除对实体的监控:

    BeanUtils.setProperty(copy, "pcVersionInit", false);

  3. 将主键设置为 default/null。

  4. 坚持每个副本。

Also see: http://www.java-tutorial.ch/java-persistence-api/how-to-persist-duplicate-of-an-entity-with-openjpa

另请参阅:http: //www.java-tutorial.ch/java-persistence-api/how-to-persist-duplicate-of-an-entity-with-openjpa