当前位置: 首页 > 面试题库 >

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

常彭薄
2023-03-14
问题内容

我们使用的是带有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使集合无效,以便在需要时再次加载集合。


问题答案:

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



 类似资料:
  • 尝试获取父实体(Msg)的实体,其中父PK (msg_id)是子实体中的FK时,尝试保持子实体(MsgRetry)时出错。 错误,如:org.hibernate.id.IdentifierGenerationException:试图从null一对一属性分配id 父实体,不需要知道子实体(至少我认为它不需要知道)。一旦子实体被持久化,我就会尝试也持久化父实体。我可以通过在子实体中没有父实体并调用关联

  • 我有一个父实体a,它与映射在a_B表和a_C表中的实体B和实体C有多对多关系。在持久化时,我希望只持久化a、a_B和a_C,而不持久化B和C。如果我不使用cascadetype。all i get“object references a unsaved transient instance-save the transient instances before flush”错误。如果我使用casc

  • 问题内容: 我有一个托管bean,其中包含当前页面的实体对象列表。在我创建一个新对象并在事务中使用persist()将其持久保存到数据库之后;在另一个事务中,当我调用merge时(由于该实体由于先前的事务提交而处于分离状态);实体管理器无法在持久性上下文中找到对象,并向数据库抛出选择查询。我是否缺少某些东西,或者是正常行为? 更新:当我使用mysql数据库和自动生成的ID列时,存在上述问题。当我在

  • 我有一个实体,它已经持久化,并希望将其添加到新生成的父实体(尚未持久化)。如果我尝试持久化父级,我会得到错误“分离的实体传递到持久化:model.child”。我想我必须以某种方式为孩子调用“EntityManager.merge()”,而不是“EntityManager.persisted()”。但是我没有显式调用persisted。这由“cascade=cascadetype.all”注释处理

  • 问题内容: 但是,首选解决方案(属性访问)在我的情况下不起作用(我缺少列异常-为什么?) 该模型如下所示:实体和。表含有列是的表,以便它是典型的关系。 现在的问题是,如果我取的实体,我需要有机会获得价值(亦称的实体),而不取实体。我怎样才能做到这一点? 我使用的映射如下所示: 我想做的是调用而无需从DB中额外获取实体。 根据我上面提到的答案,如果我将注释从字段移到getter(在实体上,我对吗?)

  • 问题内容: 我正在尝试将实体扩展为用于填充超类字段的非实体。问题是,当我尝试保存它时,Hibernate会抛出MappingException。这是因为即使我将ReportParser强制转换为Report,但运行时实例仍然是ReportParser,因此Hibernate抱怨它是一个未知的实体。 ReportParser仅用于填写字段。 尝试将其投射到报告中并保存 在转移到ORM之前,我已经使用