JSF + Hibernate:Collection与任何会话无关

首先,我使用Java EE,Hibernate与EntityManager和PrimeFaces。

我有一个EJB模块(业务逻辑和域)和两个WAR模块(Jersey WS和JSF PrimeFaces)。

我决定在JSF WAR模块中初始化延迟集合,以避免延迟初始化exception。 我不使用扩展实体管理器。

@ManagedBean(name = "company") @SessionScoped public class CompanyBean { @EJB private CompanyFacade cf; ... public String showDetails(Long id) { company = cf.find(id); Hibernate.initialize(company.getCompanyTypes()); Hibernate.initialize(company.getPrimaryUser()); Hibernate.initialize(company.getBlocked()); Hibernate.initialize(company.getAddresses()); Hibernate.initialize(company.getContacts()); return "DETAILS"; } ... } 

我得到:

Caused by: org.hibernate.HibernateException: collection is not associated with any session at org.hibernate.collection.AbstractPersistentCollection.forceInitialization(AbstractPersistentCollection.java:474) at org.hibernate.Hibernate.initialize(Hibernate.java:417) at minepackage.CompanyBean.showDetails(CompanyBean.java:79) ...

我不明白。 在从数据库中提取初始化之前必须有一个会话,不是吗? 我以类似的方式初始化WS模块中的属性,并且它正在工作。

知道发生了什么事吗?

我认为会话在EJB完成后关闭,因此对象处于分离状态。 所以Hibernate.initialize()将不再起作用。 这里有多个选项:

  • 在客户端(在JSF bean或servletfilter中)打开事务。 这样,当您调用Hibernate.initialize()时,会话仍将处于打开状态。
  • 修改EJB以加载完整对象和所有必需的集合。 你可以使用fetch join和/或在那里使用Hibernate.initialize()
  • 在EJB中创建更细粒度的API。 像CompanyFacade.getAddressesByCompany()这样的方法。

我更喜欢后两者的组合。 使用fetch join在find方法中加载一对一和多对一关系,并添加额外的方法来加载一对多集合(如地址)。 这还可以提高后端的性能,因为它减少了数据库查询的数量。