我在 #hibernate IRC 上,有人与我分享了以下(部分)模式:
@Entity
public MyEntity() {
... primary key, object properties, getters/setters go here ...
@Column(nullable=false)
private int hashCode;
public MyEntity() {
hashCode += id;
}
private final Set<String> tags = Sets.newHashSet();
public void addTag(String tag) {
if(tags.add(tag)) {
hashCode += tag.hashCode();
}
}
public void removeTag(String tag) {
if(tags.remove(tag) {
hashCode -= tag.hashCode();
}
}
public void hashCode() {
return hashCode;
}
... http://www.artima.com/lejava/articles/equality.html style equals ...
}
有人称之为“分段更新的缓存hashCode”。(这绝对不是一些评论者所认为的“业务键”模式。 “业务键”模式需要一个具有唯一性约束的列,例如用户名,用于相等性测试)。
在JPA / Hibernate中使用时,它意味着@Entity可以像{{link1:JBoss Equals and HashCode article}}中的“eq / hC with business [sic] key”一样具有类似的优势,但表现出开发人员希望任何普通的JavaBean对象表现出的方式(即,在被持久化到数据库之前;在EAGER获取模式下的Transaction之后;以及在Transaction或EXTENDED模式下的LAZY获取中的任何时间)。
然而,确保hashCode始终正确更新可能是一个真正的挑战。
这个模式有没有人有经验并能分享一下他们的发现(无论是积极的还是消极的)? 我对 Gotchas 非常感兴趣,但我不太喜欢那些只是声称某些东西“不好”而没有实质性论据的评论。
请注意,我知道 JPA 的 hashCode() / equals() 问题,但我不认为这个模式在那个讨论中被涵盖了。
最初建议采用这种模式来避免在加载嵌套的 Collection
时出现问题,例如在 Hibernate 中使用 EAGER @ElementCollection 时 LazyInitializationException 的问题。
更新:一些评论者非常热情地讨论现有的方法。为了避免产生疑义,我只是对这个新模式的优点感兴趣。为了您的参考,并请您停止说您认为如何实现 equals/hashCode,请注意我已经在我的 @Entity
中使用以下模式几年了:
@Id
private UUID id = UUID.randomUUID();
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (!(obj instanceof MY_CLASS) || id == null)
return false;
MY_CLASS other = (MY_CLASS) obj;
return id.equals(other.id);
}
@Override
public int hashCode() {
Preconditions.checkNotNull(id, "id must be set before @Entity.hashCode can be called");
return id.hashCode();
}
我最近尝试了一些新的方法,以确定是否真的需要像这样单独使用一个方法
public boolean hasSameProperties(Note other) {
Preconditions.checkNotNull(other);
if (this == other)
return true;
return Objects.equal(source, other.source)
&& Objects.equal(title, other.title)
&& Objects.equal(tags, other.tags)
&& Objects.equal(contents, other.contents);
}
equals
基于集合???这就好像将人的身份基于他所借阅的书籍一样荒谬。 - maaartinusPerson
数据类包含一个Collection<Book>
(以及许多其他东西),那么如果它们的所有属性都相等,包括书籍的集合和存储书籍的方式,那么两个实例相等是一个合理的选择(顺便说一下,在 Java 中,equals
不等同于==
身份)。对于 JPA 管理的数据类,良好的做法是基于id
字段来构建equals
。 - fommilid
的equals
可以实现这种行为。 - maaartinus