我在#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
可以与JBoss Equals and HashCode article中的“eq / hC with buisness [sic] key”具有相似的优势,但其行为与开发人员的行为方式相同期望任何正常的Javabean对象都行为(即不必像数据库那样考虑对象):在被持久化到DB之前;在Transaction
取EAGER
个取模模式后;并且可以在LAZY
或Transaction
模式下随时EXTENDED
提取。
但是,确保hashCode
始终正确更新可能是一个真正的挑战。
这里有没有人有这种模式的经验,你能分享一下你的发现(正面和负面)吗?我对Gotchas非常感兴趣,但我对评论一点也不感兴趣如果没有关于它为什么不好的坚实论据,就会声称某些事情是“坏的”。
请注意,我知道The JPA hashCode() / equals() dilemma,但我不相信这种模式实际涵盖在讨论中。
此模式最初是作为一种在Collection
中加载嵌套@Entity
时避免问题的方法,例如Hibernate LazyInitializationException on find() with EAGER @ElementCollection中遇到的问题。
更新:一些评论者对现有方法充满热情。为避免疑问,我只对这种新模式的优点感兴趣。供你参考,并且还要求你停止说你如何相信equals / hashCode应该被实现,请注意我已经使用以下模式为我的@Entity
s已经好几年了:
@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);
}
答案 0 :(得分:1)
此商家密钥并非唯一,因此对于equals()来说,它似乎是一个糟糕的选择。
商业密钥1002添加了标签500和标签-502,商业密钥995是否添加了标签3和标签2?这些对象真的是平等吗?
对于32位数字的冲突相对较低的风险可能是可以容忍的,无论您的特定实体服务的目的是什么,但是将某些东西称为“模式”,人们希望它实际上是正确的,而不仅仅是任意不可能失败对于给定的数据大小。
答案 1 :(得分:0)
我写过,重写并删除了两三个长答案,解释了为什么我认为这是一个坏主意,但最终,所有这些都是对象身份的基本解释,我相信你明白了这一点。
我对这种模式的回应是它无法解决任何需要解决的问题。
所谓的“hashCode / equals问题”的解决方案非常简单。在创建实体时为其提供标识符。坚持下去。基础equals
和hashCode
就可以了。 不依赖于插入时由数据库或持久层创建的标识符。现在是positively ancient principle。
顺便说一句,对于实体而言,永远不会将equals
或hashCode
基于可变字段。这不是平等对实体的作用。实体不仅仅是一个国家的包,它们是一些国家恰好附加的身份。等式和哈希码必须基于身份,而不是状态。