【问题标题】:Generic implementation with lots of database tables具有大量数据库表的通用实现
【发布时间】:2012-11-01 20:05:52
【问题描述】:

我正在开发的当前应用程序很大。该数据库由 300 多个表组成,并且还在不断增长。目前它是一个桌面应用程序,但我们正在将其转移到网络上。

我们为此使用的技术是用于后端的 Spring (MVC) + Hibernate 和前端的 ZK 框架。在数据库中有 300 多个表,我最终也创建了那么多 POJO。使用 Spring 的 DAO 模式,这需要项目具有 300 多个 DAO 对象和 300 多个服务类。

这就是我目前的做法:

POJO:

@Entity
@Table(name="test")
public class Test implements Serializable {

    private static final long serialVersionUID = 1L;

    private Long id;
    private Integer version;

    private String m_name;


    @Id
    @GeneratedValue(strategy=GenerationType.AUTO)
    @Column(name="jpa_id")
    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    @Version
    @Column(name="jpa_version", insertable=false, updatable=false)
    public Integer getVersion() {
        return version;
    }

    public void setVersion(Integer version) {
        this.version = version;
    }

    @Column(name="name", length=30)
    public String getM_name() {
        return m_name;
    }

    public void setM_name(String m_name) {
        this.m_name = m_name;
    }
}

DAO 对象接口:

public interface IDao<T> {
    public List<T> getAll();
}

为了避免复制/粘贴,我创建了一个通用 DAO 类,它将被所有 DAO 对象扩展:

@Repository
public class GenericDAO<T extends Serializable> implements IDao<T> {

    @Autowired
    protected SessionFactory sessionFactory;

    protected Class<T> entity;

    @SuppressWarnings("unchecked")
    public List<T> getAll() {
        List<T> result = (List<T>) getSessionFactory().getCurrentSession().createQuery("from " + entity.getName()).list();
        return result;
    }

    public void setSessionFactory(SessionFactory sessionFactory) {
        this.sessionFactory = sessionFactory;
    }

    public void setEntity(Class<T> entity) {
        this.entity = entity;
    }
}

DAO 对象:

@Repository
public class TestDAO extends GenericDAO<Test> {

    public TestDAO() {
        setEntity(Test.class);
    }   
}

服务接口:

public interface IService<T> {
    public List<T> getAll();
}

服务实现:

@Service
public class TestService implements IService<Test> {

    @Autowired
    private IDao<Test> testDAO;

    @Transactional(readOnly=true)
    public List<Test> getAll() {
        return testDAO.getAll();
    }

    public void setTestDAO(IDao<Test> testDAO) {
        this.testDAO = testDAO;
    }
}

我有两个问题:

  1. 如何编写像上面的GenericDAO类这样的通用服务来避免c/p?

  2. 如果您查看 DAO 实现,唯一的事情就是构造函数。有没有办法让“一个”DAO 类处理所有 POJO 和一个服务类来处理所有/一个 DAO 对象?

【问题讨论】:

  • 我相信 Spring Data 项目提供了实现通用存储库的工具 www.springsource.org/spring-data/jpa

标签: java spring hibernate generics spring-mvc


【解决方案1】:

我建议仔细查看 Spring Data 项目,尤其是 Spring-Data-JPA,这可能会极大地简化 DAO 类。它提供了CrudRepositoryJpaRepository,在大多数情况下,它们已经具备了所有需要的功能。如果您需要更多,那么您总是可以编写自己的查询并扩展标准接口。

还有一些想法:你 generate entities from database 并生成 DAO 类。

