Quelle est la bonne façon de ré-attacher des objets détachés en veille prolongée?
J'ai une situation dans laquelle j'ai besoin de ré-attacher des objets détachés pour une session hibernate, bien qu'un objet de la même identité n'existe pas déjà dans la session, ce qui va provoquer des erreurs.
Maintenant, je peux faire une de deux choses.
-
getHibernateTemplate().update( obj )
Cela fonctionne si et seulement si un objet n'existe pas déjà dans la session hibernate. Des Exceptions sont levées, indiquant un objet avec l'identifiant donné existe déjà dans la session quand j'en ai besoin plus tard. -
getHibernateTemplate().merge( obj )
Cela fonctionne si et seulement si un objet existe dans la session hibernate. Des Exceptions sont levées quand j'ai besoin de l'objet à être dans une session plus tard si je l'utilise.
Compte tenu de ces deux scénarios, comment puis-je génériquement joindre séances d'objets? Je ne veux pas utiliser les exceptions pour contrôler le flux de cette solution du problème, car il doit y avoir une solution plus élégante...
Vous devez vous connecter pour publier un commentaire.
Il semble donc qu'il n'est pas possible de rattacher un état détaché entité JPA.
merge()
va pousser les vicié de l'état de la DB,et d'écraser tout intervenant mises à jour.
refresh()
ne peut pas être appelé un décollement de l'entité.lock()
ne peut pas être appelé un décollement de l'entité,et même si elle le pouvait, et il a fait rattacher l'entité,
l'appel de "verrouiller" avec l'argument 'LockMode.AUCUN"
ce qui implique que vous êtes de verrouillage, mais pas de verrouillage,
est le plus paradoxal morceau de conception d'API que j'ai jamais vu.
Donc, vous êtes coincé.
Il y a un
detach()
méthode, mais pas deattach()
oureattach()
.Une étape évidente dans le cycle de vie des objets n'est pas disponible pour vous.
À en juger par le nombre de questions similaires à propos de JPA,
il semble que, même si JPA ne prétendent avoir un modèle cohérent,
le plus certainement ne correspond pas au modèle mental de la plupart des programmeurs,
qui ont été condamnés à perdre de nombreuses heures à essayer de comprendre
comment obtenir JPA à faire les choses les plus simples, et jusqu'à la fin avec cache
code de gestion sur leurs applications.
Il semble que la seule façon de faire est de jeter votre rassis détaché de l'entité
et faire une requête de la recherche avec le même id, qui va frapper la L2 ou de la DB.
Mik
refresh()
détaché entités? En regardant à travers la 2.0 spécification, je ne vois pas de justification, juste qu'il n'est pas autorisé.*Reattaching a modified detached instance* A detached instance may be reattached to a new Session (and managed by this new persistence context) by calling update() on the detached object. In our experience, it may be easier for you to understand the following code if you rename the update() method in your mind to reattach()—however, there is a good reason it’s called updating.
Plus peut être trouvé dans la section 9.3.2lock(LockMode.NONE)
peut en fait être appelé sur un transitoire de l'objet, et il ne se rattacher à l'entité de la session. Voir stackoverflow.com/a/3683370/14379Toutes ces réponses manquer une distinction importante. mise à jour() est utilisée pour (re)joindre votre objet graphique à une Session. Les objets que vous lui transmettre sont celles qui sont faites géré.
merge() est en fait pas une (re)de fixation de l'API. Avis de fusion() a une valeur de retour? C'est parce qu'il vous renvoie l'géré graphique, qui ne peut être le graphique que vous avez passé il. merge() est une API JPA et son comportement est régi par la JPA spec. Si l'objet que vous transmettez à fusionner() est déjà géré (déjà associé à la Session) puis c'est le graphique Hibernate travaille; l'objet transmis est le même objet renvoyé de merge(). Si, toutefois, l'objet que vous passer dans merge() est détachée, Hibernate crée un nouvel objet graphique qui est géré et la copie de l'état de votre détachée graphique sur la nouvelle géré graphique. Encore une fois, c'est tous les dictées et régie par la JPA spec.
En termes de stratégie générique pour "assurez-vous que cette entité est gérée, ou faire gérer", ça dépend si vous voulez que le compte n'est pas encore inséré de données ainsi. En supposant que vous le faites, utilisez quelque chose comme
Notez que j'ai utilisé saveOrUpdate() plutôt que la mise à jour(). Si vous ne voulez pas ne sont pas encore insérés les données traitées ici, l'utilisation de mise à jour() à la place...
Session.contains(Object)
contrôles par référence. Si il existe déjà une autre Entité représentant la même ligne dans la session et que vous passez une instance détachée, vous obtiendrez une exception.Session.contains(Object)
contrôles par référence, s'il y a autre Entité représentant la même ligne dans la session, il sera de retour faux, et il mettra à jour.Peu diplomatique réponse: Vous êtes probablement à la recherche d'un contexte de persistance étendue. C'est l'une des principales raisons derrière la Couture-Cadre... Si vous avez du mal à utiliser Hibernate au Printemps en particulier, découvrez cette pièce de Couture de docs.
Réponse diplomatique: Ceci est décrit dans le Hibernate docs. Si vous avez besoin de plus de précisions, consultez la Section 9.3.2 de Persistance Java avec Hibernate intitulée "Travailler avec des Objets Détachés." J'avais fortement vous recommandons de vous procurer ce livre si vous êtes en train de faire quelque chose de plus que CRUD avec Hibernate.
Si vous êtes sûr que votre entité n'a pas été modifié (ou si vous acceptez toute modification sera perdue), alors vous pouvez le rattacher à la session avec serrure.
Il se verrouille rien, mais il l'entité à partir du cache de session ou (si elles n'y figurent pas) de le lire à partir de la DB.
Il est très utile pour éviter LazyInitException lorsque vous naviguez à travers les relations d'une "ancienne" (à partir de la HttpSession par exemple) des entités. Vous d'abord "rattacher" l'entité.
À l'aide de get peut aussi travailler, sauf si vous obtenez l'héritage mappé (qui est déjà lever une exception sur la getId()).
Session.lock(entity, LockMode.NONE)
échoue à l'exception de dire: impossible de réassocier non initialisée transitoire de la collection. Comment peut surmonter cela?Session.find()
méthode de l'API. Peut-être vous direSession.load(Object object, Serializable id)
.Je suis retourné à la JavaDoc de
org.hibernate.Session
et constaté ce qui suit:Ainsi
update()
,saveOrUpdate()
,lock()
,replicate()
etmerge()
sont les candidats des options.update()
: Lève une exception si il y a une instance persistante avec le même identifiant.saveOrUpdate()
: Enregistrer ou mettre à jourlock()
: Obsolètereplicate()
: Persister à l'état de l'instance détachée, la réutilisation de l'actuelle valeur de l'identifiant.merge()
: Retourne un objet persistant avec le même identifiant. L'instance donnée ne devient pas associée à la session.Donc,
lock()
ne doit pas être utilisé aussitôt, et basé sur l'exigence fonctionnelle d'un ou de plusieurs d'entre eux peuvent être choisis.Je l'ai fait de cette façon en C# avec NHibernate, mais il devrait fonctionner de la même manière en Java:
Première Écluse a été appelée sur chaque objet, car Contient a toujours été faux. Le problème est que NHibernate compare les objets par id de base de données et le type. Contient utilise le
equals
méthode, qui compare par référence si ce n'est pas écrasé. Avec quiequals
méthode, il fonctionne sans aucune exception:Session.contains(Object obj)
vérifie la référence et ne détecte pas une autre instance qui représente la même ligne et à est déjà attaché à elle.Ici ma solution générique pour les Entités ayant une propriété d'identifiant.
C'est l'un des rares aspects de la .Net EntityFramework j'aime, les différents joindre options concernant changé entités et leurs propriétés.
Je suis venu avec une solution à "rafraîchir" un objet à partir du magasin de persistance qui compte pour les autres objets, qui peuvent déjà être attachés à la session:
Désolé, ne semble pas à ajouter des commentaires (pas encore?).
De L'Utilisation D'Hibernate 3.5.0-Finale
Alors que la
Session#lock
cette méthode obsolète, la javadoc ne vous suggérons d'utiliserSession#buildLockRequest(LockOptions)#lock(entity)
et si vous assurez-vous que vos associations ontcascade=lock
, le chargement différé n'est pas un problème non plus.Donc, ma méthode d'attachement ressemble un peu à
Tests préliminaires suggèrent qu'il fonctionne un régal.
Peut-être qu'il se comporte de façon légèrement différente sur Eclipselink. Pour re-joindre des objets détachés sans obtenir des données périmées, j'ai l'habitude de faire:
et à titre facultatif, une deuxième étape (pour obtenir des caches invalidé):
essayer getHibernateTemplate().répliquer(entité,ReplicationMode.LATEST_VERSION)
Dans le post original, il y a deux méthodes,
update(obj)
etmerge(obj)
qui sont mentionnés à l'œuvre, mais en face de circonstances. Si c'est vraiment vrai, alors pourquoi ne pas tester pour voir si l'objet est déjà dans la première session, et ensuite appelerupdate(obj)
si elle l'est, sinon appelmerge(obj)
.Le test pour l'existence dans la session est
session.contains(obj)
. Donc, je pense que le pseudo-code du travail:à rattacher à cet objet, vous devez utiliser merge();
cette methode accepter en paramètre de votre entité détachée et le retour à une entité sera jointe et rechargé à partir de la Base de données.
convocation de la première fusion() (mise à jour instance persistante), puis la verrouiller(LockMode.AUCUN) (à joindre à l'instance actuelle, pas celui retourné par merge()) semble fonctionner pour certains cas d'utilisation.