Duplicate Field Set in Hibernate


The problem whose solutions 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 database normalization, but this is inconvenient for sampling and affects the performance, no one needs extra joins for the sake of several columns.
So, let's imagine there is some kind of accounting system, in it it is important in any entity to keep a history of who changed, who created, when the last changes were, by whom they were created. In fact, in any project you can find similar sets and not one. As a result, when programmers create these fields, at best 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 problem can be solved using the @Embeddable entity:

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;
    /* getters and setters */
}

We remove the fields from the class, insert one Embedded property. In practice, walking through the code and adding an extra getter before calling these fields is not difficult, 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;
    /* getters and setters */
}

If at least one field from HistoryFields is filled, then a HistoryFields object will be created and these fields will be filled, otherwise the object will be null, which, by the way, is very convenient when writing logic. The names of the fields in the database can be different, to change them the annotation @AttributeOverride is used .

The advantages of this approach:
  • The logical group of fields is singled out as a separate entity, the fields will always be called the same, it would never occur to anyone to write them “in the right way”
  • The selected data is selected without subqueries, since it lies in the same table
  • Search criteria for these fields will be unchanged.
  • In essence, there can be several such fields

Disadvantages :
  • In some cases, a set of fields may be redundant; you cannot remove them.
  • When refactoring, you have to change the JSP by hand, it’s difficult to do this in a large project, you have to double-check everything, or make additional getters that get data from the Embedded field

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;
     /* getters and setters */
}

Now there is a base class with a set of fields, and when we see a similar set, we can just inherit from 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, since it lies in the same table
  • When making fields on a working project, you don’t have to refactor anything

Disadvantages :
  • In some cases, a set of fields may be redundant; you cannot remove them.
  • There is no multiple inheritance in Java, so if an entity is suitable for two types, then this method is not suitable

Conclusion


I talked about how to get rid of the repeated description of a set of fields in Hibernate entities, and also described the advantages and disadvantages of each. I hope you find this article helpful.

Also popular now: