代码之家  ›  专栏  ›  技术社区  ›  Michael Bavin

复制实体集合并在Hibernate/JPA中持久化

  •  4
  • Michael Bavin  · 技术社区  · 16 年前

    我想复制数据库中的实体集合。

    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 例外。

    我想他想再次懒洋洋地加载这些类别,因为我已经将它们分离了。我现在该怎么办?

    4 回复  |  直到 16 年前
        1
  •  6
  •   Community Mohan Dere    9 年前

    亚伦·迪吉拉 answer 是去这里的路,也就是说,你需要 detach 在您的实例中,将业务密钥设置为 null 然后 persist

    遗憾的是,使用JPA1.x无法断开一个对象与实体管理器的连接(JPA2.0将有 EntityManager.detach(Object) 并解决此问题)。所以,要么等待JPA2.x(我想这不是一个选项),要么使用Hibernate的底层 Session

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

    当然,这只适用于将Hibernate用作Java持久性提供程序的情况,因为委托是会话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代码不可移植,我必须承认,我并不期望此方法调用的结果是特定于实现的。

    更新2: categories.get(0) 在驱逐之前?另外,我可能遗漏了这一部分,但是,你在哪里取消了类别的关键呢?

        2
  •  8
  •   Aaron Digulla    16 年前

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

    1. 序列化对象并再次反序列化它。

    然后必须更改业务密钥(这样新实例将返回 false 打电话的时候 equals() 使用未修改的实例)。这是重要的一步:没有它,Hibernate会将实例重新附加到数据库中现有的实例,否则会出现其他奇怪的错误。

        3
  •  0
  •   Michael Bavin    16 年前

    好啊

    因为我使用的是glassfish v3,JPA2.0是最终版本,所以我使用了EntityManager.detach() 奇怪的是,ejb3-persistence.jar包含在我的库中,所以我将其抛出,并使用glassfish jar的javax.persistence。分离方法已经存在,但是我的hibernate版本还没有实现

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

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

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