Hibernate有很多方法,每一种方法都有自己实现的过程,这里详述Hibernate两种方法的实现Hibernate equals()和Hibernate hashCode()。
实现Hibernate equals()和hashCode()如果你有如下需求,你必须重载 equals() 和 hashCode()方法:
想把持久类的实例放入Set中(当表示多值关联时,推荐这么做)
想重用脱管实例
Hibernate保证,仅在特定会话范围内,持久化标识(数据库的行)和Java标识是等价的。因此,一旦 我们混合了从不同会话中获取的实例,如果希望Set有明确的语义,就必 须实现equals() 和hashCode()。
实现Hibernate equals()/HibernatehashCode()最显而易见的方法是比较两个对象标识符的值。如果值相同,则两个对象对应于数据库的同一行,因此它们是相等的(如果都被添加到 Set,则在Set中只有一个元素)。
不幸的是,对生成的标识不能 使用这种方法。Hibernate仅对那些持久化对象赋标识值,一个新创建的实例将不会有任何标识值。此外, 如果一个实例没有被保存(unsaved),并且它当前正在一个Set中,保存它将会给这个对象 赋一个标识值。
如果Hibernate equals() 和Hibernate hashCode()是基于标识值 实现的,则其哈希码将会改变,这违反了Set的契约。建议去Hibernate的站点阅读关于这个 问题的全部讨论。
注意:这不是Hibernate的问题,而是一般的Java对象标识和Java对象等价的语义问题。
我们建议使用业务键值相等(Business key equality)来实现equals() 和 hashCode()。业务键值相等的意思是,equals()方法 仅仅比较形成业务键的属性,它能在现实世界里标识我们的实例(是一个自然的候选码)。
- public class Cat {
- ...
- public boolean equals(Object other) {
- if (this == other) return true;
- if ( !(other instanceof Cat) ) return false;
- final Cat cat = (Cat) other;
- if ( !cat.getLitterId().equals( getLitterId() ) ) return false;
- if ( !cat.getMother().equals( getMother() ) ) return false;
- return true;
- }
- public int hashCode() {
- int result;
- result = getMother().hashCode();
- result = 29 * result + getLitterId();
- return result;
- }
- }
注意:
业务键不必像数据库的主键那样固定不变。对业务键而言,不可变或唯一的属性是不错的选择。
【编辑推荐】