如何在会话关闭后使用hibernate访问延迟加载的字段?

时间:2009-07-01 14:08:44

标签: java hibernate lazy-loading

考虑这种情况:

  • 我已经通过hibernate加载了一个Parent实体
  • Parent包含一个大型且延迟加载的子集合
  • 当用户查看父数据
  • 时,在初始加载后关闭hibernate会话
  • 用户可以选择查看懒惰儿童集合的内容
  • 我现在希望加载该集合

加载此系列的方式/最佳方式是什么?

  • 假设session-in-view不是一个选项,因为只有在用户查看Parent并且决定查看Children之后才会获取Children集合。
  • 这是一项服务,将由基于Web和桌面的客户端远程访问。

感谢。

3 个答案:

答案 0 :(得分:7)

可以使用Hibernate.initialize(parent.getCollection())加载延迟集合,但父对象需要附加到活动会话。

此解决方案获取父实体和延迟加载字段的名称,并返回完全加载集合的实体。

不幸的是,由于父级需要重新连接到新打开的会话,因此我不能使用对延迟集合的引用,因为这将引用实体的分离版本;因此fieldName和反射。出于同样的原因,这必须返回附加的父实体。

因此,在OP场景中,当用户选择查看延迟集合时,可以进行此调用:

Parent parentWithChildren = dao.initialize(parent,"lazyCollectionName");

方法:

public Entity initialize(Entity detachedParent,String fieldName) {
    // ...open a hibernate session...
    // reattaches parent to session
    Entity reattachedParent = (Entity) session.merge(detachedParent); 

    // get the field from the entity and initialize it
    Field fieldToInitialize = detachedParent.getClass().getDeclaredField(fieldName);
    fieldToInitialize.setAccessible(true);
    Object objectToInitialize = fieldToInitialize.get(reattachedParent);

    Hibernate.initialize(objectToInitialize);
    return reattachedParent;
}

答案 1 :(得分:3)

我正在对用户正在查看的内容做出一些假设,但是如果用户已经查看了父级并且真的想要看到孩子,那么您似乎只想检索孩子。

为什么不尝试打开新会话并通过其父级获取子级?有些东西......

criteria = session.createCriteria(Child.class);
criteria.add(Restrictions.eq("parent", parent));
List<Child> children = criteria.list();

答案 2 :(得分:0)

Hibernate以与普通字段不同的方式处理集合。

在我的工作中,我们通过在个案基础上初始化我们需要的初始负载中的字段来解决这个问题。例如,在您可能拥有的事务所包围的Facade load方法中:

public Parent loadParentWithIntent1(Long parentId)
{
  Parent parent = loadParentFromDAO();

  for (Child c : parent.getChildren())
  {
    c.getField1();
  }
}

我们对每个意图都有不同的外观调用。这基本上可以实现您所需要的,因为您在任何方式需要时都会加载这些特定字段,这只是在加载时将它们放入会话中。