【问题标题】:Single DAO & generic CRUD methods (JPA/Hibernate + Spring)单个 DAO 和通用 CRUD 方法(JPA/Hibernate + Spring)
【发布时间】:2011-04-22 18:15:40
【问题描述】:

在我之前的问题DAO and Service layers (JPA/Hibernate + Spring) 之后,我决定在使用 JPA/Hibernate、Spring 和 Wicket 的应用程序中只使用一个 DAO 作为我的数据层(至少在开始时)。提出了使用通用 CRUD 方法,但我不太确定如何使用 JPA 来实现它。你能给我一个例子或分享一个关于这个的链接吗?

【问题讨论】:

    标签: java jpa crud dao genericdao


    【解决方案1】:

    这是一个示例界面:

    public interface GenericDao<T, PK extends Serializable> {
        T create(T t);
        T read(PK id);
        T update(T t);
        void delete(T t);
    }
    

    还有一个实现:

    public class GenericDaoJpaImpl<T, PK extends Serializable> 
        implements GenericDao<T, PK> {
    
        protected Class<T> entityClass;
    
        @PersistenceContext
        protected EntityManager entityManager;
    
        public GenericDaoJpaImpl() {
            ParameterizedType genericSuperclass = (ParameterizedType) getClass()
                 .getGenericSuperclass();
            this.entityClass = (Class<T>) genericSuperclass
                 .getActualTypeArguments()[0];
        }
    
        @Override
        public T create(T t) {
            this.entityManager.persist(t);
            return t;
        }
    
        @Override
        public T read(PK id) {
            return this.entityManager.find(entityClass, id);
        }
    
        @Override
        public T update(T t) {
            return this.entityManager.merge(t);
        }
    
        @Override
        public void delete(T t) {
            t = this.entityManager.merge(t);
            this.entityManager.remove(t);
        }
    }
    

    【讨论】:

    • 这将如何适应 slsb 和 pojo 实体(代表 db 表)?
    • 很好的答案。只是几个 cmets:我宁愿在构造方法中将 Class 作为参数传递(而不是未经检查的强制转换);删除方法中的参数 t 不应重新分配,并且类最好是抽象的。
    • 我试图按照这个例子但是ParameterizedType genericSuperclass = (ParameterizedType) getClass().getGenericSuperclass(); 代码抛出java.lang.ClassCastException 并显示以下消息:java.lang.Class cannot be cast to java.lang.reflect.ParameterizedType 有人知道如何解决这个问题吗?还是谢谢。
    • 为什么没有交易?我的意思是entityManager.getTransaction().begin();entityManager.getTransaction().commit();
    • @Woland 如果使用 JTA,您不需要所有这些方法,事实上,如果您尝试在 JTA 上下文中调用这些方法,IIRC 会抛出异常。
    【解决方案2】:

    根据Don't repeat the DAO 这篇文章,我们多年来一直使用这种技术。在我们意识到我们犯了一个大错误之后,我们总是在与我们的模式问题作斗争。

    通过使用诸如 Hibernate 或 JPA 之类的 ORM 工具,您不必分别考虑 DAO 和服务层。您可以在服务类中使用 EntityManager,因为您知道事务的生命周期和实体类的逻辑。

    如果您拨打myDao.saveEntity 而不是简单的entityManager.saveEntity,您会节省任何时间吗?不,您将拥有一个不必要的 dao 类,它什么都不做,只是 EntityManager 的一个包装器。不要害怕在 EntityManager(或休眠中的会话)的帮助下在您的服务类中编写选择。

    还有一点注意:你应该定义你的服务层的边界,不要让程序员返回或等待实体类。 UI 或 WS 层程序员根本不应该只知道 DTO-s 的实体类。实体对象具有大多数程序员不知道的生命周期。如果您将实体对象存储在会话数据中并尝试在几秒钟或几小时后将其更新回数据库,您将遇到非常严重的问题。好吧,您可能不会这样做,但知道您的服务层的参数类型和返回类型的 UI 程序员只会节省一些代码行。

    【讨论】:

    • EJB 中的注释事务管理?!尽管您可能需要更复杂的 DAO,它不再是通用的,但无论如何。我仍然发现这种方法在特定情况下很有用。
    【解决方案3】:

    我也在寻找同样的东西。我发现似乎正是这样——SpringSource 提供的Spring-Data JPA 项目。这是来自Hades 的代码端口,现在(2011 年初)已被 Spring 吞并并更好地集成。 它允许您使用带有静态创建的单个 dao (SimpleJpaRepository),或扩展基本 JpaRepository 类以使用现成的 CRUD+ 方法创建任何特定于对象的 dao。还允许仅通过在接口中使用参数名称作为方法名称(不需要实现!)即findByLastname(String lastName); 看起来很有希望——成为 Spring 项目的一部分肯定也会确保它的未来。 我现在已经开始在我即将进行的项目中实现这一点。

    【讨论】:

      【解决方案4】:

      如果您正在寻找第三方实施,您可以查看 http://www.altuure.com/projects/yagdao/ 。它是一个基于注解的通用 DAO 框架,支持 JPA 和休眠

      【讨论】:

        【解决方案5】:

        你也可以看看http://codeblock.engio.net/data-persistence-and-the-dao-pattern/

        相关代码可以在github上找到https://github.com/bennidi/daoism

        它集成了 Spring 以及 Hibernate 和 EclipseLink 的配置示例

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2018-01-10
          • 2010-12-27
          • 2011-04-22
          • 1970-01-01
          • 2011-01-27
          • 1970-01-01
          • 2017-10-20
          • 2015-07-09
          相关资源
          最近更新 更多