10

在 Java 中为 UDT提供#equals实现时,条件之一是传递的参数对象必须是当前类的实例,否则我们会快速失败,return false请参阅Effective Java (EJ2)。但是,在使用 Hibernate 4 时,由于延迟加载,我们最终会得到 javassist 代理实例,这种#equals情况将失败。克服这个问题的最佳选择是什么?我能想到的几个选择是:

  • 扩展equals实现以考虑代理情况。缺点:可维护性代价、对 Hibernate 代理基础设施的硬连线依赖、hacky、实体或域模型应该与所使用的 ORM 无关,即因为它们可能在不需要 ORM 的不同上下文中重用,例如 Swing UI。
  • 在调用之前检查它是否是代理equals。缺点:并不总是可能的,即处理集合和隐式调用equals,例如 Map。
  • 避免使用延迟加载。缺点:在所有用例中都不合理也不高效。

更新

再次回顾 EJ2 我相信以下内容适用于所有场景(Type-Type、Type-Proxy、Proxy-Type 和 Proxy-Proxy),但正如下面的评论之一所指出的,如果将 Type 与完全不同的类型,例如Person.equals(Employee),两者都使用相同的等于 EJ2 标准。

    if (this.getClass() != anObject.getClass())
    {
        return anObject.equals(this);
    }
4

4 回答 4

10

我偶然发现了同样的问题。我修复的方法是更改.equals​​ - 方法。

@Override
public boolean equals(Object obj) {
    if (this == obj)
        return true;
    if (obj == null)
        return false;
    if (!getClass().isAssignableFrom(obj.getClass()))
        return false;
    AbstractEntity other = (AbstractEntity) obj;
    if (getId() == null) {
        if (other.getId() != null)
            return false;
    } else if (!getId().equals(other.getId()))
        return false;
    return true;

诀窍是不要比较类是否相同,而是使用isAssignableFrom- 方法。另一个技巧是不使用直接属性 ( other.id),而是使用 get 方法 ( other.getId())

于 2013-08-15T11:32:22.823 回答
8

我没有评论 Willem de Wit 答案的声誉。比我需要发布一个新的答案。

要解决 djechelon 的问题,您应该替换此行:

if (!getClass().isAssignableFrom(obj.getClass()))

为了

if ( !obj.getClass().isAssignableFrom(getClass()) && !getClass().isAssignableFrom(obj.getClass()) )

然后,您将确保 equals 将适用于所有场景(Type-Type、Type-Proxy、Proxy-Type 和 Proxy-Proxy)。

我也没有声望投票给你的答案。我好惨!

于 2014-03-11T12:45:25.867 回答
1

您可以做两件事: 1. 将 equals 更改为使用 instanceof 而不是类相等。代理的类型不等于实体的类型,而是扩展了实体的类型。

  1. 打开代理以获取实体本身(有几个休眠工具可以帮助您做到这一点)
于 2013-03-24T12:10:42.087 回答
1

上面 Dhansen 的答案很接近,但对我来说(使用 Hibernate)这解决了这个问题:

if (!Hibernate.getClass(this).equals(Hibernate.getClass(obj))) { return false; } 正如Hans-Peter Störr 博士所建议的那样

同样重要的是始终使用上面 Willem de Wit 所建议的“吸气剂”。

于 2017-04-27T14:16:32.397 回答