如何在不加载父端集合集

时间:2016-12-13 11:05:32

标签: hibernate

我们正在使用Hibernate 3.5.6-Final和Hazelcast 3.6.1二级缓存。

情况

我在Hibernate设置为Parent的{​​{1}}和Child实体之间存在双向一对多关系。实体类定义如下:

inverse = true

父级的Hibernate映射定义如下:

class Parent {
   Set<Child> children;
   ... // setters, getters, other properties
}

class Child {
   Parent parent;
   ... // setters, getters, other properties       
}

子进程的Hibernate映射定义如下:

<set name="children"
     lazy="true"
     inverse="true"
     cascade="all"
     sort="unsorted">
     <cache usage="read-write"/>
     <key column="parent_id"/>
     <one-to-many class="Child"/>
</set>

现在的代码现在向<many-to-one name="parent" class="Parent" cascade="none" column="parent_id" not-null="true"/> 添加Child,如下所示:

Parent

问题是第二行代码会导致Hibernate加载所有子项。在我们的设置中,这是一个非常昂贵的操作,因为子实体具有渴望的集合,这些集合具有再次拥有热切集合的实体。

目前无法更改Hibernate模型。

问题

我更改了上面的代码如下:

child.setParent(parent);
parent.getChildren().add(child);

到目前为止一直有效。现在明显的问题是,如果在执行代码之前加载了当前会话中父级的child.setParent(parent); sessionFactory.getCache().evictCollection( "Parent.children", parent.getId() ); 集合可能过时。我希望确保之后对children的任何调用都会返回最新的集合,而不会将该子项明确地添加到集合中。我实际上想告诉Hibernate使集合无效,以便在需要时再次加载集合。

2 个答案:

答案 0 :(得分:0)

有更好的方法:

  1. 你需要让多对一的一方懒惰。

    <many-to-one name="parent"
        class="Parent"
        cascade="none"
        column="parent_id"
        not-null="true"
        lazy="true"/>
    
  2. 只要您不需要在当前运行的持久性上下文中获取Parent实体,您就可以获取代理参考:

    Parent parentProxy = session.load(Parent.class, parentId);
    
  3. 现在,您可以按如下方式创建一个新子项:

    Child newChild = new Child();
    child.setParent(parentProxy);
    session.persist(newChild);
    
  4. 另一种解决方法如下:

    您甚至无法获取父代理参考,而是执行以下操作:

    Parent parentReference = new Parent();
    parentReference.setId(parentId);
    
    Child newChild = new Child();
    child.setParent(parentReference);
    session.persist(newChild);
    

    这样,如果您只需要持久保存Child实体,则无需完全获取Parent实体。

答案 1 :(得分:0)

我找到了解决问题的方法。我通过向addChild添加一个新方法Parent来解决它,如下所示:

 public void addChild(Child child) {
     child.setParent(this);
     if (Hibernate.isInitialized(getChildren()) {
         getChildren().add(child);
     } else {
         Hibernate.getSessionFactory().getCache().evictCollection(
             getClass().getName()+".children", this.getId());
     }
 }

因此:如果孩子因某种原因已经被加载,则将新孩子添加到子集中。这可确保已加载的集合保持一致。如果该集合尚未 ,我只需将父级设置为子级并逐出第二级缓存(此处需要说明这一点:https://github.com/hibernate/hibernate-orm/pull/580)。由于集合未加载但它也不会不一致。当之后访问该集合时,Hibernate将加载包括新子节点的集合。