Hibernate延迟加载,代理和继承

时间:2012-01-11 16:42:44

标签: java hibernate orm lazy-loading lazy-initialization

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

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

3 个答案:

答案 0 :(得分:1)

事实证明,我正在尝试使用@LazyToOne(LazyToOneOption.NO_PROXY)注释进行正确的跟踪。这对我来说不起作用,因为我还没有运行Hibernate字节码增强工具。有关这方面的说明,请访问:

19.1.7. Using lazy property fetching

答案 1 :(得分:0)

您可能想尝试将getB()上的fetch属性更改为FetchType.EAGER。希望这会有所帮助。

答案 2 :(得分:0)

无论对象是实体还是/或延迟加载,实际上都不可能尊重equals的契约,并且在使用instanceof的子类中具有equals的特化。实际上,您将处于b1.equals(c1) == truec1.equals(b1) == false的情况。

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

那就是说,你在B中的等于方法是不对的:

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

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

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

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

最后,如果它们具有相同的ID,则两个B是相等的,并且因为所有继承树的ID必须是唯一的,所以如果你使这个等于方法最终,那么你是安全的。