Vous devez surcharger les méthodes equals()
et hashCode()
si vous
avez l'intention de mettre des instances de classes persistantes dans un Set
(la manière recommandée pour représenter des associations pluri-valuées) et
avez l'intention d'utiliser le réattachement d'instances détachées
Hibernate garantit l'équivalence de l'identité persistante (ligne de base de données) et l'identité Java seulement à l'intérieur
de la portée d'une session particulière. Donc dès que nous mélangeons des instances venant de différentes sessions, nous devons
implémenter equals()
et hashCode()
si nous souhaitons avoir une sémantique correcte pour les Set
s.
La manière la plus évidente est d'implémenter equals()
/hashCode()
en comparant la valeur de l'identifiant des deux objets. Si cette valeur est identique, les deux doivent représenter la même
ligne de base de données, ils sont donc égaux (si les deux sont ajoutés à un Set
, nous n'aurons qu'un seul élément dans le Set
). Malheureusement, nous ne pouvons pas utiliser cette approche avec des identifiants générés ! Hibernate n'assignera de valeur
d'identifiant qu'aux objets qui sont persistants, une instance nouvellement créée n'aura donc pas de valeur d'identifiant
! De plus, si une instance est non sauvegardée et actuellement dans un Set
, le sauvegarder assignera une valeur d'identifiant à l'objet. Si equals()
et hashCode()
sont basées sur la valeur de l'identifiant, le code de hachage devrait changer, rompant le contrat du Set
. Regardez sur le site web d'Hibernate pour une discussion complète de ce problème. Notez que ceci n'est pas un problème d'Hibernate,
mais la sémantique normale de Java pour l'identité d'un objet et l'égalité.
Nous recommandons donc d'implémenter equals()
et hashCode()
en utilisant l'égalité par clé métier.L'égalité par clé métier signifie que la méthode equals()
compare uniquement les propriétés qui forment une clé métier, une clé qui identifierait notre instance dans le monde réel
(une clé candidate naturelle) :
public class Cat { ... public boolean equals(Object other) { if (this == other) return true; if ( !(other instanceof Cat) ) return false; final Cat cat = (Cat) other; if ( !cat.getLitterId().equals( getLitterId() ) ) return false; if ( !cat.getMother().equals( getMother() ) ) return false; return true; } public int hashCode() { int result; result = getMother().hashCode(); result = 29 * result + getLitterId(); return result; } }
Notez qu'une clef métier ne doit pas être solide comme une clef primaire de base de données (voir Section 11.1.3, « L'identité des objets »). Les propriétés immuables ou uniques sont généralement de bonnes candidates pour une clef métier.