207 votes

Quelle est la bonne façon de ré-attacher des objets détachés en mise 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.

  1. 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.

  2. 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, il doit y avoir une solution plus élégante...

191voto

mikhailfranco Points 699

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 d' attach() ou reattach(). 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

55voto

Mark Points 14208

Je pense que la fusion est la bonne façon de rattacher des objets. L'API Hibernate pour la Session.de fusion(obj) les états suivants

Exemplaire à l'état de l'objet donné dans la persistance de l'objet avec le même identifiant. Si il n'y a pas d'instance persistante associée à la session, il sera chargé. De retour de l'instance persistante. Si l'instance est enregistré, enregistrez une copie et revenir comme une nouvelle instance persistante. L'instance donnée ne devient pas associée à la session. Cette opération cascades sur les instances associées si l'association est mappée avec cascade="fusionner".

Cela semble contredire votre réclamation que cela fonctionne si et seulement si un objet existe dans la session hibernate. Selon la Javadoc de l'instance qui sera chargée si elle n'est pas associée à cette Session.

37voto

Steve Ebersole Points 3544

Toutes 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é. 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. En supposant que vous le faites, utilisez quelque chose comme

if ( session.contains( myEntity ) ) {
    // nothing to do... myEntity is already associated with the session
}
else {
    session.saveOrUpdate( myEntity );
}

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...

19voto

cwash Points 1683

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 de Cadre... Si vous avez du mal à utiliser Hibernate au Printemps en particulier, découvrez cette pièce de Couture de docs.

Réponse diplomatique: Ce qui est décrit dans les Hibernate docs. Si vous avez besoin de plus de précisions, consultez la Section 9.3.2 de Java Persistance avec Hibernate intitulée "Travailler avec des Objets Détachés." J'aimerais vivement vous recommander de vous procurer ce livre si vous êtes en train de faire quelque chose de plus que CRUD avec mise en veille prolongée.

16voto

John Rizzo Points 308

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 de l'écluse.

session.lock(entity, LockMode.NONE);

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()).

entity = session.get(entity.getClass(), entity.getId());

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X