如何在基于Wicket、Spring、Hibernate的Web应用程序中正确使用LoadableDetachableModel?

4
我正在开发一个基于Hibernate,Spring和Wicket的Web应用程序。
到目前为止,我已经实现了业务对象和持久化层。事务由Spring框架的事务拦截器管理。因此,DAO类的每个方法都封装在一个事务中。与单元测试一起实现非常直接。
现在,我来到了Web应用程序部分,我也使用Spring进行依赖注入。与Wicket框架的@SpringBean注解一起,我将DAO注入Wicket组件。但是,由于我对Wicket还不太熟悉,所以在将业务对象传递给Wicket组件时,我有点卡住了。
我尝试使用LoadableDetachableModel,但遇到了一些问题。我有一个页面可以根据页面的输入参数创建新的或编辑现有的业务对象。如果页面上有id,则应从数据库中加载相应的业务对象。当没有参数时,应创建新的业务对象。编辑对象的部分运行得很好,但是当应创建新对象并填写Web表格并保存时,我会收到一个NullPointerException。经过一些调试,我发现LoadableDetachableModel无法返回业务对象的实例,因为重载的load()方法无法从数据库中加载对象,因为它尚未保存,并且因此没有id。
因此,现在我想知道如何解决这个问题。LoadableDetachableModel是否是正确的选择?是否建议将表单分为两个相互依赖的表单,每个表单使用不同的模型。因此,仅编辑页面/表单使用LoadableDetachableModel?
2个回答

2
这个问题以及一些相关问题有一个很好的解释,由Igor Vaynberg在“Wicket In Action”博客(链接)中提供。
该页面的最后一部分解决了这个问题,基本上是通过不使用“LoadableDetachableModel”,而是实现“AbstractEntityModel”来获得更完整的控制。

请参考最新的 http://wicket.apache.org/guide/guide/modelsforms.html,该文档适用于仍然使用 LoadableDetachableModel 的 Wicket 6.x 版本。 - Hendy Irawan
该链接已经不存在,请使用此链接https://ci.apache.org/projects/wicket/guide/7.x/guide/modelsforms.html。 - Miklos Krivan

0

Wicket 6.x参考文档 > 11 Wicket模型和表单 > 11.6 可分离模型描述如下:

Now as example of a possible use of LoadableDetachableModel, we will build a model designed to work with entities managed via JPA. To understand the following code a basic knowledge of JPA is required even if we won't go into the detail of this standard.

The following model is provided for example purposes only and is not intended to be used in production environment. Important aspects such as transaction management are not taken into account and you should rework the code before considering to use it.

public class JpaLoadableModel<T> extends LoadableDetachableModel<T> {

    private EntityManagerFactory entityManagerFactory;
    private Class<T> entityClass;
    private Serializable identifier;
    private List<Object> constructorParams;

    public JpaLoadableModel(EntityManagerFactory entityManagerFactory, T entity) {
        super();

        PersistenceUnitUtil util = entityManagerFactory.getPersistenceUnitUtil();

        this.entityManagerFactory = entityManagerFactory;
        this.entityClass = (Class<T>) entity.getClass();
        this.identifier = (Serializable) util.getIdentifier(entity);

        setObject(entity);
    }

    @Override protected T load() {
        T entity = null;

        if(identifier != null) {
            EntityManager entityManager = entityManagerFactory.createEntityManager();
            entity = entityManager.find(entityClass, identifier);
        }
        return entity;
    }

    @Override protected void onDetach() {
        super.onDetach();

        T entity = getObject();
        PersistenceUnitUtil persistenceUtil = entityManagerFactory.getPersistenceUnitUtil();

        if(entity == null) return;

        identifier = (Serializable) persistenceUtil.getIdentifier(entity);
    }
}

The constructor of the model takes as input two parameters: an implementation of the JPA interface javax.persistence.EntityManagerFactory to manage JPA entities and the entity that must be handled by this model. Inside its constructor the model saves the class of the entity and its id (which could be null if the entity has not been persisted yet). These two informations are required to retrieve the entity at a later time and are used by the load method.

onDetach is responsible for updating the entity id before detachment occurs. The id can change the first time an entity is persisted (JPA generates a new id and assigns it to the entity). Please note that this model is not responsible for saving any changes occurred to the entity object before it is detached. If we don't want to loose these changes we must explicitly persist the entity before the detaching phase occurs.

Since the model of this example holds a reference to the EntityManagerFactory, the implementation in use must be Serializable.


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接