4

我正在处理的当前应用程序是一个很大的应用程序。该数据库由 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 实现,唯一的事情就是构造函数。有没有办法拥有一个处理所有 POJO 的“一个”DAO 类和一个处理所有/一个 DAO 对象的服务类?

4

3 回答 3

4

问题 1

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

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

这是一个普遍的误解,而且是错误的。

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

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

让我们看下面的例子:

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

在这个例子中,我们确实有三个 JPA 注释的 POJO。但是,我们将只有两个DAO:theAuthorDAOBookDAO. 不会,因为所有对章节的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 实现,唯一的事情就是构造函数。有没有办法让“一个”DAO 类处理所有 POJO

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

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

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

    getAuthorsWithMultipleBooks(int minimalBookCount); 
}

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

于 2012-11-13T12:17:56.223 回答
3

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

还有一些想法:您从数据库生成实体并生成 DAO 类。

于 2012-11-13T11:50:28.360 回答
2

回答这个问题:

如果您查看 DAO 实现,唯一的事情就是构造函数。有没有办法拥有一个处理所有 POJO 的“一个”DAO 类和一个处理所有/一个 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;
    }
}
于 2012-11-13T11:50:56.860 回答