Question

J'ai un problème avec le chargement paresseux en veille prolongée lorsqu'ils traitent avec l'héritage. J'ai une entité qui fait référence à une seconde entité qui est sous-classée. Je veux que la référence à charger paresseusement, mais cela provoque des erreurs dans mes méthodes equals ().

Dans le code ci-dessous, si vous appelez equals () sur une instance de A, la vérification échoue dans la fonction C.equals () lors de la vérification si l'objet o est une instance de C. Elle échoue parce que l'autre objet est en fait un proxy Hibernate créé par javassist, qui se prolonge B, non C.

Je comprends que Hibernate ne peut pas créer un proxy de type C sans aller à la base de données et brisant ainsi le chargement paresseux. Y at-il un moyen de rendre la fonction getB () dans la classe A retourner l'instance de béton B au lieu de la procuration (paresseusement)? Je l'ai essayé d'utiliser l'annotation @LazyToOne spécifique Mise en veille prolongée (LazyToOneOption.NO_PROXY) sur la méthode getB () sans résultat.

@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
}
Était-ce utile?

La solution

Il se trouve que je suis sur le suivi droit d'essayer d'utiliser l'annotation @LazyToOne (LazyToOneOption.NO_PROXY). Il ne fonctionnait pas pour moi de la boîte parce que je ne l'avais pas encore exécuté l'outil activateur de bytecode Mise en veille prolongée sur elle. Instructions pour cela se trouve ici:

19.1.7. En utilisant la propriété paresseux fetching

Autres conseils

Vous pouvez essayer de changer la propriété fetch sur get () à FetchType.EAGER. Espérons que cela aide.

Regardless of whether the objects are entities and/or lazy-loaded, it's practically impossible to respect the contract of equals and to have a specialization of equals in a subclass which uses instanceof. Indeed, you would then be in a situation where you would have b1.equals(c1) == true, but c1.equals(b1) == false.

So, I think the superclass (B) should define equals, and make it final, because all the subclasses should use the base class equals method.

That said, your equals method in B isn't right:

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

This means that the Object implementation of equals must return true to have two B instances equal. Which means that two B instances are only equals if they are the same object.

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

Why does the B class check that the other instance is an instance of C. It should check if the other instance is an instance of B.

Since in the end, two Bs are equal if they have the same ID, and since the IDs must be unique for all the inheritance tree, you're safe if you make this equals method final.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top