一尘不染

Hibernate等于和代理

hibernate

我有一个抽象ID和版本属性的BaseEntity。此类还实现哈希码,并基于PK(id)属性进行等于。

BaseEntity{

    Long id;
    Long version;

public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + ((id == null) ? 0 : id.hashCode());
    return result;
}

public boolean equals(Object obj) {
    if (this == obj)
        return true;
    if (obj == null)
        return false;
    if (getClass() != obj.getClass())
        return false;
    BaseEntity other = (BaseEntity) obj;
    if (id == null) {
        if (other.id != null)
            return false;
    } else if (!id.equals(other.id))
        return false;
    return true;
}


}

现在两个实体A和B扩展了BaseEntity,如下所示

A extends BaseEntity{
    `B b`
     B getB(){return b;)
     void setB(B b){this.b=b;}
}

B extends BaseEntity{
}

object b1;
object a1;
a1.set(b1);
session.save(a1) //cascade save;

关闭会话以懒惰的b加载a并尝试a1.getB()。equals(b1)给出false,但如果我与a1.getB()。getId()。equals(b1.getId())比较,则得出真正的奇怪!我认为是因为Java辅助代理对象,无论如何要解决此问题?


阅读 251

收藏
2020-06-20

共1个答案

一尘不染

为了能够延迟加载a.b关联,Hibernate将b字段设置a为代理。代理是扩展B的类的实例,但不是B。因此,将非代理B实例与代理B实例进行比较时,您的equals()方法将始终失败,因为它会比较两个对象的类:

if (getClass() != obj.getClass())
    return false;

对于Hibernate实体,应将其替换为

if (!(obj instanceof B)) {
    return false;
}

另外请注意

  • hibernate建议不执行equals()hashCode()通过使用ID,而是通过使用天然标识符。使用ID实施它可能会引起问题,因为实体在保存并生成ID之前没有ID
  • 使用实体继承时,问题甚至更加严重。假设B是两个子实体B1和B2的超类。Hiberante a.b在加载之前不知道是哪种类型(B1或B2)。因此a.b将初始化为代理,该代理是B的子类,但不是B1或B2的子类。因此,hashCode()equals()方法应在B中实现,但不能在B1和B2中覆盖。如果两个B实例是B实例且具有相同的标识符,则应视为相等。
2020-06-20