我正在处理的当前应用程序是一个很大的应用程序。该数据库由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;
}
}
我有两个问题:
如何编写上面的GenericDAO类通用服务以避免c / p?
如果你看看DAO实现,那么唯一的就是构造函数。有没有办法让“one”DAO类处理所有POJO和一个处理所有/一个DAO对象的Service类?
答案 0 :(得分:4)
这不是你问题的准确答案,但请耐心等待......
使用Spring的DAO模式,这需要项目拥有300多个DAO对象和300多个服务类。
这是一种常见的误解,这是错误的。
首先,您的300多个表格不太可能彼此独立。更有可能的是,其中许多表提供了1-1,1 - n 和 n - m 的关系。在这种情况下,最好只为关系的拥有部分设置DAO。应使用JPA的级联功能存储和检索其他部分。
此外,服务层不意味着在DAO之上的额外无关层;它旨在提供统一的概念域模型,其中用户的每个操作都映射到服务层上的一个方法。
让我们看看下面的例子:
有三个表:author
,book
和chapter
。 book
和chapter
之间存在1 < n 关系,book
和author
之间存在 nm 关系。在这个例子中,作者和书籍被认为是强实体,而章节被认为是弱实体(它们的存在取决于书籍的存在)。
在这个例子中,我们确实有三个JPA注释的POJO。但是,我们只有两个 DAO:AuthorDAO
和BookDAO
。 不是ChapterDAO
,因为对章节的所有访问都应通过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无法提供系统中所有书籍的列表。要解决这个问题,有两种选择:
getAllBooks
和getAllAuthors
方法添加到AdminService
。 我更喜欢后者,但如上所述,其他人会不同意这一点。
但要注意的是,无论我们实现这些服务,它们绝不直接与您的DAO相关。
现在我可以完整地回答你的问题:
如何编写上面的GenericDAO类通用服务以避免使用c / p?
你没有。通用服务打败了拥有服务层的整个目的。
如果你看一下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类。它提供CrudRepository和JpaRepository,在大多数情况下已经具备所有功能。如果您需要更多,那么您总是可以编写自己的查询并扩展标准接口。
还有一些想法:你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;
}
}