我在 #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 ...
}
可以将其称为“分段更新的缓存哈希码”。 (这绝对不是一些评论者似乎相信的“业务键”模式。“业务键”模式需要一个具有唯一性约束的列,如用户名,用于平等测试)。
在 JPA/Hibernate 中使用时,这意味着 @Entity
可以具有与 JBoss Equals and HashCode article 中的“eq/hC with buisness [sic] key”类似的优点。 ,但其行为方式与开发人员期望的任何普通 Javabean 对象的行为方式相同(即无需将对象视为数据库行):在被持久化到 DB 之前;在 EAGER
获取模式下的 Transaction
之后;并在任何时候使用 LAZY
在 Transaction
或 EXTENDED
模式下获取。
但是,确保 hashCode
始终正确更新可能是一个真正的挑战。
这里有人对这种模式有任何经验吗?您能否分享您对此的发现(积极的和消极的)?我对 Gotchas 非常感兴趣,但我对评论完全不感兴趣声称某些东西是“坏的”,却没有关于为什么它是坏的可靠论据。
请注意,我知道 The JPA hashCode() / equals() dilemma ,但我认为该讨论实际上并未涵盖这种模式。
这种模式最初是为了避免在 @Entity
中加载嵌套的 Collection
时出现问题而提出的,例如在 Hibernate LazyInitializationException on find() with EAGER @ElementCollection 中遇到的问题。 .
更新:一些评论者对现有方法非常感兴趣。为免生疑问,我只对这种新模式的优点感兴趣。供您引用,也请您不要再说您认为 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);
}
最佳答案
这个业务 key 不是唯一的,所以它似乎是 equals() 的一个糟糕选择。
业务 key 1002 添加了标签 500 和标签 -502,业务 key 995 添加了标签 3 和标签 2?这些对象真的意味着相等吗?
对于您的特定实体服务的任何目的,32 位数字的相对较低的冲突风险可能是可以容忍的,但是将某些东西称为“模式”时,人们希望它实际上是正确的,而不仅仅是任意不可能失败对于给定的数据大小。
关于java - 这个 JPA "cached hashCode"模式有什么陷阱吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11730379/