一尘不染

如何在不加载父级Set集合的情况下持久化Hibernate子实体

hibernate

我们使用的是带有Hazelcast 3.6.1 2级缓存的Hibernate 3.5.6-Final。

情况

ParentChild具有Hibernate设置的实体之间存在双向,一对多关系inverse = true。实体类定义如下:

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>

子项的hibernate映射定义如下:

<many-to-one name="parent"
    class="Parent"
    cascade="none"
    column="parent_id"
    not-null="true"/>

现在,当前代码Child向中添加了,Parent如下所示:

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

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

当前不能更改Hibernate模型。

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

child.setParent(parent);
sessionFactory.getCache().evictCollection( "Parent.children", parent.getId() );

到目前为止,这一直有效。现在的明显问题是,如果在执行代码之前加载children了当前会话中的父级集合,则该集合 可能
已过时。我想确保在随后进行的任何调用都parent.getChildren()返回最新的集合,而无需真正地将子项显式添加到集合中。我实际上想告诉Hibernate使集合无效,以便在需要时再次加载集合。


阅读 209

收藏
2020-06-20

共1个答案

一尘不染

我找到了解决问题的方法。我通过在上添加了一个新方法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将加载包括新子集的集。

2020-06-20