Many times in our application, we face a situation where we have to compare two instances to check their equality for satisfying some business rules. In core java, we have hashCode() and equals() methods checking the equality of objects. But in hibernate, we need to take care of a few extra things as well.
Let’s learn what are those extra things we need to consider while implementing the entity identity and equality rules.
1. Managed Entities Represent Database Rows
We have already learned about hibernate entity lifecycle state. We know that hibernate tracks and manages the persistent objects only. Also, we know that a persistent object represents two things:
- An instance of a class in a particular Java virtual machine (JVM)
- A row (or rows) in a database table (or tables)
In runtime, the current Session instance is responsible for fetching, storing and managing an instance of an entity. As an entity represents a database row, it is worth noting that if we fetch the same row over and over again, there is no new Entity instance is created in the same Session. Rather, Session refreshes the existing entity instance and its fields information.
The above fact plays an important role in deciding how to compare entity instances within the same session or different sessions.
2. Entity Instances Fetched in Same Session
Requesting a persistent object again from the same Hibernate session returns the same Java instance of the entity class, which means that we can compare the objects using the standard Java ‘==
‘ equality syntax.
Let’s see a quick example:
public static void main(String[] args)
{
Session sessionOne = HibernateUtil.getSessionFactory().openSession();
sessionOne.beginTransaction();
// Create new Employee object
EmployeeEntity emp = new EmployeeEntity();
emp.setFirstName("Lokesh");
emp.setLastName("Gupta");
//Save employee
sessionOne.save(emp);
sessionOne.getTransaction().commit();
//Get employee id
Integer empId = emp.getEmployeeId();
//New session where we will fetch the employee two times and compare the objects
Session sessionTwo = HibernateUtil.getSessionFactory().openSession();
sessionTwo.beginTransaction();
EmployeeEntity employeeObj1 = (EmployeeEntity) sessionTwo.get(EmployeeEntity.class, empId);
EmployeeEntity employeeObj2 = (EmployeeEntity) sessionTwo.get(EmployeeEntity.class, empId);
//Checking equality
System.out.println(employeeObj1 == employeeObj2); //TRUE
HibernateUtil.shutdown();
}
You see above that we got two instances on EmployeeEntity and both are actually the same java object instance.
2. Entity Instances Fetched in Different Sessions
If you request a persistent object from more than one Hibernate session, Hibernate will provide distinct instances from each session, and the == operator will return false if you compare these object instances.
Let’s compare instances “emp
” and “employeeObj1
” in above example and you will get the result as false; because both are fetched in separate sessions.
System.out.println(emp == employeeObj1); //FALSE
System.out.println(emp.equals(employeeObj1)); //FALSE
So if we are comparing objects in two different sessions, we will need to implement the equals()
method on your Java persistence objects, which we should do as a best practice anyway. (Just don’t forget to override hashCode()
along with it.)
Hibernate wraps the actual object in a proxy so always use the getter methods instead of directly accessing the fields inside the hashCode() and equals() methods.
Now let’s add equals()
method as suggested and then see the behavior change while checking the equality of both instances on EmployeeEntity
.
@Entity
@Table(name = "Employee")
public class EmployeeEntity implements Serializable
{
private static final long serialVersionUID = -1798070786993154676L;
@Id
@Column(name = "ID", unique = true, nullable = false)
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private Integer employeeId;
@Column(name = "FIRST_NAME", unique = false, nullable = false, length = 100)
private String firstName;
@Column(name = "LAST_NAME", unique = false, nullable = false, length = 100)
private String lastName;
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof EmployeeEntity)) return false;
EmployeeEntity otherEmployee = (EmployeeEntity) o;
if (getEmployeeId() != null ?
!getEmployeeId().equals(otherEmployee.getEmployeeId()) : otherEmployee.getEmployeeId() != null)
return false;
if (getFirstName() != null ?
!getFirstName().equals(otherEmployee.getFirstName()) : otherEmployee.getFirstName() != null)
return false;
if (getLastName() != null ?
!getLastName().equals(otherEmployee.getLastName()) : otherEmployee.getLastName() != null)
return false;
return true;
}
@Override
public int hashCode() {
int result = getEmployeeId() != null ? getEmployeeId().hashCode() : 0;
result = 31 * result + (getFirstName() != null ? getFirstName().hashCode() : 0);
result = 31 * result + (getLastName() != null?getLastName().hashCode() : 0);
return result;
}
//Setters and Getters
}
Now let’s again check the equality using equals()
method. [‘==’ will return false, we know that].
System.out.println(emp.equals(employeeObj1)); //TRUE
Now both objects are equal logically as well as programmatically.
4. Conclusion
- Requesting a persistent object again from the same Hibernate session returns the “same instance” of a class.
- Requesting a persistent object from the different Hibernate sessions returns the “different instances” of a class.
- As a best practice, always implement equals() and hashCode() methods in the hibernate entities; and always compare them using
equals()
method only.
Happy Learning !!