考虑我们有一个类MyEntity
,它有一些带有getter和setter的字段。此外,课程EntityA
和EntityB
会延伸MyEntity
。 MyEntityA
中的某些字段不在MyEntityB
中,反之亦然。在我们讨论实体时,EntityA
和EntityB
确实有自己的equals
- 方法看起来像
@Override
public boolean equals(Object other) {
if ((this == other))
return true;
if ((other == null))
return false;
if (!(other instanceof EntityA))
return false;
EntityA castOther = (EntityA) other;
return ((this.getId() == castOther.getId()) || (this.getId() != null && castOther.getId() != null && this.getId().equals(castOther.getId())));
}
此equals
- 方法用于hibernate以识别唯一实体。
现在我想将EntityA
的实例与EntityB
的实例进行比较。如果MyEntity
中的所有字段都匹配,我将它们定义为相同。
为了检查这个,我让eclipse为我生成equals方法并将其复制到类似isEqualWithRegardsToContent(MyEntity other)
的方法。
我发现这种方法存在一个大问题:
如果某人曾向其中一个实体添加新列并且未更新isEqualWithRegardsToContent(MyEntity other)
- 方法,则会出现错误:实体可能被视为内容相同,尽管它们不是。< / p>
我没有看到单元测试会对此有所帮助。
你有什么最佳做法吗?
答案 0 :(得分:2)
一般来说,在处理继承树时,不可能拥有完全正常的功能。 superclass.equals(subclass)
不会返回与subclass.equals(superclass)
相同的结果,打破对称性(这是相等的基本合同 - 如果a.eq(b)
,那么b.eq(a)
)。
您只能在顶层实现equals(),从而从超类的角度比较整个层次结构。这将有效,但不会被&#34;所有字段&#34; (只有超类中的那些)。通常可以通过主键来比较实体
就我个人而言,我通常不会将2 - equals()
和hashcode()
i保留用于非多态的简单数据存储类(或用于在地图中查找的键)。
在此处查看详细信息 - http://www.angelikalanger.com/Articles/JavaSolutions/SecretsOfEquals/Equals-2.html
答案 1 :(得分:1)
比如说,你在超类中有equals()
方法来比较常见属性。
在子类equals()
中,您可以先调用super.equals()
,然后,如果比较对象也是此类,则仅比较特定属性。所以你在EntityA
写道:
@Override
public boolean equals(Object o) {
boolean eq = super.equals(o);
if (eq && o instanceof EntityA) {
EntityA e = (EntityA) o;
return Objects.equals(this.propOne, e.propOne)
&& Objects.equals(this.propTwo, e.propTwo)
&& // compare other properties
} else
return eq;
}
这样,同一具体类的对象将通过完整的属性集进行比较,包括公共属性和特定属性,不同类的实例将仅通过公共属性进行比较。虽然这是违反合同传递属性的非标准方式,但它可以解决您的特定问题。
答案 2 :(得分:0)
课程&#39; equals()
方法应该只适用于该类的其他实例。如果您想将EntityA
和EntityB
与equals()
进行比较,则应在equals()
(以及MyEntity
)上定义hashCode()
方法,并且EntityA
和EntityB
都不应该有equals()
个方法。否则,你很可能会与contract for equals()
发生冲突。像Hibernate这样的库依赖equals()
正确地遵守合同。
答案 3 :(得分:0)
如果我正确理解您的问题:
MyEntity
的课程,缺少getId
字段EntityA
和EntityB
,它们都定义了id
字段但形成了不同的生成器EntityA
(resp。EntityB
)的2个对象时,他们比较相等,当且仅当他们的id字段具有相同的值时 - 我假设在那种情况下所有字段都继承自{{1具有相同的值MyEntity
对象与EntityA
对象进行比较时,如果且仅当从EntityB
继承的所有字段相等时,它们应该相等。以下是您可以做的事情:
MyEntity
中声明equals
方法,当且仅当所有字段都相等时才返回true - 如果您不能使用MyEntity
方法,请将方法命名为{{1} (例如)在子类equals
中声明相等的方法(分别为ABequals
)
EntityA
在这种情况下,必须在使用所有字段的EntityB
类中实现哈希方法,并且不应在子类中覆盖它。这样,您可以确保两个比较相等的对象具有相同的哈希值 - 上面的定义已经保证@Override
public boolean equals(Object other) {
if ((this == other))
return true;
if ((other == null))
return false;
if (!(other instanceof EntityA))
return MyEntity.equals(other); // or return ABequals(other);
EntityA castOther = (EntityA) other;
return ((this.getId() == castOther.getId()) || (this.getId() != null && castOther.getId() != null && this.getId().equals(castOther.getId())));
}
函数是等价关系。