Hibernate用户指南的第2.1.5节说明了
如果您要处理Session之外的实体(无论是瞬态还是分离)......您应该考虑实现equals / hashCode。
忽略在诸如Set之类的集合中使用这些实体的明显原因,我们希望或需要覆盖hibernate doc中建议的现有equals / hashcode的其他情况是什么?
答案 0 :(得分:1)
首先,实体相等是一个域细节,最好从业务代码中抽象出来。显而易见的最佳位置是实体本身。此外,相等规则通常可能基于实体状态或其他域规则而有所不同,因此覆盖equals
方法可确保这些规则不仅适用于业务代码,还适用于集合使用和hibernate的会话管理。
考虑一个基于复合键的实体,它使用几个字段来构成平等。以下哪些业务代码看起来更具吸引力,并且变化最不严格:
public void someBusinessFunction(EntityA e1, EntityA e2) {
if(e1.equals(e2))
throw new SomeEqualityException();
// do logic
}
public void someBusinessFunction2(EntityA e1, EntityA e2) {
if(e1.getId().getFieldA().equals(e2.getId().getFieldA()) &&
e1.getId().getFieldB().equals(e2.getId().getFieldB()) &&
e1.getId().getFieldC().equals(e2.getId().getFieldC())) {
throw new SomeEqualityException();
}
// do logic
}
从业务代码的角度来看,我们不应该关心什么是平等。所有代码都关心的是同一个类的2个实例是否彼此相等。使用什么规则来确定用例是无关紧要的。
简而言之,通过抽象应该首先抽象的细节,这只是一个很好的编程。
修改强>
更具体的是Java语言本身,Object
的股票相等性仅比较两个操作数是否通过==
运算符指向同一物理实例。仅当两个实例指向相同的内存位置时,此选项才有效。
可以通过多个事务获得相同的域实体,因此可以指向两个不同的内存位置,因为它们曾经由不同的会话管理。在这种情况下,默认的equals
方法将返回false,这可能是不合需要的。
通过重写equals
方法,您可以明确地确保上述情况始终返回true
的相等性,无论实例是如何获得的以及它可以存储在内存中的位置。
此外,java doc明确指出当覆盖hashCode
以维持equals
和hashCode
之间的契约时,覆盖equals
会发生,以便在对象相等为真时,哈希码也是相同的。
答案 1 :(得分:1)
看起来2.1.5不是一个非常明确的部分。
如果您要处理Session之外的实体(无论是瞬态还是分离)......您应该考虑实现equals / hashCode。
它并不意味着"如果你打算使用重新附加的分离实例"你必须覆盖equals()和hashCode()方法。
这意味着其他的事情。如果从会话中获得具有相同id的两个对象,则它将是相同的对象(在内存中)。
Set<Person> set = new HashSet<Person>();
Session session = factory.openSession();
Person p1 = session.get( Person.class, 1 );
Person p2 = session.get( Person.class, 1);
set.put(p1);
set.put(p2);
session.close();
由于set
和p1 == p2
使用默认Person
和equals()
,hashCode()
将是一个对象。
如果从两个会话中获得两个具有相同id的对象,则内存中将有两个对象。
Set<Person> set = new HashSet<Person>();
Session session1 = factory.openSession();
Person p1 = session1.get( Person.class, 1 );
session1.close();
Session session2 = factory.openSession();
Person p2 = session1.get( Person.class, 1 );
session2.close();
set.put(p1);
set.put(p2);
由于set
,p1 != p2
将是两个对象。
2.1.5中的文档只是警告您,如果您想在集合(或其他此类集合)的会话之外使用持久对象,则需要实现equals()
和hashCode()
或制作其他(!)努力获得正确的工作集合。
答案 2 :(得分:0)
如果您目前不在Set
(或Collection
中使用您的已分离实体,请考虑remove(Object)
及类似情况依赖于equals
方法的方法,并不意味着您(或您的同事)在您忘记equals
被破坏的六个月后不会将这些实体放入集合中。这对我来说是个好理由。