Saturday, January 3, 2015

Hibernate Object Identity and Equality

There are several mismatches between the Object oriented system and Relation system. In that one of the important mismatch is Object identity and equality.

There are three ways to tackle identity: two ways in java world, and one is relational world. 

Java provides two ways for object identity and equality. 
  • If two objects are called identical when they point to the same reference in memory.
  • If two objects are considered equal when they contain similar data.
Java offers the equals() method and == operator to support equality and identity.
Employee employee1 = new  Employee("Ranga", 27, 35534);
Employee employee2 = employee1;
// identicality
System.out.println(employee1 == employee2); 
// equality
System.out.println(employee1.equals(employee2));

Note: When two objects are identical, they refer to the same memory location. Therefore, they have the same value and are definitely equal. However, two objects that are equal may not be identical since they may point to different locations in memory.
The identity of a Relational model is primary key.  Given a primary key we will 
always retrieve the same data.
To solve object oriented and relational mismatches( in that one identity and equality is one mismatch), orm tool is introduces. In that, Hibernate is one ORM tool. 
Lets see how Hibernate solve this identity and equality mismatch.
Entity (Employee.java) class:

package com.varasofttech.pojo;

import java.io.Serializable;

public class Employee implements Serializable {

private static final long serialVersionUID = -9001198124094210159L;

// properties
private long id; // identifier
private String name;
private int age;
private float salary;

public Employee() {
super();
}

public Employee(String name, int age, float salary) {
super();
this.name = name;
this.age = age;
this.salary = salary;
}

// setters and getters
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public float getSalary() {
return salary;
}
public void setSalary(float salary) {
this.salary = salary;
}

@Override
public String toString() {
return "Employee [id=" + id + ", name=" + name + ", age=" + age
+ ", salary=" + salary + "]";
}
}


Client Application (Application.java)

package com.varasofttech.client;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;

import com.varasofttech.pojo.Employee;
import com.varasofttech.util.HibernateUtil;

public class Application {
public static void main(String[] args) {

// Object Identity and Equality - Java

String name1 ="Ranga";
String name2 = "Ranga";
String name3 = new String("Ranga");

// identical
System.out.println(name1 == name2);
System.out.println(name1 == name3);

// equals
System.out.println(name1.equals(name2));
System.out.println(name1.equals(name3));

SessionFactory sessionFactory = HibernateUtil.getSessionFactory();
Session session1 = sessionFactory.openSession();

// Object Identity and Equality - Hibernate

Employee employee = new Employee("Ranga", 27, 30998);
Transaction transaction = session1.beginTransaction();
Long employeeId = (Long) session1.save(employee);
transaction.commit();

Employee employee1 = (Employee) session1.get(Employee.class, employeeId);
Employee employee2 = (Employee) session1.get(Employee.class, employeeId);

// identity
if( employee1 == employee2) {
System.out.println("Both employee objects are identical in same session");
} else {
System.out.println("Both employee objects are not identical in same session");
}

// equality
if( employee1.equals(employee2)) {
System.out.println("Both employee objects are equal in same session");
} else {
System.out.println("Both employee objects are not equal");
}

session1.close();

Session session2 = sessionFactory.openSession();
Employee employee3 = (Employee) session2.get(Employee.class, employeeId);

// identity
if( employee1 == employee3) {
System.out.println("Both employee objects are identical in another session");
} else {
System.out.println("Both employee objects are not identical in another session");
}

// equality
if( employee1.equals(employee3)) {
System.out.println("Both employee objects are equal in another session");
} else {
System.out.println("Both employee objects are not equal in another session");
}

session2.close();
sessionFactory.close();
}
}

Run the Client Application (Application.java)

true
false
true
true

Hibernate: select max(e_id) from employees
Hibernate: insert into employees (e_name, e_age, e_salary, e_id) values (?, ?, ?, ?)
Both employee objects are identical in same session
Both employee objects are equal in same session
Hibernate: select employee0_.e_id as e_id1_0_0_, employee0_.e_name as e_name2_0_0_, employee0_.e_age as e_age3_0_0_, employee0_.e_salary as e_salary4_0_0_ from employees employee0_ where employee0_.e_id=?
Both employee objects are not identical in another session
Both employee objects are not equal in another session

Now override equals() and  hashcode() in Entity(Employee.java) class.

package com.varasofttech.pojo;
import java.io.Serializable;

public class Employee implements Serializable {

private static final long serialVersionUID = -9001198124094210159L;

// properties
private long id; // identifier
private String name;
private int age;
private float salary;

public Employee() {
super();
}

public Employee(String name, int age, float salary) {
super();
this.name = name;
this.age = age;
this.salary = salary;
}

// setters and getters
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public float getSalary() {
return salary;
}
public void setSalary(float salary) {
this.salary = salary;
}

@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + age;
result = prime * result + (int) (id ^ (id >>> 32));
result = prime * result + ((name == null) ? 0 : name.hashCode());
result = prime * result + Float.floatToIntBits(salary);
return result;
}

@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
Employee other = (Employee) obj;
if (age != other.age)
return false;
if (id != other.id)
return false;
if (name == null) {
if (other.name != null)
return false;
} else if (!name.equals(other.name))
return false;
if (Float.floatToIntBits(salary) != Float.floatToIntBits(other.salary))
return false;
return true;
}

@Override
public String toString() {
return "Employee [id=" + id + ", name=" + name + ", age=" + age
+ ", salary=" + salary + "]";
}
}

Now run the Client Application (Application.java)

true
false
true
true

Hibernate: select max(e_id) from employees
Hibernate: insert into employees (e_name, e_age, e_salary, e_id) values (?, ?, ?, ?)
Both employee objects are identical in same session
Both employee objects are equal in same session
Hibernate: select employee0_.e_id as e_id1_0_0_, employee0_.e_name as e_name2_0_0_, employee0_.e_age as e_age3_0_0_, employee0_.e_salary as e_salary4_0_0_ from employees employee0_ where employee0_.e_id=?
Both employee objects are not identical in another session
Both employee objects are equal in another session

0 comments: