
The problem that I would like to describe today is a repeating set of fields in Hibernate entities. Of course, it could be solved with the help of normalizing the database, but this is inconvenient when sampling and affects the speed, unnecessary joins for the sake of several columns are not needed by anyone.
So, let's imagine there is some kind of accounting system, in it in any entity it is important to keep history, who changed, who created, when there were recent changes, who created. In fact, in any project you can find similar sets and not one. As a result, when programmers create these fields, at best a copy-paste is obtained, and sometimes new names are born for the same fields.
I would like to consider two ways to solve this problem.
First way
This task can be solved using
@Embeddable entities:
package ru.kabit.entity.embeded; import javax.persistence.Embeddable; import java.util.Date; @Embeddable public class HistoryFields { private Long lastModifierId; private Long creatorId; private Date lastModifyDate; private Date createDate; }
Remove removed fields from the class, insert one
embedded property. In practice, walking through the code and adding an extra getter before calling these fields is easy, but in XML, JSP it is difficult to find all the places.
package ru.kabit.entity; import ru.kabit.entity.embeded.HistoryFields; import javax.persistence.Embedded; import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; @Entity public class Post { @Id @GeneratedValue private Long id; @Embedded private HistoryFields historyFields; }
If at least one field from
HistoryFields is filled, then a
HistoryFields object will be created and these fields will be filled, otherwise null will be in place of the object, which is by the way, very handy when writing logic. The names of the fields in the database can be different, so the
@AttributeOverride annotation is used to change them.
')
The advantages of this approach:
- The logical group of fields is highlighted in a separate entity, the fields will always be called the same, no one would ever think of them to write "according to the correct"
- The selected data is selected without subqueries, as they are in the same table.
- Search criteria for these fields will be unchanged
- There may be several such fields.
Disadvantages :
- In some cases, the set of fields may be unnecessary, they will not work.
- When refactoring, you have to change JSP with your hands, it is difficult to do this in a large project, you have to recheck everything, or make additional getters that retrieve data from the Embedded fields
Second way
The second solution is to use the
@MappedSuperclass annotation:
package ru.kabit.entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.MappedSuperclass; import java.util.Date; @MappedSuperclass public class HistoryEntity { @Id @GeneratedValue private Long id; private Long lastModifierId; private Long creatorId; private Date lastModifyDate; private Date createDate; }
Now there is a base class with a set of fields and when we see a similar set, you can simply follow it:
package ru.kabit.entity; import javax.persistence.Entity; @Entity public class Table1 extends HistoryEntity { private Long otherFieldTable1; public Long getOtherFieldTable1() { return otherFieldTable1; } public void setOtherFieldTable1(Long otherFieldTable1) { this.otherFieldTable1 = otherFieldTable1; } }
The advantages of this approach:
- The selected data is selected without subqueries, as they are in the same table.
- When rendering fields on a working project, you will not have to refactor anything.
Disadvantages :
- In some cases, the set of fields may be unnecessary, they will not work.
- Java does not have multiple inheritance, so if an entity fits two types, then this method does not fit
Conclusion
I described how to get rid of re-describing the set of fields in Hibernate entities, and also described the advantages and disadvantages of each. I hope that this article will be useful to you.