Ce lien qui explique en bonne manière :
http://www.stevideter.com/2008/12/07/saveorupdate-versus-merge-in-hibernate/
Nous avons tous les problèmes que l'on rencontre assez rarement que lorsque nous les voyons encore, nous savons que nous avons résolu ce problème, mais ne me souviens pas comment.
Le NonUniqueObjectException jeté lors de l'utilisation de Session.saveOrUpdate() en mode veille prolongée est l'un des miens. Je vais être en ajoutant de nouvelles fonctionnalités à une application complexe. Tous mes tests unitaires, beau travail. Puis dans les tests de l'INTERFACE utilisateur, en essayant de sauver un objet, je commence à être une exception avec le message "un objet différent avec le même identifiant de la valeur a déjà été associé à la session." Voici un exemple de code à partir de Java Persistance avec Hibernate.
Session session = sessionFactory1.openSession();
Transaction tx = session.beginTransaction();
Item item = (Item) session.get(Item.class, new Long(1234));
tx.commit();
session.close(); // end of first session, item is detached
item.getId(); // The database identity is "1234"
item.setDescription("my new description");
Session session2 = sessionFactory.openSession();
Transaction tx2 = session2.beginTransaction();
Item item2 = (Item) session2.get(Item.class, new Long(1234));
session2.update(item); // Throws NonUniqueObjectException
tx2.commit();
session2.close();
Pour comprendre la cause de cette exception, il est important de comprendre des objets détachés et ce qui se passe lorsque vous appelez saveOrUpdate() (ou juste une mise à jour()) sur un décollement de l'objet.
Quand on ferme un individu Session Hibernate, les objets persistants avec qui nous travaillons détaché. Cela signifie que les données sont toujours dans l'application de la mémoire, mais Hibernate n'est plus responsable pour le suivi des modifications apportées aux objets.
Si nous modifions notre détaché de l'objet et souhaitez le mettre à jour, nous devons rattacher à l'objet. Pendant que le processus de rattachement, Hibernate va vérifier pour voir si il y a toutes les autres copies du même objet. S'il en trouve, il a à nous dire qu'il ne sait pas ce que le "réel" copie est plus. Peut-être d'autres modifications ont été apportées à ceux d'autres exemplaires que nous nous attendons à être sauvés, mais Hibernate ne les connaît pas, parce qu'il n'était pas de les gérer à l'époque.
Plutôt que l'exception peut-être de mauvaises données, Hibernate nous dit à propos de ce problème via la NonUniqueObjectException.
Alors que devons nous faire? Dans Hibernate 3, nous avons merge() (dans Hibernate 2, utilisez saveOrUpdateCopy()). Cette méthode force Hibernate pour copier des changements par rapport à d'autres instances détachées sur l'instance que vous souhaitez enregistrer, et regroupe donc toutes les modifications en mémoire avant de l'enregistrer.
Session session = sessionFactory1.openSession();
Transaction tx = session.beginTransaction();
Item item = (Item) session.get(Item.class, new Long(1234));
tx.commit();
session.close(); // end of first session, item is detached
item.getId(); // The database identity is "1234"
item.setDescription("my new description");
Session session2 = sessionFactory.openSession();
Transaction tx2 = session2.beginTransaction();
Item item2 = (Item) session2.get(Item.class, new Long(1234));
Item item3 = session2.merge(item); // Success!
tx2.commit();
session2.close();
Il est important de noter que l'opération de fusion renvoie une référence à la nouvelle version mise à jour de l'instance. Ce n'est pas le rattachement de l'élément de la Session. Si vous testez par exemple l'égalité (item == item3), vous verrez qu'il renvoie false dans le cas présent. Vous aurez probablement envie de travailler avec item3 à partir de ce point.
Il est également important de noter que la JPA (Java Persistence API) n'ont pas de concept de détaché et remis en place les objets, et utilise l'EntityManager.persist() et l'EntityManager.merge().
J'ai trouvé que, en général, lors de l'utilisation d'Hibernate, saveOrUpdate() est généralement suffisant pour mes besoins. J'ai l'habitude de n'utiliser que de fusionner quand j'ai des objets qui peuvent avoir des références à des objets de même type. Plus récemment, la cause de l'exception était dans le code de validation que la référence n'est pas récursive. J'était en train de charger le même objet dans ma session, dans le cadre de la validation, de l'origine de l'erreur.
Où avez-vous rencontré ce problème? Avez-fusionner le travail pour vous ou avez-vous besoin d'une autre solution? Préférez-vous de toujours utiliser la fusion, ou si vous préférez utiliser seulement dans la mesure nécessaire pour des cas spécifiques