【问题标题】:How to use the LoadableDetachableModel in a Wicket, Spring, Hibernate based web application correctly?如何在基于 Wicket、Spring、Hibernate 的 Web 应用程序中正确使用 LoadableDetachableModel?
【发布时间】:2011-08-11 19:20:35
【问题描述】:

我正在开发一个基于 Hibernate、Spring 和 Wicket 的 Web 应用程序。

到目前为止,我实现了业务对象和持久层。事务由 Spring 框架的事务拦截器管理。所以DAO类的每个方法都封装在一个事务中。与单元测试一起实现这一点很简单。

现在我来到 Web 应用程序部分,我也使用 Spring 进行依赖注入。连同 Wicket 框架的 @SpringBean 注解,我将 DAO 注入到 Wicket 组件中。但是由于我对 Wicket 还很陌生,所以在将正确的模型用于我的业务对象时,当我将它们传递给 Wicket 组件时,我有点卡住了。

我尝试了 LoadableDetachableModel,但遇到了一些问题。根据页面的输入参数,我得到一个页面来创建新的或编辑现有的业务对象。如果参数中有 id,则应从数据库中加载相应的业务对象。当没有参数时,应该创建一个新的业务对象。这部分是一个应该编辑的对象运行得很好,但是当应该创建一个新对象时,我填写了 Web 表单并按保存,我得到一个 NullPointerException。经过一些调试后,我发现 LoadableDetachableModel 无法返回业务对象的实例,因为重写的 load() 方法无法从数据库加载对象,因为它还没有保存在那里,因此没有 id。

所以现在我想知道如何解决这个问题。 LoadableDetachableModel 是正确的选择吗?是否建议将表单分成两个相互依赖的表单,每个表单使用不同的模型。所以只有编辑页面/表单使用 LoadableDetachableModel?

【问题讨论】:

    标签: hibernate spring wicket


    【解决方案1】:

    Igor Vaynberg 在the Wicket In Action blog 对此和一些相关问题进行了很好的解释。

    该页面的最后一点处理这个问题,基本上使用LoadableDetachableModel,而是实现AbstractEntityModel,这样可以实现更完整的控制。

    【讨论】:

    【解决方案2】:

    Wicket 6.x Reference Documentation > 11 Wicket models and forms > 11.6 Detachable models是这样描述的:

    现在作为LoadableDetachableModel 的可能用法示例,我们将 构建一个旨在与通过 JPA 管理的实体一起使用的模型。到 理解以下代码 需要具备 JPA 的基本知识 即使我们不会详细介绍这个标准。

    以下型号仅供参考,并非 打算在生产环境中使用。重要方面如 因为没有考虑交易管理,你应该 在考虑使用之前重新编写代码。

    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);
        }
    }
    

    模型的构造函数将两个参数作为输入:一个 JPA接口的实现 javax.persistence.EntityManagerFactory 管理 JPA 实体和 必须由该模型处理的实体。在其构造函数内部 模型保存实体的类及其 id(如果 该实体尚未持久化)。这两个信息是 需要稍后检索实体并由 加载方法。

    onDetach负责在分离前更新实体id 发生。 id 可以在第一次持久化实体时更改(JPA 生成一个新的 id 并将其分配给实体)。请注意 此模型不负责保存发生的任何更改 实体对象在分离之前。如果我们不想失去这些 我们必须在分离之前显式地持久化实体 阶段发生。

    由于此示例的模型包含对EntityManagerFactory 的引用,因此使用中的实现必须是Serializable

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-01-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-02-02
      • 2015-03-07
      相关资源
      最近更新 更多