从实体延迟加载集合时出现异常

时间:2011-07-26 12:40:28

标签: jsf-2 jpa-2.0 java-ee-6 cdi entitymanager

我担心我会错过一个非常基本的观点,但我现在已经陷入困境,希望有人可以指出我的眼睛主演,努力向右迈进...... 我尝试逐步完成我的应用程序设置,以使自己清楚(希望人们在发布结束之前不会觉得无聊):

我有一个会话范围的CDI组件,用作JSF 2.0视图的处理程序。它包含一个实体管理器,一个对象列表和一个特殊的单个对象:

@Named
@SessionScoped
public class EventHandler implements Serializable {

  @PersistenceContext
  private EntityManager em;

  private List<MyEvent> events;

  private MyEvent currentEvent;
  ...

当视图请求列表显示表时,它通过查询数据库来填充列表:

Query query = em.createQuery("select e from MyEvent e");
events = (ArrayList<MyEvent>) query.getResultList();

视图在数据表中显示了这一点,并提供了处理程序中操作方法的链接:

<h:dataTable value="#{eventHandler.events}" var="_var">
  ...
    <h:commandLink action="#{eventHandler.linkAction(_var)}"> ... </h:commandLink>

action方法存储引用:

public void setCurrentEvent(MyEvent currentEvent) {
  this.currentEvent = currentEvent;
  ...

在上面的集合和引用中使用的实体中,默认情况下存在一种懒惰加载的关系:

@ManyToMany(mappedBy="supportedServices")
public Set<MyEntity> getSupportingEntities() {
  ...

现在,当进入详细视图并尝试通过执行以下操作来访问此关系时:

#{eventHandler.currentEvent.supportingEntities...}

我收到org.hibernate.LazyInitializationException,告诉我会话已关闭。

当处理程序是会话作用域并通过查询加载引用时,处理程序是否应该能够在第二个视图中的稍后加载所请求的关系?

1 个答案:

答案 0 :(得分:1)

嗯,我认为这是因为persistenceContext事件(如果它是会话范围bean的成员)不是会话作用域。
在第一次调用视图时,将创建持久性上下文,加载实体(事件)并填充数据表。然后刷新,关闭持久化上下文,并将响应发送到客户端。这一切都发生在同一个http请求中。

但是当您再调用详细信息视图时,会发出另一个http请求,并创建另一个持久性上下文,并且您对“currentEvent”的引用不再附加到上一个持久性上下文。因此,LazyInitializationError(必须将实体管理为延迟加载)。

解决方案可能是:

  • 使用扩展持久化上下文(explained here)。
  • 渴望获取关系:

    @ManyToMany(mappedBy="supportedServices", fetch=FetchType.EAGER)

  • 在详细信息视图中使用之前合并currentEvent的分离实例:

    entityManager.merge(currentEvent);