我正在使用
Java EE上的基于Wicket的Web应用程序.
我试图找到一种方法来确保用作模型对象的任何实体始终附加到当前的EntityManager之前,Wicket会尝试渲染任何组件.这样,当组件从其模型中抓取数据时,数据可以根据需要被实体轻松加载.
有很多教程,在这里的一些帖子,引用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; } /* ... */ }
我们的EntityManager由GlassFish注入,它跨越了一个完整的servlet请求,所以当实体被附加到持久性上下文时,它将保持附加,直到页面被渲染为止.
上面的模型处理实体已经被持久化并正在被编辑的情况.每当页面上的一个组件在此模型上调用getObject()时,Model将会将实体与持久性上下文合并,并且我们可以自由导航实体的整个对象图,而不会抛出任何LazyInitializationExceptions.
但是,在实体是新的且尚未被持久化的情况下,我们不能使用此模型,因为实体尚未准备好合并.当用户正在创建一个新实体时,通常会出现这种情况,并且仍然需要通过表单将其填充.在这种情况下,我们希望拥有相同的自由度导航实体的对象图(因为一些关联已经被设置,比如实体的父),而不用担心LazyInitializationException.