如何在多个请求(使用Wicket和JPA)中保持实体(或其关联)附加到当前持久性上下文?

pbi*_*tty 11 wicket jpa java-ee

我正在研究Java EE上基于Wicket的Web应用程序.

我试图找到一种方法来确保在Wicket尝试渲染任何组件之前,任何用作模型对象的实体始终附加到当前的EntityManager.这样,当组件从其模型中获取数据时,实体可以根据需要延迟加载数据.

有很多教程,这里有一些帖子,指的是LoadableDetachableModels(LDM)作为解决方案.当我们不需要保持任何状态中间请求时,这对我们有用.在这些情况下,无论何时呈现页面,LDM都将从数据库加载所需实体的最新版本.

但是,有时用户需要在保存数据之前通过多个步骤以有状态形式编辑数据,因此模型需要将实体保留在其"未保存"状态.LDM会在每一步都有效地消除用户的更改.

到目前为止,我们一直在使用一个模型,在需要时将实体与持久化上下文合并.这是一个简化版本:

public final class DetachableMergingModel<E extends Identifiable> implements IModel<E> {

    private E entity;
    private boolean attached = false;

    public DetachableMergingModel(E entity) {
        this.entity = entity;
    }

    @Override
    public E getObject() {
        if (!attached) {
            attached = true;
            // Non-transactional method merges entity with persistence context 
            // but does not flush any data to database
            entity = getRepository().merge(entity);
            }
        }
        return entity;
    }

    @Override
    public void setObject(E entity) {
        this.entity = entity;
    }

    @Override
    public void detach() {
        // This ensures that the next call to getObject() will merge the entity with 
        // the persistence context
        attached = false;
    }
    /* ... */
}
Run Code Online (Sandbox Code Playgroud)

我们的EntityManager由GlassFish注入,它跨越整个servlet请求,因此当实体附加到持久化上下文时,它将保持连接直到呈现页面之后.

上面的这个模型处理实体已经被持久化并且正在被编辑的情况.只要页面上的组件在此模型上调用getObject(),模型就会将实体与持久化上下文合并,我们可以自由地导航实体的整个对象图,而不会抛出任何LazyInitializationExceptions.

但是,在实体是新的并且尚未持久化的情况下,我们无法使用此模型,因为实体尚未准备好合并.当用户创建新实体时,通常会出现这种情况,并且仍然需要通过表单使用值填充它.在这种情况下,我们希望具有导航实体的对象图的相同自由(因为已经设置了一些关联,例如实体的父对象),而不用担心LazyInitializationException.

这里描述类似的解决方案(选项#3),但它没有涵盖上述'新实体'用例.

有人遇到过这个用例吗?你是怎么解决的?是否有更好的方法将Wicket与JPA集成,而不是通过自定义IModel实现?

小智 1

在这种情况下,我通常会创建一个 DTO 来保存创建实体所需的所有数据。如果您需要引用现有实体 - 将它们作为单独的模型传递到您的表单/面板。提交表格后,您可以:

  • 执行验证
  • 从已编辑的 DTO 创建一个新实体
  • 注入对您存储在这些单独的 LDM 模型中的其他实体的引用。
  • 持久化实体。

虽然有点麻烦,但确实有效。

跨越多个请求的对话在纯 wicket 中不可用,并且可能永远不会 - 这不是 wicket 的区域。

Seam 支持长时间对话,并且它确实支持 wicket(我从未使用过 Seam - 我无法在这方面向您提供建议)。