Comment Equals et hashcode doivent-ils être implémentés lors de l'utilisation de JPA et Hibernate?

StackOverflow https://stackoverflow.com/questions/1638723

Question

Comment les équivalents et le hashcode de la classe de modèle doivent-ils être implémentés dans Hibernate? Quels sont les pièges courants? L'implémentation par défaut est-elle suffisante dans la plupart des cas? Est-il judicieux d’utiliser des clés d’entreprise?

Il me semble qu'il est assez difficile de fonctionner correctement dans toutes les situations, lorsque l'on prend en compte la récupération paresseuse, la génération d'identifiant, le proxy, etc.

.
Était-ce utile?

La solution

Hibernate a une longue et jolie description de quand / comment remplacer equals () / hashCode () dans documentation

En gros, vous ne devez vous en préoccuper que si votre entité fait partie d'un ensemble ou si vous allez détacher / attacher ses instances. Ce dernier n'est pas si commun. Le premier est généralement mieux géré via:

  1. Baser equals () / hashCode () sur une clé commerciale - par exemple. une combinaison unique d'attributs qui ne changera pas pendant la durée de vie de l'objet (ou au moins de la session).
  2. Si ce qui précède est impossible, base equals () / hashCode () sur la clé primaire SI c'est défini et l'identité de l'objet / System.identityHashCode () sinon. La partie importante ici est que vous devez recharger votre ensemble après l'ajout et la persistance d'une nouvelle entité. sinon, vous risquez de vous retrouver avec un comportement étrange (entraînant des erreurs et / ou une corruption des données) car votre entité peut être affectée à un compartiment ne correspondant pas à son hashCode () <)> actuel.

Autres conseils

Je ne pense pas que la réponse acceptée soit exacte.

Pour répondre à la question initiale:

  

L’implémentation par défaut est-elle suffisante dans la plupart des cas?

La réponse est oui, dans la plupart des cas.

Il suffit de remplacer equals () et hashcode () si l'entité sera utilisée dans un Set (ce qui est très courant ) ET l'entité sera détachée des sessions d'hibernation, puis rattachées à celles-ci (ce qui constitue un usage inhabituel d'hibernation).

La réponse acceptée indique que les méthodes doivent être remplacées si la condition soit est vraie.

Lorsqu'une entité est chargée via un chargement différé, ce n'est pas une instance du type base, mais un sous-type généré dynamiquement généré par javassist. Par conséquent, la vérification du même type de classe échouera. N'utilisez pas:

if (getClass() != that.getClass()) return false;

utilisez plutôt:

if (!(otherObject instanceof Unit)) return false;

qui est également une bonne pratique, comme expliqué à la Implémentation d'égal à égal dans les pratiques Java .

pour la même raison, l'accès direct aux champs peut ne pas fonctionner et renvoyer null, au lieu de la valeur sous-jacente, aussi n'utilisez pas de comparaison sur les propriétés, mais utilisez les getters, car ils pourraient déclencher le chargement des valeurs sous-jacentes.

Le meilleur égal à / hashCode est lorsque vous utilisez un clé commerciale unique .

La clé de gestion doit être cohérente pour toutes les état de l'entité transitions (transitoires, attachées, détachées, supprimées), c’est pourquoi vous ne pouvez pas compter sur id pour l’égalité.

Une autre option consiste à utiliser les identificateurs UUID attribués par l'application. logique. De cette façon, vous pouvez utiliser l'UUID pour est égal à / hashCode car l'identifiant est attribué avant le vidage de l'entité.

Vous pouvez même utiliser l'identificateur d'entité pour est égal à et hashCode , mais vous devez toujours renvoyer la même valeur hashCode pour pouvoir assurez-vous que la valeur hashCode de l'entité est cohérente pour toutes les transitions d'état de l'entité. Consultez cet article pour en savoir plus sur ce sujet. .

Oui, c'est difficile. Dans mon projet equals et hashCode reposent tous les deux sur l'id de l'objet. Le problème de cette solution est qu’aucun d’eux ne fonctionne si l’objet n’a pas encore été conservé, l’id étant généré par la base de données. Dans mon cas, c'est tolérable, car dans presque tous les cas, les objets persistent immédiatement. En dehors de cela, cela fonctionne très bien et est facile à mettre en œuvre.

S'il vous est arrivé de remplacer est égal à , assurez-vous de remplir ses contrats: -

  • SYMÉTRIE
  • RÉFLÉCHISSANT
  • TRANSITIVE
  • CONSISTANT
  • NON NULL

Et redéfinissez hashCode , car son contrat repose sur une implémentation de égale à .

Joshua Bloch (concepteur du framework Collection) a vivement recommandé de suivre ces règles.

  • élément 9: remplacez toujours hashCode lorsque vous substituez est égal à

Si vous ne respectez pas ces contrats, il existe un effet non voulu grave. Par exemple, List.contains (Object o) peut renvoyer une valeur boolean erronée, car le contrat général n'est pas rempli.

Dans la documentation d'Hibernate 5.2, il est indiqué que vous ne souhaitez peut-être pas implémenter hashCode et égal à - selon votre situation.

https: // docs.jboss.org/hibernate/orm/5.2/userguide/html_single/Hibernate_User_Guide.html#mapping-model-pojo-equalshashcode

En règle générale, deux objets chargés à partir de la même session seront égaux s'ils sont égaux dans la base de données (sans implémentation de hashCode et equals).

Cela devient compliqué si vous utilisez deux sessions ou plus. Dans ce cas, l’égalité de deux objets dépend de votre implémentation de la méthode equals.

De plus, vous aurez des problèmes si votre méthode equals compare les identifiants générés uniquement lors de la persistance d'un objet pour la première fois. Ils pourraient ne pas être encore là quand on appelle égaux.

Il y a un très bel article ici: https://docs.jboss.org/hibernate/stable/core.old/reference/en/html/persistent-classes-equalshashcode.html

Citation d'une ligne importante de l'article:

  

Nous vous recommandons d'implémenter equals () et hashCode () à l'aide de la clé Business   égalité. L'égalité de clé métier signifie que la méthode equals ()   compare uniquement les propriétés qui forment la clé métier, une clé qui   identifierait notre instance dans le monde réel (un candidat naturel   clé):

En termes simples

public class Cat {

...
public boolean equals(Object other) {
    //Basic test / class cast
    return this.catId==other.catId;
}

public int hashCode() {
    int result;

    return 3*this.catId; //any primenumber 
}

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