Wie sollten Gleichheits- und Hashcode der Modellklasse in Hibernate implementiert werden? Was sind die häufigsten Fallstricke? Ist die Standardimplementierung für die meisten Fälle gut genug? Ist es sinnvoll, Geschäftsschlüssel zu verwenden?
Es scheint mir, dass es ziemlich schwierig ist, es in jeder Situation richtig zum Laufen zu bringen, wenn faules Abrufen, ID-Generierung, Proxy usw. berücksichtigt werden.
Antworten:
Hibernate hat eine schöne und lange Beschreibung, wann / wie
equals()
/hashCode()
in der Dokumentation überschrieben werden mussDer Kern davon ist, dass Sie sich nur darum kümmern müssen, ob Ihre Entität Teil einer Instanz ist
Set
oder ob Sie ihre Instanzen trennen / anhängen werden. Letzteres ist nicht so üblich. Ersteres wird normalerweise am besten gehandhabt über:equals()
/hashCode()
auf einem Business - Schlüssel - zB eine einzigartige Kombination von Eigenschaften , die während des Objekts zu ändern gehen (oder zumindest Session) Lebensdauer nicht.equals()
/hashCode()
auf Primärschlüssel , wenn es Satz und Objektidentität /System.identityHashCode()
sonst. Der wichtige Teil hierbei ist, dass Sie Ihr Set neu laden müssen, nachdem eine neue Entität hinzugefügt und beibehalten wurde. Andernfalls kann es zu seltsamem Verhalten kommen (was letztendlich zu Fehlern und / oder Datenbeschädigungen führt), da Ihre Entität möglicherweise einem Bucket zugewiesen wird, der nicht mit dem aktuellen übereinstimmthashCode()
.quelle
refresh()
? Wie kommt Ihre Entität, die denSet
Vertrag befolgt , in den falschen Bereich (vorausgesetzt, Sie haben eine ausreichend gute Hashcode-Implementierung)?Set.contains(entity)
Sie anzurufen , und Sie werden zurückkehrenfalse
. Gleiches gilt für get () / put () / etc ...Ich denke nicht, dass die akzeptierte Antwort richtig ist.
So beantworten Sie die ursprüngliche Frage:
Die Antwort lautet ja, in den meisten Fällen.
Sie müssen nur überschreiben
equals()
undhashcode()
ob die Entität in einemSet
(sehr häufigen) AND verwendet wird Entität verwendet wird, wird die Entität von Ruhezustandsitzungen getrennt und anschließend erneut angehängt (was eine ungewöhnliche Verwendung von Ruhezustand ist).Die akzeptierte Antwort gibt an, dass die Methoden überschrieben werden müssen, wenn eine der beiden Bedingungen erfüllt ist.
quelle
Die beste
equals
/hashCode
Implementierung ist , wenn Sie einen verwenden einzigartigen Geschäftsschlüssel .Der Geschäftsschlüssel sollte über alle Entitätsstatusübergänge hinweg konsistent sein (vorübergehend, verbunden, getrennt, entfernt). Aus diesem Grund können Sie sich nicht auf die ID für die Gleichheit verlassen.
Eine andere Möglichkeit besteht darin, zur Verwendung von UUID-Kennungen zu wechseln , die von der Anwendungslogik zugewiesen werden. Auf diese Weise können Sie die UUID für das
equals
/ verwendenhashCode
da die ID zugewiesen wird, bevor die Entität geleert wird.Sie können sogar die Entitätskennung für
equals
und verwendenhashCode
. Dazu müssen Sie jedoch immer denselbenhashCode
Wert zurückgeben, um sicherzustellen, dass der hashCode-Wert der Entität über alle Entitätsstatusübergänge hinweg konsistent ist. In diesem Beitrag finden Sie weitere Informationen zu diesem Thema .quelle
BaseEntity
und denken Sie nie wieder über dieses Problem nach. Es braucht ein bisschen Platz auf der DB-Seite, aber diesen Preis zahlen Sie besser für den Komfort :)Wenn eine Entität durch verzögertes Laden geladen wird, handelt es sich nicht um eine Instanz des Basistyps, sondern um einen dynamisch generierten Subtyp, der von javassist generiert wird. Daher schlägt eine Überprüfung desselben Klassentyps fehl. Verwenden Sie daher nicht:
Verwenden Sie stattdessen:
Dies ist auch eine gute Vorgehensweise, wie unter Implementieren von Equals in Java Practices erläutert .
Aus dem gleichen Grund funktioniert der direkte Zugriff auf Felder möglicherweise nicht und gibt anstelle des zugrunde liegenden Werts null zurück. Verwenden Sie daher keinen Vergleich für die Eigenschaften, sondern die Getter, da diese möglicherweise zum Laden der zugrunde liegenden Werte ausgelöst werden.
quelle
Ja, es ist schwer. In meinem Projekt sind equals und hashCode beide auf die ID des Objekts angewiesen. Das Problem dieser Lösung ist, dass keines von beiden funktioniert, wenn das Objekt noch nicht beibehalten wurde, da die ID von der Datenbank generiert wird. In meinem Fall ist das tolerierbar, da in fast allen Fällen Objekte sofort bestehen bleiben. Davon abgesehen funktioniert es hervorragend und ist einfach zu implementieren.
quelle
In der Dokumentation zu Hibernate 5.2 heißt es, dass Sie hashCode möglicherweise nicht implementieren möchten und dass dies - je nach Ihrer Situation - überhaupt gleich ist.
https://docs.jboss.org/hibernate/orm/5.2/userguide/html_single/Hibernate_User_Guide.html#mapping-model-pojo-equalshashcode
Im Allgemeinen sind zwei aus derselben Sitzung geladene Objekte gleich, wenn sie in der Datenbank gleich sind (ohne hashCode und equals zu implementieren).
Es wird kompliziert, wenn Sie zwei oder mehr Sitzungen verwenden. In diesem Fall hängt die Gleichheit von zwei Objekten von Ihrer Implementierung der Equals-Methode ab.
Außerdem treten Probleme auf, wenn Ihre Equals-Methode IDs vergleicht, die nur generiert werden, wenn ein Objekt zum ersten Mal beibehalten wird. Sie sind möglicherweise noch nicht da, wenn gleich aufgerufen wird.
quelle
Hier gibt es einen sehr schönen Artikel: https://docs.jboss.org/hibernate/stable/core.old/reference/en/html/persistent-classes-equalshashcode.html
Zitieren einer wichtigen Zeile aus dem Artikel:
In einfachen Worten
quelle
Wenn Sie überschrieben haben
equals
, stellen Sie sicher, dass Sie die Verträge erfüllen: -Und überschreiben
hashCode
, da sein Vertrag von derequals
Implementierung abhängt.Joshua Bloch (Designer des Collection Frameworks) forderte nachdrücklich die Einhaltung dieser Regeln.
Es gibt schwerwiegende unbeabsichtigte Auswirkungen, wenn Sie diese Verträge nicht befolgen. Zum Beispiel
List#contains(Object o)
könnte ein falscherboolean
Wert zurückgegeben werden, da der Generalvertrag nicht erfüllt ist.quelle