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

发布于 2024-11-26 02:11:02 字数 1357 浏览 1 评论 0原文

我担心我错过了一个非常基本的要点,但我现在被困住了,希望有人能把我的眼睛集中到正确的地方...... 我尝试一步一步地完成我的应用程序设置,以便让自己清楚(希望人们在阅读完帖子之前不会感到无聊):

我有一个会话范围的 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>

操作方法存储引用:

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

在上面的集合和引用中使用的实体中,默认情况下会延迟加载一个关系:

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

现在,当处于详细信息视图中并尝试通过以下方式访问此关系时:做:

#{eventHandler.currentEvent.supportingEntities...}

我得到一个org.hibernate.LazyInitializationException 告诉我会话已关闭。

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

I fear that I miss a very basic point, but I'm stuck at the moment, hopefully someone can point my eyes starring to hard at it to the right one...
I try to go through my application setup step by step for make myself clear (hoping people won't get bored before they reach the end of the posting):

I have a session scoped CDI component serving as a handler for a JSF 2.0 view. It holds an entity manager, a list of objects and a special single object:

@Named
@SessionScoped
public class EventHandler implements Serializable {

  @PersistenceContext
  private EntityManager em;

  private List<MyEvent> events;

  private MyEvent currentEvent;
  ...

When the view requests the list for displaying a table, it fills the list by querying the database:

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

The view shows this in a data table and provides a link to an action method within the handler:

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

The action method stores the reference:

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

Within the entity used in the collection and references above, there'a relationship which gets loaded lazily by default:

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

Now, when being in the detail view and trying to access this relationship by doing:

#{eventHandler.currentEvent.supportingEntities...}

I get a org.hibernate.LazyInitializationException telling me that the session is closed.

Shouldn't the handler be able to load the requested relationship at a later point in the 2nd view, when the handler is session scoped and loaded the references via a query?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

怂人 2024-12-03 02:11:02

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

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

解决方案可能是:

  • 使用扩展持久性上下文(此处说明)。
  • 急切获取关系:

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

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

    entityManager.merge(currentEvent);

Hum, I think this is because the persistenceContext, event if it is a member of a session scoped bean, is not session scoped.
When the view is called the first time, a persistence context is created, the entities(events) are loaded and the datatable is populated. Then the persistence context is flushed, closed and the response is sent to the client. This all happen in the same http request.

But when you then call the details view, another http request is issued, and another persistence context is created, and your reference to "currentEvent" is no more attached to the last persistence context. Hence the LazyInitializationError (the entity must be managed to lazy load).

Solutions could be :

  • Use an extended persistence context (explained here).
  • Eager fetch the relation :

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

  • Merge the detached instance of currentEvent before using it in the details view :

    entityManager.merge(currentEvent);

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文