首先,考虑代码片段,
public class Employee
{
private Integer id;
private String firstname;
private String lastName;
private String department;
// public getters and setters here, i said PUBLIC
}
我创建了 2 个具有相同 id 的对象,并且所有字段的其余部分也相同。
Employee e1 = new Employee();
Employee e2 = new Employee();
e1.setId(100);
e2.setId(100);
//Prints false in console
System.out.println(e1.equals(e2));
整个问题从这里开始 在实时应用程序中,这必须返回 true。
因此,每个人都知道存在一个解决方案(实现 equals() 和 hashcode())
public boolean equals(Object o) {
if(o == null)
{
return false;
}
if (o == this)
{
return true;
}
if (getClass() != o.getClass())
{
return false;
}
Employee e = (Employee) o;
return (this.getId() == e.getId());
}
@Override
public int hashCode()
{
final int PRIME = 31;
int result = 1;
result = PRIME * result + getId();
return result;
}
现在,像往常一样:
Employee e1 = new Employee();
Employee e2 = new Employee();
e1.setId(100);
e2.setId(100);
//Prints 'true' now
System.out.println(e1.equals(e2));
Set<Employee> employees = new HashSet<Employee>();
employees.add(e1);
employees.add(e2);
//Prints ofcourse one objects(which was a requirement)
System.out.println(employees);
我正在阅读这篇优秀的文章 Don't Let Hibernate Steal Your Identity 。但有一件事我未能完全理解。上面讨论的整个问题及其解决方案以及链接的文章正在处理 2 个 Employee 对象 id 相同时的问题。
考虑一下,当我们为 id 字段提供一个私有(private) setter 时,其 id 字段由生成器类<生成/em> 在 hbm.xml 中提供。一旦我开始保留 Employee 对象(并且我无法更改 id),我发现不需要实现 equals 和 hashcode 方法。我确信我错过了一些东西,因为我的直觉告诉我,当一个特定的概念在网络上旋转太多时,它一定总是放在你面前,以避免一些常见的错误?当我有 id 字段的私有(private) setter 时,我是否仍然需要实现这两种方法?
最佳答案
如果实体定义了自然业务 key ,那么您应该将其用于 equals
和 hashCode
。自然标识符或业务 key 在所有实体状态转换中都是一致的,因此当 JPA 实体状态发生变化(例如从 New 到 Managed 到 Detached)时,hashCode
不会改变。
在您的示例中,您使用的是分配的
标识符,当您保留实体时,该标识符不会更改。
但是,如果您没有自然标识符,但有生成的 PRIMARY KEY
(例如 IDENTITY
、SEQUENCE
),那么你可以像这样实现 equals 和 hashCode :
@Entity
public class Book implements Identifiable<Long> {
@Id
@GeneratedValue
private Long id;
private String title;
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (!(o instanceof Book))
return false;
Book other = (Book) o;
return id != null &&
id.equals(other.getId());
}
@Override
public int hashCode() {
return getClass().hashCode();
}
//Getters and setters omitted for brevity
}
实体标识符可用于equals
和hashCode,但前提是hashCode
始终返回相同的值。这听起来可能是一件可怕的事情,因为它违背了在 HashSet
或 HashMap
中使用多个存储桶的目的。
但是,出于性能原因,您应该始终限制集合中存储的实体数量。您永远不应该在 @OneToMany
Set
中获取数千个实体,因为数据库端的性能损失比使用单个哈希存储桶高出多个数量级。
此版本的 equals
和 hashCode
之所以有效,是因为 hashCode
value does not change from one entity state to another ,并且仅当标识符不为 null
时才会检查该标识符。
关于java - 当我有私有(private) id 字段时,为什么 Hibernate 要求我们实现 equals/hashcode 方法?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/28268328/