3

在处理继承时,我遇到了休眠中延迟加载的问题。我有一个实体引用了第二个子类实体。我希望引用延迟加载,但这会导致我的 .equals() 方法出错。

在下面的代码中,如果在 A 的实例上调用 equals(),则在检查 Object o 是否是 C 的实例时,C.equals() 函数中的检查失败。它失败是因为另一个对象实际上是 Hibernate由 javassist 创建的代理,它扩展了 B,而不是 C。

我知道 Hibernate 不能在不访问数据库的情况下创建 C 类型的代理,从而破坏延迟加载。有没有办法让 A 类中的 getB() 函数返回具体的 B 实例而不是代理(懒惰地)?我尝试在 getB() 方法上使用 Hibernate 特定的 @LazyToOne(LazyToOneOption.NO_PROXY) 注释无济于事。

@Entity @Table(name="a")
public class A {
    private B b;

    @ManyToOne(fetch=FetchType.LAZY)
    @JoinColumn(name="b")
    public B getB() {
        return this.b;
    }

    public boolean equals(final Object o) {
        if (o == null) {
            return false;
        }

        if (!(o instanceof A)) {
            return false;
        }
        final A other = (A) o;
        return this.getB().equals(o.getB());
    }
}

@Entity @Table(name="b")
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(
    name="type",
    discriminatorType=DiscriminatorType.STRING
)
public abstract class B {
   private long id;

   public boolean equals(final Object obj) {
       if (this == obj) {
           return true;
       }
       if (obj == null) {
           return false;
       }
       if (!(obj instanceof B)) {
           return false;
       }
       final B b = (B) o;
       return this.getId().equals(b.getId());
    }
}

@Entity @DiscriminatorValue("c")
public class C extends B {
   private String s;

   public boolean equals(Object obj) {
       if (this == obj) {
           return true;
       }
       if (!super.equals(obj)) {
           return false;
       }
       if (obj == null) {
           return false;
       }
       if (!super.equals(obj)) {
           return false;
       }
       if (!(obj instanceof C)) {
           return false;
       }
       final C other = (C) o;
       if (this.getS() == null) {
           if (other.getS() != null) {
               return false;
           }
       } else if (!this.getS().equals(other.getS())) {
           return false;
       }
       return true;
    }
}

@Entity @DiscriminatorValue("d")
public class D extends B {
    // Other implementation of B
}
4

3 回答 3

1

事实证明,我在尝试使用 @LazyToOne(LazyToOneOption.NO_PROXY) 注释时处于正确的跟踪状态。它对我来说不是开箱即用的,因为我还没有在它上面运行 Hibernate 字节码增强器工具。可以在此处找到相关说明:

19.1.7。使用惰性属性获取

于 2012-01-12T15:19:00.370 回答
0

您可能想尝试将fetchgetB() 上的属性更改为FetchType.EAGER. 希望这可以帮助。

于 2012-01-11T16:52:09.070 回答
0

无论对象是实体和/或延迟加载的对象,实际上都不可能遵守 equals 的约定并在使用 instanceof 的子类中专门化 equals。确实,您将处于您会遇到的情况b1.equals(c1) == true,但是c1.equals(b1) == false

所以,我认为超类(B)应该定义equals,并使其成为final,因为所有子类都应该使用基类equals方法。

也就是说,您在 B 中的 equals 方法不正确:

if (!super.equals(obj)) {
   return false;
}

这意味着 equals 的 Object 实现必须返回 true 才能使两个 B 实例相等。这意味着两个 B 实例只有在它们是同一个对象时才相等。

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

为什么B类检查另一个实例是C的实例。它应该检查另一个实例是否是B的实例。

因为最后,如果两个 B 具有相同的 ID,则它们是相等的,并且由于所有继承树的 ID 必须是唯一的,因此如果将此 equals 方法设为 final,则您是安全的。

于 2012-01-11T16:53:58.703 回答