La JPA hashCode() / equals() dilemme
Il y a eu certains les discussions ici sur des entités JPA et qui hashCode()
/equals()
mise en œuvre devrait être utilisé pour les classes d'entité JPA. La plupart (si pas tous) d'entre eux dépendent de mise en veille prolongée, mais j'aimerais en discuter JPA-mise en œuvre-neutre (je suis en utilisant EclipseLink, par la voie).
Toutes les implémentations possibles ont leur propre avantages et inconvénients sujet:
hashCode()
/equals()
contrat conformité (immuabilité) pourList
/Set
opérations- Si identiques objets (par exemple, à partir de différentes sessions, des proxies dynamiques de paresseusement-chargé de structures de données) peuvent être détectés
- Si les entités se comportent correctement dans détaché (ou non persistantes) état
Aussi loin que je peux voir, il y a trois options:
- Ne pas les remplacer; compter sur
Object.equals()
etObject.hashCode()
hashCode()
/equals()
travail- ne peut pas identifier les objets identiques, les problèmes avec des proxies dynamiques
- pas de problèmes avec du recul des entités
- Remplacer, à partir de la clé primaire
hashCode()
/equals()
sont cassés- identité correcte (pour toutes les entités gérées)
- problèmes avec du recul des entités
- Remplacer, à partir de la d'Affaires-Id (non champs de clé primaire; ce sur les clés étrangères?)
hashCode()
/equals()
sont cassés- identité correcte (pour toutes les entités gérées)
- pas de problèmes avec du recul des entités
Mes questions sont:
- Ai-je raté une option et/ou pro/con point?
- Quelle option avez-vous choisi et pourquoi?
Mise à JOUR 1:
Par "hashCode()
/equals()
sont cassé", je veux dire que les hashCode()
invocations peuvent renvoyer des valeurs différentes, ce qui est (lorsqu'il est correctement mis en œuvre) ne se décompose pas dans le sens de la Object
documentation de l'API, mais qui pose des problèmes lorsque vous essayez de récupérer un changement de l'entité à partir d'un Map
, Set
ou d'autres à base de hachage Collection
. Par conséquent, les implémentations JPA (au moins EclipseLink) ne fonctionnera pas correctement dans certains cas.
Mise à JOUR 2:
Merci pour vos réponses -- la plupart d'entre eux ont une qualité remarquable.
Malheureusement, je suis toujours pas sûr de l'approche qui sera le meilleur pour une vraie vie de l'application, ou la façon de déterminer la meilleure approche pour mon application. Donc, je vais garder ouverte la question et d'espoir pour certains plus de discussions et/ou des opinions.
- Je ne comprends pas ce que tu veux dire par "hashCode()/equals() cassé"
- de l'Objet.hashCode() javadoc: "Chaque fois qu'il est invoqué sur le même objet plus d'une fois lors d'une exécution d'une application Java, la méthode hashCode doit constamment revenir par le même entier" et "Si deux objets sont égaux selon la equals(Object) méthode, puis en appelant la méthode hashCode sur chacun des deux objets doit produire le même résultat sous forme d'entier." qui est violé dans l'option 2 et 3.
- Qu'ils ne serait pas "cassé" en ce sens, alors, comme dans l'option 2 et 3, vous serait mise en œuvre à la fois equals() et hashCode() en utilisant la même stratégie.
- b option 2 du hashCode() va changer après persist(), l'option 3 du hashCode() va changer si certaines modifications de champ que je qualifierais de "cassé" dans le sens de la méthode equals() javadoc commentaire et Joshua Blochs livre "Effective Java".
- Ce n'est pas vrai de l'option 3. hashCode() et equals() doit être en utilisant les mêmes critères, donc si l'un de vos champs de changement, oui le hashcode() la méthode renverra une valeur différente pour la même instance que ce précédent a fait, mais il en sera de equals(). Vous ai quitté la seconde partie de la phrase à partir de la hashcode() javadoc: à Chaque fois qu'elle est invoquée sur le même objet plus d'une fois lors d'une exécution d'une application Java, la méthode hashCode doit constamment revenir par le même entier, pas fourni d'informations utilisés dans les égaux des comparaisons sur l'objet est modifié.
- b Peut-être que je suis missunderstanding le contrat (je ne suis pas un locuteur natif anglais) mais je suis interprète "pas fourni d'informations utilisés dans les égaux des comparaisons sur l'objet est modifié" "il y a une exception à la règle si les champs ont été modifiés sur lequel la méthode equals ne repose pas sur les" qui n'est pas vrai dans l'option 3, parce que les deux reposent sur le même champs (qui tout peut changer).
- En fait la partie de la phrase signifie le contraire - l'appel de
hashcode()
sur la même instance d'objet doit retourner la même valeur, à moins que tous les champs utilisés dans laequals()
la mise en œuvre du changement. En d'autres termes, si vous avez trois champs dans votre classe et votreequals()
méthode utilise seulement deux d'entre eux pour déterminer l'égalité des cas, alors vous pouvez vous attendre lehashcode()
valeur de retour à changer si vous modifiez l'une de ces valeurs du champ - qui a du sens lorsque l'on considère que cette instance de l'objet n'est plus "égale" à la valeur que l'ancienne instance représentée. - Merci, matt-b - j'ai mis à jour ma question pour refléter votre correctes.
- "des problèmes lorsque vous essayez de récupérer un changement de l'entité à partir d'une Carte, ou autre base de hachage Collections"... ce doit être "des problèmes lorsque vous essayez de récupérer un changement de l'entité à partir d'une table de hachage, HashSet ou d'autres à base de hachage Collections"
- Quelles sont vos pensées sur y compris votre verrouillage optimiste bien, si vous l'utilisez dans votre hashCode()? Peut-être cela mérite sa propre question.
- Qu'entendez-vous des problèmes avec du recul des entités?
- Si vous ajoutez un pas-encore-ont persisté entité dans une base de hachage collection et si l'entité hashCode s'appuie sur le PK, son hashcode va changer après conservation (parce que sa PK sera probablement set), d'où la violation de la base de hachage collection du contrat, ce qui conduit à des résultats imprévisibles
- n'est pas encore persisté n'est pas le même que détaché. Selon l'APC, spec, "une entité détachée de l'instance est une instance avec un persistantes identité qui n'est pas (ou plus) associée à un contexte de persistance". Merci de corriger la question. Aussi, quand vous dites des problèmes avec mais-pas-a persisté entités, tu veux dire en fait la cause de la
hashCode/equals() broken
problème. Ainsi, vous pourriez envisager de reformuler les trois points. - Qu'entendez-vous par
problems with dynamic proxies
? - Si j'ai bien compris les réponses correctement alors il y a une 4ème non cotées de l'option qui a les avantages de tous les 3 options cotées. C'est lorsque vous créez une entité (l'appel de nouveau) vous pouvez également affecter un grand nombre aléatoire à son JPA ID (avec la valeur par défaut GenerationType attribué). Maintenant vous pouvez utiliser une égale/hashcode basée sur ce nombre aléatoire. La probabilité que deux de ces nombres aléatoires entrent en collision est faible.
- Ce n'est pas correct. Vous faites probablement référence à la génération d'UUID - cela devrait vous donner une image plus claire. onjava.com/pub/a/onjava/2006/09/13/...
- Belle question. Est-ce encore s'applique sur JPA en 2019?
Vous devez vous connecter pour publier un commentaire.
Lire ce très bel article sur le sujet: Ne pas Laisser Hibernate Voler Votre Identité.
La conclusion de l'article qui va comme ceci:
suid.js
récupère l'ID des blocs desuid-server-java
que vous pouvez ensuite obtenir et utiliser côté client.J'ai toujours le remplacement est égal à/hashcode et le mettre en œuvre en fonction de l'id. Semble la solution la plus raisonnable pour moi. Voir la suite lien.
MODIFIER:
Pour expliquer pourquoi cela fonctionne pour moi:
Nous avons habituellement deux Id dans nos entités:
equals()
ethashCode()
en particulier)Prendre un coup d'oeil:
EDIT: pour clarifier mon point de vue concernant les appels à
setUuid()
méthode. Voici un scénario typique:Quand je lance mes tests et voir le journal de sortie-je résoudre le problème:
Alternativement, on peut distinguer constructeur:
Donc mon exemple pourrait ressembler à ceci:
- Je utiliser un constructeur par défaut et un setter, mais vous pouvez trouver deux constructeurs approche plus approprié pour vous.
ensureUuid()
idée - c'est simple, mais probablement très efficace, si vous avez l'habitude de vérifier régulièrement les journaux (en fait, je pense que je vais l'utiliser). La partie je n'ai pas (encore) c'est ceci: Si l'uuid peut changer, alors que faut-il acheter de vous (si vous souhaitez toujours avoir le HashSet problème)? Si elle ne peut pas changer, alors pourquoi ne pas l'utiliser en tant que clé primaire?hashCode
/equals
méthodes pour la JVM de l'égalité et deid
de la persistance de l'égalité? Ce n'est pas logique du tout pour moi.Object
'sequals()
serait de retourfalse
dans ce cas. Basé sur l'UUIDequals()
retournetrue
.private UUID uuid= UUID.randomUUID();
. Cela évite la nécessité de définir explicitement ou involontairement modification d'un mot de l'UUID. Une seule condition, bien sûr, c'est que la génération d'UUID doit être léger. Bien sûr, je utilisez uniquement un UUID si il n'y a pas d'autres affaires importantes, dans le cas ci-dessus, je serais probablement utiliser l'adresse e-mail comme une clé d'entreprise (si obligatoire) et pas UUID (et seulement 1 constructeur disponibles, celui qui prend l'adresse e-mail arg).equals()
ethashCode()
qui marcherait bien normal entités, détachée des entités et des objets proxy? Que faire si nous avons collé avec entier DB clés? Je serais ravi de voir une solution plus simple que la mienne!Si vous souhaitez utiliser
equals()/hashCode()
pour vos Jeux, dans le sens que le même entité ne peut être là qu'une fois, alors il n'y a qu'une seule option: l'Option 2. C'est parce que clé primaire pour une entité qui, par définition, ne change jamais (si quelqu'un, en effet, mises à jour, ce n'est pas la même entité plus)Vous devriez prendre littéralement: Depuis votre
equals()/hashCode()
sont basés sur la clé primaire, vous ne devez pas utiliser ces méthodes, jusqu'à ce que la clé primaire est définie. Donc, vous ne devez pas mettre des entités dans l'ensemble, jusqu'à ce qu'ils sont affectés à une clé primaire. (Oui, Uuid et des concepts similaires peut aider à attribuer les clés primaires tôt.)Maintenant, il est aussi théoriquement possible d'atteindre qu'avec l'Option 3, même si les soi-disant "business-clés" ont le désagréable inconvénient qu'ils peuvent changer: "Tout ce que vous aurez à faire est de supprimer le déjà inséré des entités de l'ensemble(s), et réinsérez-les." C'est vrai - mais cela signifie aussi, que dans un système distribué, vous aurez à vous assurer que cela est fait, absolument partout, les données ont été insérées à (et vous aurez à vous assurer, que la mise à jour est effectuée, avant que d'autres choses se produisent). Vous aurez besoin d'un système sophistiqué de mécanisme de mise à jour, surtout si certains systèmes à distance ne sont pas joignable...
L'Option 1 ne peut être utilisée que si tous les objets dans vos jeux sont de la même session Hibernate. La documentation Hibernate très clair à ce sujet dans le chapitre 13.1.3. Considérant l'identité de l'objet:
Il continue de plaider en faveur de l'Option 3:
C'est vrai, si vous
Sinon, vous êtes libre de choisir l'Option 2.
Il mentionne la nécessité d'une stabilité relative:
C'est correct. Le problème pratique que je vois c'est: Si vous ne pouvez pas la garantie absolue de la stabilité, comment allez-vous être en mesure de garantir la stabilité "tant que les objets sont dans le même Ensemble". Je peux imaginer certains cas particuliers (comme l'utilisation de jeux uniquement pour une conversation, puis de le jeter), mais j'ai de la question générale de la faisabilité de cette.
Version courte:
Personnellement, j'ai déjà utilisé l'une de ces trois stratégies dans les différents projets. Je dois dire que l'option 1 est à mon avis le plus possible dans la vie réelle application. Faites l'expérience de la rupture hashCode()/equals() de la conformité conduit à de nombreuses fou bugs que vous aurez à chaque fois retrouver dans des situations où le résultat de l'égalité des changements après qu'une entité a été ajouté à une collection.
Mais il y a d'autres options (également avec leurs avantages et leurs inconvénients):
a) hashCode/égale basé sur un ensemble de immuable, pas null, constructeur attribué, les champs
(+) tous les trois critères sont garantis
(-) des valeurs de champ doivent être disponibles pour créer une nouvelle instance
(-) compliquent la manipulation si vous devez changer un puis
b) hashCode/égale basée sur la clé primaire qui est affectée par l'application (dans le constructeur) au lieu de JPA
(+) tous les trois critères sont garantis
(-) vous ne pouvez pas profiter de simple et fiable de génération d'ID de stratégies comme DB séquences
(-) compliqué si de nouvelles entités sont créées dans un environnement distribué (client/serveur) ou de l'application de serveur de cluster
c) hashCode/égale basé sur un UUID attribué par le constructeur de l'entité
(+) tous les trois critères sont garantis
(-) frais généraux de l'UUID de la génération
(-) peut-être un peu plus de risque que deux fois le même UUID est utilisé, en fonction de l'algorithme utilisé (peut être détecté par un index unique sur DB)
equals
/hashCode
.Object
equals et hashCode implémentations parce que cela ne fonctionne pas après lamerge
et de l'entité.Vous pouvez l'utilisation de l'identifiant d'entité comme il est suggéré dans ce post. Le seul hic, c'est que vous devez utiliser une
hashCode
de mise en œuvre qui renvoie toujours la même valeur, comme ceci:Bien que l'utilisation d'une clé d'entreprise (option 3) est le plus couramment recommandé approche (Hibernate wiki de la communauté, "Java Persistance avec Hibernate" p. 398), et c'est ce que nous utilisons principalement, il y a une Hibernate bug qui rompt pour avide de cheveux ensembles: HHH-3799. Dans ce cas, Hibernate peut ajouter une entité à un ensemble avant que ses champs sont initialisés. Je ne sais pas pourquoi ce bug n'a pas reçu plus d'attention, comme il le fait vraiment recommandé d'affaires-clés approche de la problématique.
Je pense que le coeur de la question est que equals et hashCode devrait être fondée sur l'état immuable (référence Odersky et coll.), et Hibernate entity avec Hibernate-géré clé primaire a pas tel état immuable. La clé primaire est modifiée par Hibernate lors d'un transitoire de l'objet devient persistante. La clé d'entreprise est également modifiée par Hibernate, quand il hydrate un objet dans le processus d'être initialisé.
Qui ne laisse que l'option 1, héritant de java.lang.Objet implémentations basées sur l'identité de l'objet, ou à l'aide d'une application gérée clé primaire comme suggéré par James Brundege dans "Ne pas Laisser Hibernate Voler Votre Identité" (déjà référencé par Stijn Geukens de réponse) et par Lance Arlaus dans "L'objet de la Génération: Une Meilleure Approche de mise en veille prolongée de l'Intégration".
Le plus gros problème avec l'option 1, les instances détachées ne peuvent pas être comparés avec les instances persistantes à l'aide .equals(). Mais c'est OK, le contrat de equals et hashCode laisse au développeur de décider de la signification de l'égalité pour chaque classe. Il suffit donc de laisser equals et hashCode hérite de l'Objet. Si vous avez besoin de comparer une instance détachée à une instance persistante, vous pouvez créer une nouvelle méthode explicitement à cette fin, peut-être
boolean sameEntity
ouboolean dbEquivalent
ouboolean businessEquals
.Je suis d'accord avec André réponse. Nous faisons la même chose dans notre application, mais au lieu de stocker des Uuid as VARCHAR/CHAR, nous nous sommes séparés en deux valeurs longues. Voir l'UUID.getLeastSignificantBits() et l'UUID.getMostSignificantBits().
Plus qu'une chose à considérer, c'est que les appels à l'UUID.randomUUID() sont assez lent, donc, vous voudrez peut-être regarder paresseusement dans la génération de la UUID uniquement lorsque cela est nécessaire, comme lors de la persistance ou à des appels à equals()/hashCode()
Que d'autres gens beaucoup plus intelligents que moi l'a souligné déjà, il y a un grand nombre de stratégies. Il semble être le cas bien que la majorité de la appliqué des modèles de conception d'essayer de pirater leur chemin vers le succès. Ils limitent constructeur d'accès si pas gêner le constructeur invocations complètement spécialisés, des constructeurs et des méthodes de fabrique. En effet, il est toujours agréable avec une coupe claire de l'API. Mais si la seule raison est de faire de la equals et hashcode remplacements être compatibles avec l'application, alors je me demande si ces stratégies sont en conformité avec KISS (Keep It Simple Stupid).
Pour moi, j'aime à remplacer equals et hashcode par l'examen de l'identité. Dans ces méthodes, j'ai besoin de l'id de ne pas être null et document de ce comportement bien. Ainsi, il deviendra l'développeurs contrat de persister une nouvelle entité avant de le ranger quelque part d'autre. Une application qui ne respecte pas ce contrat serait un échec dans la minute (j'espère).
Mot d'avertissement cependant: Si votre entités sont stockées dans différentes tables et de votre fournisseur d'utiliser un auto-stratégie de génération de la clé primaire, vous obtiendrez alors dupliqué clés primaires à travers des types d'entité. Dans de tels cas, également comparer les temps d'exécution des types avec un appel à Objet#getClass() qui, bien sûr, font qu'il est impossible que deux types différents sont considérées comme égales. Qui me convient très bien pour la plupart.
Object#getClass()
est mauvais à cause de H. procurations. L'appel deHibernate.getClass(o)
aide, mais le problème de l'égalité des entités de différentes sortes reste. Il y a une solution à l'aide de canEqual, un peu compliqué, mais utilisable. Convenu que, habituellement, il n'est pas nécessaire. +++ Jetant dans eq/hc sur null ID viole le contrat, mais il est très pragmatique.Il y a bien évidemment déjà très instructif de réponses ici, mais je vais vous dire ce que nous faisons.
Nous ne faisons rien (c'est à dire ne pas remplacer).
Si nous avons besoin est égal à/hashcode de travail pour les collections, nous utilisons des Uuid.
Il vous suffit de créer l'UUID dans le constructeur. Nous utilisons http://wiki.fasterxml.com/JugHome pour les UUID. L'UUID est un peu plus cher CPU sage, mais n'est pas cher par rapport à la sérialisation et la db accès.
Les clés d'entreprise approche ne convient pas pour nous. Nous utilisons DB généré ID, temporaire, transitoire tempId et remplacer l'égalité()/hashcode() pour résoudre le dilemme. Toutes les entités sont des descendants de l'Entité. Pros:
Contre:
Coup d'oeil à notre code:
Veuillez considérer ce qui suit approche basée sur prédéfinies de l'identificateur de type et l'ID.
Les hypothèses de JPA:
L'entité abstraite:
Béton entité exemple:
Exemple de Test:
Principaux avantages ici:
Inconvénients:
super()
Notes:
class A
etclass B extends A
peut dépendre de détails concrets de l'application.Impatient de vos commentaires.
J'ai toujours utilisé l'option 1 dans le passé parce que j'étais au courant de ces discussions et pensait qu'il était mieux de ne rien faire jusqu'à ce que je savais que la bonne chose à faire. Ces systèmes sont tous encore en cours d'exécution avec succès.
Cependant, la prochaine fois je peut essayer l'option 2 - à l'aide de la base de données Id généré.
Hashcode et equals va jeter l'exception IllegalStateException si l'id n'est pas réglé.
Cela permettra d'éviter subtiles erreurs impliquant des entités non enregistrées apparaissent de façon inattendue.
Ce que les gens pensent de cette approche?
C'est un problème commun à tout système informatique qui utilise Java et JPA. Le mal s'étend au-delà de la mise en œuvre de equals() et hashCode(), cela affecte la façon dont une organisation fait référence à une entité et la façon dont ses clients se réfèrent à la même entité. J'en ai assez vu la douleur de ne pas avoir une clé d'entreprise, au point que j'ai écrit mon propre blog pour exprimer mon point de vue.
En bref: utiliser un court, lisible par l'homme, ID séquentiel avec de sens des préfixes comme clé d'entreprise qui est produit sans aucune dépendance envers un stockage autres que la RAM. Twitter est Flocon de neige est un très bon exemple.
De l'OMI, vous avez 3 options pour la mise en œuvre est égal à/hashCode
L'aide d'une application générée à l'identité est l'approche la plus simple, mais avec quelques inconvénients
Si vous pouvez travailler avec ces inconvénients, il suffit d'utiliser cette approche.
À surmonter la jointure question, on pourrait utiliser l'UUID comme naturel clé et une valeur de séquence comme clé primaire, mais peut encore fonctionner dans l'est égal à/hashCode problèmes de mise en œuvre dans la composition de l'enfant entités qui ont intégré des identifiants car vous souhaitez rejoindre basée sur la clé primaire. À l'aide de la clé naturelle de l'enfant entités id et la clé primaire pour désigner le parent est un bon compromis.
IMO c'est le plus propre approche car elle permet d'éviter tous les inconvénients et en même temps vous fournir une valeur(UUID) que vous pouvez partager avec des systèmes externes, sans exposer le système de fonctionnement interne.
Mettre en œuvre sur la base d'un business clé si vous pouvez vous attendre à partir d'un utilisateur est une belle idée, mais est livré avec quelques inconvénients ainsi
La plupart du temps, cette clé d'entreprise sera une sorte de code qui fournit de l'utilisateur et de moins en moins souvent un composite de plusieurs attributs.
De l'OMI, vous ne devriez pas mettre en œuvre ou de travailler avec une entreprise clé en exclusivité. C'est un complément agréable, c'est à dire aux utilisateurs de rechercher rapidement par cette activité clé, mais le système ne devrait pas compter sur elle pour l'exploitation.
Mettre en œuvre sur la base de la clé primaire a ses problèmes, mais c'est peut-être pas une grosse affaire
Si vous avez besoin d'exposer les id de système externe, utiliser l'UUID approche que j'ai suggéré. Si vous ne le faites pas, vous pouvez toujours utiliser l'UUID approche, mais vous n'avez pas à.
Le problème de l'utilisation d'un SGBD généré id est égal à/hashCode provient du fait que l'objet pourrait avoir été ajouté pour le hachage en fonction des collections avant d'attribuer l'id.
Le moyen le plus évident de contourner ce problème est tout simplement de ne pas ajouter l'objet de hachage en fonction des collections avant d'attribuer l'id. Je comprends que ce n'est pas toujours possible parce que vous pourriez déduplication avant d'attribuer l'id déjà. Pour toujours être en mesure d'utiliser le hachage en fonction des collections, il vous suffit de reconstruire les collections après l'affectation de l'id.
Vous pourriez faire quelque chose comme ceci:
Je n'ai pas testé l'approche exacte de moi-même, donc je ne sais pas comment l'évolution des collections pré - et post-persistent événements fonctionne, mais l'idée est la suivante:
Une autre façon de résoudre ce est tout simplement de reconstruire tous vos hachage en fonction des modèles, après une mise à jour/persistent.
En fin de compte, c'est à vous. Personnellement, j'utilise la séquence de base de l'approche la plupart du temps, et de n'utiliser l'UUID approche si j'ai besoin d'exposer un identifiant à des systèmes externes.
Si l'UUID est la réponse pour beaucoup de gens, pourquoi ne pas simplement utiliser des méthodes fabrique à partir de la couche de gestion pour créer les entités et les affecter clé primaire au moment de la création?
par exemple:
cette façon, nous obtenons une valeur par défaut de la clé primaire de l'entité à partir du fournisseur de persistance, et notre hashCode() et equals() les fonctions de l'invoquer.
Nous avons pu également déclarer la Voiture, les constructeurs protégés et ensuite utiliser la réflexion dans notre entreprise, la méthode pour y accéder. De cette façon, les développeurs n'auraient pas l'intention de les instancier la Voiture avec la nouvelle, mais grâce à la méthode de fabrique.
Comment moughataa de m'bout qui?
J'ai essayé de répondre à cette question moi-même et n'a jamais été tout à fait heureux avec trouvé des solutions jusqu'à ce que j'ai lu ce post et en particulier a ATTIRÉ une. J'ai aimé la façon dont il paresseux créé UUID et stockée de façon optimale il.
Mais je voulais ajouter encore plus de flexibilité, c'est à dire paresseux créer UUID UNIQUEMENT lorsque hashCode()/equals() est accessible à l'avant première de la persistance de l'entité avec chaque solution a des avantages :
J'ai vraiment aprécier des commentaires sur mon mixtes solution ci-dessous
Dans la pratique, il semble que l'Option 2 (clé Primaire) est le plus fréquemment utilisé.
Naturelle et IMMUABLE de clés d'entreprise est rarement chose, la création et le soutien synthétique les touches sont trop lourds à résoudre des situations, qui sont sans doute jamais arrivé.
Jetez un oeil à spring-data-jpa AbstractPersistable de mise en œuvre (la seule chose que: pour Hibernate mise en œuvre utilisation de
mise en veille prolongée.getClass
).Juste conscient de la manipulation de nouveaux objets dans le HashSet/table de hachage.
En face, l'Option 1 (rester
Object
mise en œuvre) est cassé juste aprèsmerge
, qui est très commune de la situation.Si vous n'avez pas de clé d'entreprise et ont un RÉEL besoin de manipuler nouvelle entité de hachage de la structure, remplacer
hashCode
constante, comme ci-dessous Vlad Mihalcea a été conseillé.Ci-dessous est un simple (et testé) solution pour Scala.
Noter que cette solution ne rentre pas dans l'une des 3 catégories
donné dans la question.
Toutes mes Entités sont des sous-classes de la UUIDEntity j'ai donc suivi la
don't repeat yourself (SEC) principe.
Si besoin, la génération d'UUID peut être rendue plus précise (en utilisant plus de
de nombres pseudo-aléatoires).
Scala Code: