Спящая Ленивая Загрузка, Прокси и Наследование - PullRequest
3 голосов
/ 11 января 2012

У меня проблема с отложенной загрузкой в ​​спящем режиме при работе с наследованием. У меня есть один объект, который ссылается на второй объект, который находится в подклассе. Я хочу, чтобы ссылка загружалась лениво, но это вызывает ошибки в моих методах .equals ().

В приведенном ниже коде, если вы вызываете equals () для экземпляра A, проверка завершается неудачно в функции C.equals () при проверке того, является ли Object o экземпляром C. Это происходит сбой, поскольку другой объект является фактически Hibernate-прокси, созданный javassist, который расширяет B, а не C.

Я понимаю, что Hibernate не может создать прокси типа C, не заходя в базу данных и тем самым прерывая ленивую загрузку. Есть ли способ заставить функцию getB () в классе A возвращать конкретный экземпляр B вместо прокси (лениво)? Я пытался использовать Hibernate-специфическую аннотацию @LazyToOne (LazyToOneOption.NO_PROXY) в методе getB (), но безрезультатно.

@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 ]

1 голос
/ 12 января 2012

Оказывается, я был на правильном пути, пытаясь использовать аннотацию @LazyToOne (LazyToOneOption.NO_PROXY). Это не работало для меня из коробки, потому что я еще не запустил на нем инструмент для улучшения байт-кода Hibernate. Инструкции для этого можно найти здесь:

19.1.7. Использование ленивой выборки свойств

0 голосов
/ 11 января 2012

Независимо от того, являются ли объекты объектами и / или загружены с отложенной загрузкой, практически невозможно соблюдать контракт равных и иметь специализацию равных в подклассе, который использует instanceof.В самом деле, вы бы оказались в ситуации, когда у вас будет b1.equals(c1) == true, но c1.equals(b1) == false.

Итак, я думаю, что суперкласс (B) должен определить равенства и сделать его окончательным, потому что все подклассыследует использовать метод базового класса equals.

Тем не менее, ваш метод equals в B неверен:

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

Это означает, что реализация объекта equals должна возвращать true дляиметь два равных экземпляра B.Это означает, что два экземпляра B равны, только если они являются одним и тем же объектом.

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

Почему класс B проверяет, является ли другой экземпляр экземпляром C. Он должен проверять, является ли другой экземплярэкземпляр B.

Так как в конце два B равны, если они имеют одинаковый идентификатор, и, так как идентификаторы должны быть уникальными для всего дерева наследования, вы в безопасности, если вы сделаете этот метод equals окончательным.

0 голосов
/ 11 января 2012

Возможно, вы захотите попробовать изменить свойство fetch в getB () на FetchType.EAGER. Надеюсь, это поможет.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...