具有大量数据库表的通用实现

时间:2012-11-13 11:30:41

标签: java spring hibernate generics spring-mvc

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

我们正在使用的技术是Spring(MVC)+ Hibernate for backend和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实现,那么唯一的就是构造函数。有没有办法让“one”DAO类处理所有POJO和一个处理所有/一个DAO对象的Service类?

3 个答案:

答案 0 :(得分:4)

问题1

这不是你问题的准确答案,但请耐心等待......

  

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

这是一种常见的误解,这是错误的。

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

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

让我们看看下面的例子:

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

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

interface BookDAO {
    findAll();
    findById(BookID id)

    saveBook(Book book);
    addChapter(BookID id, Chapter chapter); 
    // etcetera
}

现在让我们看一下示例的最终目标。假设这是一个提供新书RSS源的应用程序。还有一个Admin界面可以添加新书。

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

interface RssService {
    Collection<Book> getRecentBooks();
}

interface AdminService {
    addBook(AddBookCommand cmd);
    addAuthor(AddAuthorToBookCommand cmd);
}

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

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

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

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

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

  

如何编写上面的GenericDAO类通用服务以避免使用c / p?

你没有。通用服务打败了拥有服务层的整个目的。

问题2

  

如果你看一下DAO实现,唯一有一个构造函数。有没有办法让“一个”DAO类处理所有POJO的

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

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

interface AuthorDAO {
    // generic stuff
    ...
    // end generic stuff

    getAuthorsWithMultipleBooks(int minimalBookCount); 
}

所以现在,只要保留它们 - 一个构造函数和一堆通用的继承方法。

答案 1 :(得分:3)

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

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

答案 2 :(得分:2)

回答问题:

  

如果你看一下DAO实现,唯一有一个构造函数。有没有办法让“one”DAO类处理所有POJO和一个处理所有/一个DAO对象的Service类?

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

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