具有许多数据库表的通用实现

4
我目前开发的应用程序很庞大。数据库由300多个表组成,并且正在增长。目前它是一个桌面应用程序,但我们正在将其移植到Web上。
我们使用的技术是Spring(MVC)+ Hibernate用于后端,ZK框架用于前端。由于数据库有300多个表,我也创建了同样数量的POJO。使用Spring的DAO模式需要项目具有300个以上的DAO对象和300个以上的Service类。
这是我目前的做法:
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,以及一个Service类来处理所有/一个DAO对象?


我相信Spring Data项目提供了实现通用存储库的工具。www.springsource.org/spring-data/jpa - Boris Treukhov
3个回答

4

问题1

这并不是一个确切的回答,但请听我解释...

使用Spring DAO模式需要项目拥有300多个DAO对象和同样数量的Service类。

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

首先,你的300多张表很可能并非全部相互独立。更有可能的情况是,许多表提供了1-1、1-n以及n-m等关系。在这种情况下,最好只为拥有关系的一方创建DAO。其他部分应该使用JPA的级联功能进行存储和检索。

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

我们来看下面的例子:

有三个表:authorbookchapter。在bookchapter之间存在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没有提供任何方法来提供系统中所有书籍的列表。为解决这个问题,有两个选择:
  • AdminService 中添加 getAllBooks getAllAuthors 方法。
  • 只需在视图中使用现有的DAO。
我更喜欢后者,但是,正如我所说,其他人可能不同意这个看法。
需要注意的是,无论我们如何实现这些服务,它们都与您的DAO没有直接关系。
现在我可以完整地回答你的问题:
“如何编写像上面的GenericDAO类一样的通用服务以避免复制/粘贴?”
你不需要。通用服务违背了拥有服务层的全部目的。
问题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); 
}

目前,只需将它们保留为原样 - 一个构造函数和一堆通用的继承方法。


3
我建议更仔细地了解Spring Data项目,特别是Spring-Data-JPA,这可能会大大简化DAO类。它提供了CrudRepositoryJpaRepository,在大多数情况下已经具备了所有所需的功能。如果需要更多,您始终可以编写自己的查询并扩展标准接口。
还有一些其他想法:您可以从数据库生成实体和生成DAO类。

2

针对这个问题:

如果你看一下DAO的实现,那里面唯一的东西就是一个构造函数。有没有一种方法可以拥有“一个”DAO类来处理所有POJO,以及一个Service类来处理所有/一个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;
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接