General implementation with a large number of database tables

The current application I'm working on is great. The database consists of 300+ tables and it is growing. This is currently a desktop application, but we are moving it to the Internet.

The technology we use for this is Spring (MVC) + Hibernate for the backend and front panel ZK frames. Having 300+ tables in the database, I ended up creating a lot of POJOs. Using the Spring DAO template, this requires the project to have more than 300 DAO objects and another 300 service classes.

Here's how I do it at the moment:

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

Interface for DAO objects:

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

To avoid copy / paste, I created a generic DAO class that will be extended by all DAO objects:

 @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 Object:

 @Repository public class TestDAO extends GenericDAO<Test> { public TestDAO() { setEntity(Test.class); } } 

Service Interface:

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

Service implementation:

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

I have 2 questions:

  • How to write a generic service such as the GenericDAO class above to avoid c / p?

  • If you look at the DAO implementation, the only thing there is a constructor. Is there a way to have a β€œone” DAO class that processes all POJOs and one Service class that processes all / one DAO objects?

+4
source share
3 answers

Question 1

This will not be the exact answer to your question, but bear with me ...

Using the Spring DAO pattern, this requires the project to have more than 300 DAO objects and another 300 service classes.

This is a common misconception, and it is wrong.

First of all, it is unlikely that your 300+ tables are independent of each other. Most likely, many of these tables contain the relationships 1-1, 1 - n and n - m. In such cases, it is better to have only a DAO to own part of the relationship. The remaining parts must be stored and retrieved using the cascading capabilities of the JPA.

In addition, the service level is not intended as an additional irrelevant layer on top of your DAOs; it is designed to create a single conceptual domain model, where each user action is mapped to exactly one method at the service level.

Let's look at the following example:

There are three tables: author , book and chapter . There is a 1-n relationship between book and chapter and a nm relationship between book and author . In this example, authors and books are considered strong entities, and chapters are considered weak entities (their existence depends on the existence of books).

In this example, we really have three JPA-annotated POJOs. However, we would only have two DAOs: AuthorDAO and BookDAO . There would be no ChapterDAO , since all access to the chapters must go through BookDAO .

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

Now let's look at the ultimate goal of the example. Let's say this is an RSS feed for new books. There would also be an admin interface for adding new books.

In this case, we get two classes of Service - but they are in no way associated with your DAOs!

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

The last point I am going to make is a moot point, and others will not agree with me. The current AdminService does not provide any means to provide a list of all books in the system. To solve this problem, there are two options:

  • Add the getAllBooks and getAllAuthors methods to the AdminService .
  • Just use existing DAOs in your views.

I would prefer the latter, but as said, others will not agree with this.

It should be noted, however, that we are implementing these services, they are in no way directly related to your DAOs.

And now I can fully answer your question:

How to write a generic service such as the GenericDAO class above to avoid c / p?

No. Generic services are fully aimed at having a service level.

Question 2

If you look at the DAO implementation, the only thing there is a constructor. Is there a way to have a β€œsingle” DAO class that handles all POJOs

Yes, but I advise you again. First, your DAOs may be identical, but as your project progresses, DAOs will specialize and they will need special methods. For instance:

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

So, now let us leave them as they are, the only constructor and a bunch of common inherited methods.

+4
source

I suggest taking a closer look at the Spring Data project and especially Spring-Data-JPA , which can greatly simplify DAO classes. It provides CrudRepository and JpaRepository , which in most cases already has all the necessary functionality. If you need more, you can always write your own queries and extend the standard interfaces.

And a few more ideas: you generate entities from the database and generate DAO classes.

+3
source

In response to a question:

If you look at the DAO implementation, the only thing there is a constructor. Is there a way to have a β€œone” DAO class that processes all POJOs and one Service class that processes all / one DAO objects?

You can get the parameterized type of the general using reflection, which will allow you to reduce the number of objects that you need to create.

 @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; } } 
+2
source

Source: https://habr.com/ru/post/1445747/


All Articles