Hiberate 实体等价和等同

在我们的应用中,很多时候我们都面临着这样的情况,我们必须比较两个对象以检查它们的相等性以满足某些业务规则。 在核心 Java 中,我们已经掌握了检查对象是否相等的知识,但是在 Hiberate 下,我们还需要注意一些额外的事情。 让我们了解一下那些额外的概念。

我们已经了解了 Hiberate 实体在其生命周期中的各种状态。 在那里,我们讨论了 Hiberate 大多数仅适用于持久对象。 众所周知,当我们在 hibernate 中有一个持久对象时,该对象代表了两个:

  • 特定 Java 虚拟机(JVM)中类的实例
  • 数据库表中的一行(或多行)

我们对第一个概念了解足够。 我将集中讨论第二点。

从同一会话中获取的对象

从同一 Hibernate 会话再次请求持久对象会返回类的相同 Java 实例,这意味着您可以使用标准 Java ==等式语法比较这些对象。

让我们看一个简单的例子:

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 genEmpId = 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, genEmpId);
	EmployeeEntity employeeObj2 = (EmployeeEntity) sessionTwo.get(EmployeeEntity.class, genEmpId);

	//Checking equality 
	System.out.println(employeeObj1 == employeeObj2);

	HibernateUtil.shutdown();
}

Output:

true

您可以在上面看到,我们在EmployeeEntity上有两个实例,并且它们实际上都是同一个 Java 对象实例。

从不同会话中获取的对象

如果您从多个会话中向请求一个持久对象,则 Hibernate 将为每个会话提供不同的实例,如果您比较这些对象实例,则==运算符将返回false

让我们比较上面示例中的实例“emp”和“employeeObj1”,结果将为假; 因为两者都是在单独的会话中获取的。

System.out.println(emp == employeeObj1);
System.out.println(emp.equals(employeeObj1));

Output:

false
false

因此,如果要在两个不同的会话中比较对象,则需要在 Java 持久化对象上实现equals()方法,无论如何,您都应该经常执行此方法。 (请不要忘记将hashCode()与它一起覆盖。)

阅读更多信息覆盖hashCode()equals()方法

Hibernate 将实际对象包装在代理中,因此请始终在内部使用设置器方法而不是实际属性进行比较。

现在,根据建议添加equals()方法,然后在检查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
}

现在,使用equals()方法再次检查是否相等。 (==将返回false,我们知道)。

System.out.println(emp.equals(employeeObj1));

Output:

true

现在,两个对象在逻辑上和程序上都是相等的。

项目要点

  1. 从相同的 Hibernate 会话再次请求持久对象将返回类的“相同 Java 实例”。
  2. 从不同的 Hibernate 会话中请求一个持久对象,将返回一个类的“不同的 Java 实例”。
  3. 最佳实践是,始终在 Hiberate 实体中实现equals()hashCode()方法; 并始终仅使用equals()方法进行比较。