How to return the genarated ID in CrudDAOImpl.java when using Hibernate-JPA

111 Views Asked by At

I use the hibernate-JPA implementation (v5.6.1.Final) in my project.

I have implemented the data access layer as follows:

  1. Class Visualization Diagram.

Class Visualization Diagram before using CrudDAOImpl

1.1 Employee.java Entity

package com.elephasvacation.tms.web.entity;

import com.elephasvacation.tms.web.entity.enumeration.GenderTypes;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import javax.persistence.*;
import java.time.LocalDate;
import java.time.LocalDateTime;

@Entity
@Table(name = "employee")
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Employee implements SuperEntity {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id", nullable = false)
    private Integer id;

    @Column(name = "name", nullable = false, length = 200)
    private String name;

    @Lob
    @Column(name = "address")
    private String address;

    @Column(name = "date_of_birth")
    private LocalDate dateOfBirth;

    @Column(name = "nic", length = 45)
    private String nic;

    @Column(name = "contact", length = 45)
    private String contact;

    @Column(name = "email", length = 200)
    private String email;

    @Column(name = "gender", length = 20)
    private GenderTypes gender;

    @Column(name = "position", length = 45)
    private String position;

    @Column(name = "status", length = 45)
    private String status;

    @Column(name = "created")
    private LocalDateTime created;

    @Column(name = "updated")
    private LocalDateTime updated;

    /* Constructor with ID attribute. */
    public Employee(Integer id,
                    String name,
                    String address,
                    LocalDate dateOfBirth,
                    String nic,
                    String contact,
                    String email,
                    GenderTypes gender,
                    String position,
                    String status) {
        this.id = id;
        this.name = name;
        this.address = address;
        this.dateOfBirth = dateOfBirth;
        this.nic = nic;
        this.contact = contact;
        this.email = email;
        this.gender = gender;
        this.position = position;
        this.status = status;
    }

    /* Constructor without ID attribute. */
    public Employee(String name,
                    String address,
                    LocalDate dateOfBirth,
                    String nic,
                    String contact,
                    String email,
                    GenderTypes gender,
                    String position,
                    String status) {
        this.name = name;
        this.address = address;
        this.dateOfBirth = dateOfBirth;
        this.nic = nic;
        this.contact = contact;
        this.email = email;
        this.gender = gender;
        this.position = position;
        this.status = status;
    }

    @PrePersist
    public void creationTimeStamps() {
        created = LocalDateTime.now();
    }


    @PreUpdate
    public void updateTimeStamps() {
        updated = LocalDateTime.now();
    }

}

I want to return the Generated ID when an object is persisted successfully. So, I Implemented EmployeeDAOImpl.java as follows:

1.2 EmployeeDAOImpl.java

package com.elephasvacation.tms.web.dal.custom.impl;

import com.elephasvacation.tms.web.dal.custom.EmployeeDAO;
import com.elephasvacation.tms.web.entity.Employee;

import javax.persistence.EntityManager;
import javax.persistence.Query;
import java.util.List;

public class EmployeeDAOImpl implements EmployeeDAO {

    private EntityManager entityManager;

    @Override
    public void setEntityManager(EntityManager entityManager) {
        this.entityManager = entityManager;
    }

    @Override
    public Integer save(Employee employee) throws Exception {
        this.entityManager.persist(employee);
        //  call the flush method on EntityManager manually, because we need to get the Generated ID
        this.entityManager.flush();
        return employee.getId(); // here, generated ID will be returned.
    }

    @Override
    public void update(Employee employee) throws Exception {
        this.entityManager.merge(employee);
    }

    @Override
    public void delete(Integer key) throws Exception {
        this.entityManager.remove(this.entityManager.find(Employee.class, key));
    }

    @Override
    public Employee get(Integer key) throws Exception {
        return this.entityManager.find(Employee.class, key);
    }


    @Override
    public List<Employee> getAll() throws Exception {
        Query allEmployeesQuery = this.entityManager.createQuery("SELECT e FROM Employee e");
        return (List<Employee>) allEmployeesQuery.getResultList();
    }

}

I am refactoring the code as follows:

  • by creating CrudDAOImpl.java
  1. Class Visualization Diagram After Using CrudDAOImpl.java Class Visualization Diagram After Using CrudDAOImpl.java

2.1 CrudDAOImpl.java

package com.elephasvacation.tms.web.dal;

import com.elephasvacation.tms.web.entity.SuperEntity;

import javax.persistence.EntityManager;
import javax.persistence.TypedQuery;
import java.io.Serializable;
import java.lang.reflect.ParameterizedType;
import java.util.List;

public class CrudDAOImpl<T extends SuperEntity, K extends Serializable> implements CrudDAO<T, K> {

    private EntityManager entityManager;
    private Class<T> entityClass;

