Pregunta

Tengo un problema con la carga perezosa en Hibernate al tratar con la herencia. Tengo una entidad que hace referencia a una segunda entidad que se subclasia. Quiero la referencia a la carga perezosa, pero esto causa errores en mis métodos .equals ().

En el código a continuación, si llama a igual () en una instancia de A, la verificación falla en la función c.equals () al verificar si el objeto O es una instancia de C. falla porque el otro objeto es en realidad un hibernado Proxy creado por Javassist, que se extiende B, no C.

Entiendo que Hibernate no puede crear un proxy del Tipo C sin ir a la base de datos y así romper la carga perezosa. ¿Hay alguna forma de hacer que la función getB () en la clase A devuelva la instancia de concreto B en lugar del proxy (perezoso)? He intentado usar la anotación Hibernate específica @lazyToOne (lazyToOnOoption.no_proxy) en el método getB () en vano.

@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
}
¿Fue útil?

Solución

Resulta que estaba en el seguimiento correcto tratando de usar la anotación @LazyToOne (LazyToOnOoption.no_proxy). No estaba funcionando para mí fuera de la caja porque aún no había ejecutado la herramienta Hibernate Bytecode Enhancer. Las instrucciones para esto se pueden encontrar aquí:

19.1.7. Uso de la propiedad Lazy obteniendo

Otros consejos

Es posible que desee intentar cambiar el fetch propiedad en getB () a FetchType.EAGER. Espero que esto ayude.

Independientemente de si los objetos son entidades y/o cargados de perezosos, es prácticamente imposible respetar el contrato de igual y tener una especialización de iguales en una subclase que utiliza instancia. De hecho, entonces estarías en una situación en la que habrías b1.equals(c1) == true, pero c1.equals(b1) == false.

Entonces, creo que la superclase (b) debería definir iguales y hacerlo definitivo, porque todas las subclases deberían usar la clase base equals método.

Dicho esto, su método igual en B no es correcto:

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

Esto significa que la implementación del objeto de iguales debe devolver verdadero para tener dos instancias B iguales. Lo que significa que dos instancias B son solo iguales si son el mismo objeto.

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

¿Por qué la clase B verifica que la otra instancia sea una instancia de C. Debe verificar si la otra instancia es una instancia de B.

Dado que al final, dos BS son iguales si tienen la misma identificación, y dado que las ID deben ser únicas para todo el árbol de herencia, está a salvo si hace que este método igual sea final.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top