我想在我的数据库中复制一组实体。 我用以下方式收集了这个集合:
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
现在我想复制一个'类别'列表并用EntityManager保存它。 我正在使用JPA / Hibernate。 的更新
在知道如何分离我的实体后,我需要知道要分离的内容: 当前代码:
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);
这会引发failed to lazily initialize a collection of role: entities.CategoryHistory.categories, no session or session was closed
例外。
我认为他想再懒得加载类别,因为我让它们分离了。我现在该怎么办?
答案 0 :(得分:8)
您需要从会话中分离您的实例。有三种方法可以做到这一点:
然后您必须更改业务键(因此在使用未修改的实例调用false
时,新实例将返回equals()
。这是重要的一步:没有它,Hibernate会将实例重新附加到数据库中的现有实例,否则你会得到其他奇怪的错误。
之后,您可以像保存其他任何实例一样保存新副本。
答案 1 :(得分:6)
Aaron Diguila的answer是这里的方式,即您需要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);
更新:根据Be careful while using EntityManager.getDelegate(),使用GlassFish实际上应该使用(也可能在您的情况下):
org.hibernate.Session session = ((org.hibernate.ejb.EntityManagerImpl) em.getDelegate()).getSession();
但是这将不在JBoss中suggest使用前面提到的代码。
org.hibernate.Session session = (Session) em.getDelegate();
虽然我知道使用getDelegate()
会使JPA代码不可移植,但我必须承认我并不期望此方法调用的结果是特定于实现的。
UPDATE2:要回答问题的更新部分,我不确定您是否急切地加载了这些类别。这不是执行此操作的最佳方式,但如果您在驱逐前致电categories.get(0)
会发生什么?另外,我可能会错过那部分,但是,你在哪里取消了类别的关键?
答案 2 :(得分:0)
确定,
由于我使用的是glassfish v3,而JPA2.0是最终的,我使用了EntityManager.detach() 奇怪的是ejb3-persistence.jar包含在我的lib中,所以我把它抛出并使用了glassfish jar的javax.persistence。分离方法在那里,但我的hibernate版本还没有实现
答案 3 :(得分:0)
BeanUtils.copyProperties(copy, orig)
在OpenJPA中,使用Apache BeanUtils手动删除实体监控:
BeanUtils.setProperty(copy, "pcVersionInit", false);
将主键设置为default / null。
另见:http://www.java-tutorial.ch/java-persistence-api/how-to-persist-duplicate-of-an-entity-with-openjpa