复制一组实体并在Hibernate / JPA中保留

我想在我的数据库中复制一组实体。 我用以下方式检索了这个系列:

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

现在我想复制一个’类别’列表并用EntityManager保存它。 我正在使用JPA / Hibernate。 UPDATE

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

  CategoryHistory chLast = (CategoryHistory)em.createQuery("SELECT ch from CategoryHistory ch WHERE ch.date=(SELECT MAX(date) from CategoryHistory)").getSingleResult(); Set 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); 

这引发了一个failed to lazily initialize a collection of role: entities.CategoryHistory.categories, no session or session was closedexception。

我认为他想再懒得加载类别,因为我让它们脱离了。 我现在应该怎么做?

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

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

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

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

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

然后,分离你的对象:

 session.evict(object); 

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

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

但这不适用于建议使用前面提到的代码的JBoss。

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

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

更新2:要回答问题的更新部分,我不确定您是否急切地加载了类别。 这不是最好的方法,但如果你在驱逐前调用categories.get(0)会发生什么? 另外,我可能会错过那部分但是,你在哪里取消了类别的关键?

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

  1. 关闭会话(在您的情况下可能不可能)。
  2. 序列化对象并再次反序列化。
  3. 克隆对象并清除/ null主键/ id字段。

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

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

好,

由于我正在使用glassfish v3,而JPA2.0是最终的,我使用了EntityManager.detach()奇怪的是ejb3-persistence.jar包含在我的lib中,所以我把它抛出并使用了glassfish jar的javax.persistence。 分离方法在那里,但我的hibernate版本还没有实现

  1. 克隆或复制每个对象的属性。 您可以使用Apache BeanUtils.copyProperties(copy, orig)
  2. 在OpenJPA中,使用Apache BeanUtils手动删除实体监视:

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

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

  4. 坚持每一份。

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