    public CrudDAOImpl() {
        this.entityClass =
                (Class<T>) (((ParameterizedType) (this.getClass().getGenericSuperclass())).getActualTypeArguments()[0]);
    }

  /** This method is used to pass the EntityManager to the lower level classes that extend the CrudDAOImpl class.
    *  */
    protected EntityManager getEntityManager(){
        return this.entityManager;
    }

    @Override
    public void setEntityManager(EntityManager entityManager) {
        this.entityManager = entityManager;
    }

    @Override
    public Integer save(T entity) throws Exception {

        /* If native hibernate is used in my project. I can do something like this;
        this will return the generated ID:
        * this.session.save(entity);
        *
        * Since I go with hibernate-JPA implementation I want to do the same thing in this method. */

        this.entityManager.persist(entity);
        this.entityManager.flush();

        return null; // I want to return the generated ID here.
    }

    @Override
    public void update(T entity) throws Exception {
        this.entityManager.merge(entity);
    }

    @Override
    public void delete(K key) throws Exception {
        this.entityManager.remove(key);
    }

    @Override
    public T get(K key) throws Exception {
        return this.entityManager.find(this.entityClass, key);
    }

    @Override
    public List<T> getAll() throws Exception {
        TypedQuery<T> query =
                this.entityManager.createQuery("SELECT " + (this.entityClass.getName()), this.entityClass);
        return query.getResultList();
    }
}

I would appreciate it if you could please suggest to me a way to return the generated ID when an object persists in the database. Thanks in advance.

1

There are 1 best solutions below

0
On

If you are interested here's what I have done. I have used SuperEntity.java as @HasnainAliBohra suggested.

  1. Add a getId() method to SuperEntity.java.
package com.elephasvacation.tms.web.entity;

import java.io.Serializable;

public interface SuperEntity extends Serializable {

    <T extends Serializable> T getId();
}
  • Mostly, generated ID will be a java.lang.Integer, So it is Serializable.
  1. Create a getter for the id attribute in Employee.java. Please note that I have used Project Lombok. So, the @Data annotation generates the getter for the id attribute.

Anyhow, getter method looks like this:

// Employee.java class
public Integer getId() {
  return id;
}
  1. Change the save() method in CrudDAOImpl.java as follows:
    @Override
    public Integer save(T entity) throws Exception {
        this.entityManager.persist(entity);
        this.entityManager.flush();
        return entity.getId(); // Let's return the generated ID here.
    }
  1. Testing what I have done (with JUnit4).
package com.elephasvacation.tms.web.dal.custom.impl;

import com.elephasvacation.tms.web.dal.DAOFactory;
import com.elephasvacation.tms.web.dal.DAOTypes;
import com.elephasvacation.tms.web.dal.custom.EmployeeDAO;
import com.elephasvacation.tms.web.entity.Employee;
import com.elephasvacation.tms.web.entity.enumeration.GenderTypes;
import com.elephasvacation.tms.web.util.HibernateUtil;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import java.time.LocalDate;

import static org.junit.Assert.assertNotNull;

public class EmployeeDAOImplTest {

    private final EmployeeDAO employeeDAO = DAOFactory.getInstance().getDAO(DAOTypes.EMPLOYEE);
    private EntityManagerFactory emf;
    private EntityManager em;

    @Before
    public void setUp() {
        try {
            /* get EntityManagerFactory. */
            this.emf = HibernateUtil.getEntityManagerFactory();
            /* creates EntityManager. */
            this.em = emf.createEntityManager();

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    @After
    public void tearDown() {
        /* close the EntityManagerFactory and EntityManager. */
        if (em != null) {
            em.close();
            emf.close();
        }
    }

    @Test
    public void save() {
        try {
            /* begins the transaction. */
            this.em.getTransaction().begin();

            /* set EntityManager. */
            this.employeeDAO.setEntityManager(this.em);

            /* creates a new Employee object. */
            Employee john = new Employee("John Doe",
                    "New York",
                    LocalDate.of(1991, 01, 01),
                    "112233445566",
                    "03321234567",
                    "[email protected]",
                    GenderTypes.MALE,
                    "Trainee",
                    "Active");

            /* saving the Employee. */
            Integer generatedEmployeeId = this.employeeDAO.save(john);

            /* assert */
            assertNotNull(generatedEmployeeId);

            /* print the generated ID on the terminal. */
            System.out.println("Generated Employee ID: " + generatedEmployeeId);

            /* committing the transaction. */
            this.em.getTransaction().commit();
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

}

  1. Test case did run successfully and the database record persisted in the employee table.

5.1 Terminal output Saving-An-Employee-Object-Terminal screenshot

5.2 Database record screenshot. Database-record-screenshot

Hope you find something useful, thank you.