【讨论】:

    【解决方案2】:

    回答问题:

    如果您查看 DAO 实现,唯一的事情就是构造函数。有没有办法让“一个”DAO 类处理所有 POJO 和一个服务类来处理所有/一个 DAO 对象?

    您可以使用反射检索泛型的参数化类型,这将允许您减少需要创建的对象数量。

    @Repository
    public class GenericDAO<T extends Serializable> implements IDao<T> {
    
        @Autowired
        protected SessionFactory sessionFactory;
    
        protected Class<T> entity;
    
        public GenericDao(){
          ParameterizedType genericSuperClass = (ParameterizedType) getClass().getGenericSuperclass();
          this.entity = (Class<T>) genericSuperClass.getActualTypeArguments()[0];
        }
    
        @SuppressWarnings("unchecked")
        public List<T> getAll() {
            List<T> result = (List<T>) getSessionFactory().getCurrentSession().createQuery("from " + entity.getName()).list();
            return result;
        }
    
        public void setSessionFactory(SessionFactory sessionFactory) {
            this.sessionFactory = sessionFactory;
        }
    
        public void setEntity(Class<T> entity) {
            this.entity = entity;
        }
    }
    

    【讨论】:

      【解决方案3】:

      问题 1

      这不会是您问题的确切答案,但请耐心等待......

      使用 Spring 的 DAO 模式,这需要项目拥有 300 多个 DAO 对象和 300 多个服务类。

      这是一个常见的误解,而且是错误的。

      首先,您的 300 多个表不太可能彼此独立。更有可能的是,其中许多表提供 1-1、1 - nn - m 关系。在这种情况下,最好只为关系的拥有部分设置一个 DAO。其他部分应使用 JPA 的级联功能进行存储和检索。

      此外,服务层不是意味着你的 DAO 之上的额外无关层;它旨在提供一个统一的概念域模型,其中用户的每个操作都映射到服务层上的一个方法。

      我们看下面的例子:

      共有三个表:authorbookchapterbookchapter 之间存在 1-n 关系,bookauthor 之间存在 n-m 关系。在这个例子中,作者和书籍被认为是强实体,而章节被认为是弱实体(它们的存在取决于书籍的存在)。

      在这个例子中,我们确实有三个 JPA 注释的 POJO。但是,我们将只有 两个 DAO:AuthorDAOBookDAO不会ChapterDAO,因为所有对章节的访问都应该通过BookDAO

      interface BookDAO {
          findAll();
          findById(BookID id)
      
          saveBook(Book book);
          addChapter(BookID id, Chapter chapter); 
          // etcetera
      }
      

      现在让我们看看示例的最终目标。假设这将是一个提供新书 RSS 提要的应用程序。还会有一个管理界面来添加新书。

      在这种情况下,我们将获得两个服务类 - 但它们与您的 DAO 没有任何关系!

      interface RssService {
          Collection<Book> getRecentBooks();
      }
      
      interface AdminService {
          addBook(AddBookCommand cmd);
          addAuthor(AddAuthorToBookCommand cmd);
      }
      

      我要提出的最后一点是争论点,其他人不同意我的观点。当前的 AdminService 无法提供系统中所有书籍的列表。要解决这个问题,有两种选择:

      • getAllBooksgetAllAuthors 方法添加到AdminService
      • 只需在您的视图中使用现有的 DAO。

      我更喜欢后者,但如前所述,其他人会不同意这一点。

      但需要注意的是,无论我们如何实现这些服务,它们绝不与您的 DAO 直接相关。

      现在我可以完整回答你的问题了:

      如何编写像上面的GenericDAO类这样的通用服务来避免c/p?

      你没有。通用服务破坏了拥有服务层的全部目的。

      问题 2

      如果您查看 DAO 实现,唯一的事情就是构造函数。有没有办法拥有处理所有 POJO 的“一个”DAO 类

      是的,但我再次建议不要这样做。首先,您的 DAO 可能是相同的,但随着项目的进展,DAO 将变得专业化,他们将需要特定的方法。例如:

      interface BookDAO {
          // generic stuff
          ...
          // end generic stuff
          getBooksWithMinimumChapters(int minimumChapterCount);
      }
      
      interface AuthorDAO {
          // generic stuff
          ...
          // end generic stuff
      
          getAuthorsWithMultipleBooks(int minimalBookCount); 
      }
      

      所以现在,让它们保持原样 - 一个构造函数和一堆通用继承方法。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2014-11-12
        • 2012-04-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-05-31
        • 2013-05-04
        相关资源
        最近更新 更多