Base entity class in JPA

hibernate

In Hibernate/JPA entities there are repeated fields and methods. Don’t repeat yourself and write a base class with @MappedSuperclass.

BaseEntity one: Minimal options

Common fields:

id: Table Id Column, Auto Increment. In entity model with @Id annotation.

version: Version column for Optimistic Lock has default ’0′ in table and managed from your database and EntityManager. In entity model with @Version annotation.

Common methods:

hashCode() and equals() very important. If you do not implement the methods you get problems later.

toString():I am using entity values for display e.g. customer.getFirstname(). It is more flexible for Swing, JavaFX or JSF components.


package com.devsniper.entitydemo.model;

import java.io.Serializable;

import javax.persistence.Basic;
import javax.persistence.Column;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.MappedSuperclass;
import javax.persistence.Version;

/**
 * Base Entity
 *
 * @author cem ikta
 */
@MappedSuperclass
public abstract class BaseEntity implements Serializable {

    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Basic(optional = false)
    @Column(name = "id", nullable = false, columnDefinition = "BIGINT UNSIGNED")
    protected Long id;

    @Column(name = "version")
    @Version
    private Long version;

    public Long getId() {
        return id;
    }

    public Long getVersion() {
        return version;
    }

    @Override
    public int hashCode() {
        int hash = 0;
        hash += (this.getId() != null ? this.getId().hashCode() : 0);

        return hash;
    }

    @Override
    public boolean equals(Object object) {
	if (this == object)
            return true;
        if (object == null)
            return false;
        if (getClass() != object.getClass())
            return false;

        BaseEntity other = (BaseEntity) object;
        if (this.getId() != other.getId() && (this.getId() == null || !this.id.equals(other.id))) {
            return false;
        }
        return true;
    }

    @Override
    public String toString() {
        return this.getClass().getName() + " [ID=" + id + "]";
    }
}

BaseEntity two: with audit informations

Common fields: createdBy, createdAt, updatedBy, updatedAt

It is sometimes important to know when and by whom the data were saved. I save creation date, modification date and user informations in table. I have String for user informations, I save only username without foreign key, then I have no relations with user table. With @PrePersist and @PreUpdate you don’t need to set the date manual every time. Set the user informations(createdBy and updatedBy) in your controllers not in models. Business logic must always remain in the right place.

package com.devsniper.entitydemo.model;

import java.util.Date;

import javax.persistence.Column;
import javax.persistence.MappedSuperclass;
import javax.persistence.PrePersist;
import javax.persistence.PreUpdate;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.validation.constraints.Size;

/**
 * Base Entity Audit
 *
 * @author cem ikta
 */
@MappedSuperclass
public abstract class BaseEntityAudit extends BaseEntity {

    @Column(name = "created_at")
    @Temporal(TemporalType.TIMESTAMP)
    private Date createdAt;

    @Size(max = 20)
    @Column(name = "created_by", length = 20)
    private String createdBy;

    @Column(name = "updated_at")
    @Temporal(TemporalType.TIMESTAMP)
    private Date updatedAt;

    @Size(max = 20)
    @Column(name = "updated_by", length = 20)
    private String updatedBy;

    public Date getCreatedAt() {
            return createdAt;
    }

    public void setCreatedAt(Date createdAt) {
            this.createdAt = createdAt;
    }

    public String getCreatedBy() {
            return createdBy;
    }

    public void setCreatedBy(String createdBy) {
            this.createdBy = createdBy;
    }

    public Date getUpdatedAt() {
            return updatedAt;
    }

    public void setUpdatedAt(Date updatedAt) {
            this.updatedAt = updatedAt;
    }

    public String getUpdatedBy() {
            return updatedBy;
    }

    public void setUpdatedBy(String updatedBy) {
            this.updatedBy = updatedBy;
    }

    /**
     * Sets createdAt before insert
     */
    @PrePersist
    public void setCreationDate() {
        this.createdAt = new Date();
    }

    /**
     * Sets updatedAt before update
     */
    @PreUpdate
    public void setChangeDate() {
        this.updatedAt = new Date();
    }

}

Sample usage of EntityBaseAudit:

If you use your table id columns with table name prefix e.g customer_id then use @AttributeOverride. Without prefix you remove @AttributeOverride.

@Entity
@Table(name = "customers")
@AttributeOverride(name = "id", column = @Column(name = "customer_id",
        nullable = false, columnDefinition = "BIGINT UNSIGNED"))
public class Customer extends BaseEntityAudit {

    // fields without id column ...

    public Customer() {
    }

    // getter and setter ...

}

4 Comments

  1. Eduardo
    Jan 06, 2014 @ 13:30:44

    Very nice! Thanks.

    Reply

  2. Arshad Imam
    Jul 19, 2014 @ 14:00:52

    @PrePersist is not working. Below is my class:-

    @MappedSuperclass
    public abstract class BaseEntity implements Serializable {

    private static final long serialVersionUID = -7407983690142578023L;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = “id”)
    protected Integer id;

    @Column(name = “VERSION”)
    @Version
    private Long version;

    @Column(name = “CREATED_DATE”)
    @Temporal(TemporalType.TIMESTAMP)
    private Date createdDate;

    @Column(name = “CREATED_BY”)
    private Integer createdBy;

    @Column(name = “MODIFIED_DATE”)
    @Temporal(TemporalType.TIMESTAMP)
    private Date modifiedDate;

    @Column(name = “MODIFIED_BY”)
    private Integer modifiedBy;

    public Integer getId() {
    return id;
    }

    public Long getVersion() {
    return version;
    }

    public Date getCreatedDate() {
    return createdDate;
    }

    public void setCreatedDate(Date createdDate) {
    this.createdDate = createdDate;
    }

    public Integer getCreatedBy() {
    return createdBy;
    }

    public void setCreatedBy(Integer createdBy) {
    this.createdBy = createdBy;
    }

    public Date getModifiedDate() {
    return modifiedDate;
    }

    public void setModifiedDate(Date modifiedDate) {
    this.modifiedDate = modifiedDate;
    }

    public Integer getModifiedBy() {
    return modifiedBy;
    }

    public void setModifiedBy(Integer modifiedBy) {
    this.modifiedBy = modifiedBy;
    }

    /**
    * Sets createdAt before insert
    */
    @PrePersist
    public void setCreationDate() {
    this.createdDate = new Date();
    }

    /**
    * Sets updatedAt before update
    */
    @PreUpdate
    public void setChangeDate() {
    this.modifiedDate = new Date();
    }

    @Override
    public int hashCode() {
    int hash = 0;
    hash += (this.getId() != null ? this.getId().hashCode() : 0);

    return hash;
    }

    @Override
    public boolean equals(Object object) {
    if (this == object)
    return true;
    if (object == null)
    return false;
    if (getClass() != object.getClass())
    return false;

    BaseEntity other = (BaseEntity) object;
    if (this.getId() != other.getId() && (this.getId() == null || !this.id.equals(other.id))) {
    return false;
    }
    return true;
    }

    @Override
    public String toString() {
    return this.getClass().getName() + ” [ID=" + id + "]“;
    }
    }

    Reply

    • Cem Ikta
      Jul 21, 2014 @ 19:02:57

      I use this code snippets with JPA/Hibernate, MySQL and PostgreSQL. It works!

      Reply

    • Tanmay
      Jun 18, 2017 @ 11:04:58

      Works for me….

      Reply

Leave a Reply