122 votes

Erreur Hibernate : org.hibernate.NonUniqueObjectException : un autre objet avec la même valeur d'identifiant a déjà été associé à la session

J'ai deux objets d'utilisateur et lorsque j'essaie d'enregistrer l'objet à l'aide de la fonction

session.save(userObj);

Je reçois l'erreur suivante :

Caused by: org.hibernate.NonUniqueObjectException: a different object with the same identifier value was already associated with the session:
[com.pojo.rtrequests.User#com.pojo.rtrequests.User@d079b40b]

Je crée la session en utilisant

BaseHibernateDAO dao = new BaseHibernateDAO();          

rtsession = dao.getSession(userData.getRegion(),
                           BaseHibernateDAO.RTREQUESTS_DATABASE_NAME);

rttrans = rtsession.beginTransaction();
rttrans.begin();

rtsession.save(userObj1);
rtsession.save(userObj2);

rtsession.flush();
rttrans.commit();

rtsession.close(); // in finally block

J'ai également essayé de faire le session.clear() avant d'enregistrer, mais rien n'y fait.

C'est la première fois que j'obtiens l'objet de session lorsqu'une demande d'utilisateur arrive, alors je me demande pourquoi il dit que l'objet est présent dans la session.

Des suggestions ?

0 votes

Voici un autre excellent fil de discussion qui m'a aidé à résoudre mon problème getj2ee.over-blog.com/

177voto

Michael Wiles Points 7570

J'ai eu cette erreur à plusieurs reprises et elle peut être assez difficile à trouver...

En fait, ce que dit Hibernate, c'est que vous avez deux objets qui ont le même identifiant (la même clé primaire) mais qui ne sont pas le même objet.

Je vous suggère de décomposer votre code, c'est-à-dire de commenter des parties jusqu'à ce que l'erreur disparaisse, puis de remettre le code jusqu'à ce qu'il revienne et vous devriez trouver l'erreur.

Cela se produit le plus souvent par le biais de sauvegardes en cascade, où il y a une sauvegarde en cascade entre l'objet A et B, mais l'objet B a déjà été associé à la session, mais n'est pas sur la même instance de B que celle de A.

Quel générateur de clé primaire utilisez-vous ?

La raison pour laquelle je pose cette question est que cette erreur est liée à la façon dont vous demandez à Hibernate de vérifier l'état persistant d'un objet (c'est-à-dire si un objet est persistant ou non). L'erreur peut se produire parce que Hibernate essaie de persister un objet qui est déjà persistant. En fait, si vous utilisez save, hibernate essaiera de persister cet objet, et il se peut qu'il y ait déjà un objet avec la même clé primaire associée à la session.

Exemple

Supposons que vous ayez un objet de classe hibernate pour une table de 10 lignes basées sur une combinaison de clé primaire (colonne 1 et colonne 2). Vous avez supprimé 5 lignes de la table à un moment donné. Maintenant, si vous essayez d'ajouter les mêmes 10 lignes à nouveau, pendant que hibernate essaie de persister les objets dans la base de données, 5 lignes qui ont déjà été supprimées seront ajoutées sans erreur. Les 5 lignes restantes, qui existent déjà, lèveront cette exception.

L'approche la plus simple consiste donc à vérifier si vous avez mis à jour/supprimé une valeur dans une table qui fait partie de quelque chose et si vous essayez ensuite d'insérer à nouveau les mêmes objets.

4 votes

Belle réponse². La clé primaire était mon problème, résolu avec le GeneratedValue qui définit une séquence pour postgresql.

2 votes

J'ai eu le même problème. Dans mon cas, j'avais un objet recherché dans un code et j'essayais de construire un nouvel objet avec le même ID dans un autre morceau de code alors que le premier objet était encore dans la session d'hibernate.

0 votes

Ce problème m'a tourmenté pendant quelques jours. I would suggest you break down your code C'est certainement la meilleure réponse. Jouez avec les processus. Modifiez les CascadeTypes. En ce qui me concerne, c'est l'ordre qui a fonctionné. Au départ, je supprimais l'enfant avant le parent. Ce qui a fonctionné pour moi, c'est de supprimer le parent avant l'enfant. C'est bizarre, mais ça a marché. Alors jouez avec votre code jusqu'à ce que vous obteniez les résultats souhaités. Les relations d'Hibernate sont vraiment bizarres.

25voto

Alex Points 1063

Utilisation session.merge(object) serait utile. Lire cette article.

19voto

Hein Points 107

Ce n'est qu'un point où hibernate pose plus de problèmes qu'il n'en résout. Dans mon cas, il y a beaucoup d'objets avec le même identifiant 0, parce qu'ils sont nouveaux et n'en ont pas. La base de données les génère. J'ai lu quelque part que les signaux 0 ne sont pas définis. La façon intuitive de les persister est d'itérer sur eux et de dire hibernate pour sauvegarder les objets. Mais vous ne pouvez pas faire cela - "Bien sûr, vous devriez savoir qu'hibernate fonctionne de telle ou telle manière, donc vous devez " Donc maintenant je peux essayer de changer les Ids en Long au lieu de long et regarder si ça marche. En fin de compte, il est plus facile de le faire avec un simple mapper par soi-même, car hibernate n'est qu'un fardeau intransparent supplémentaire. Autre exemple : Essayer de lire des paramètres d'une base de données et de les conserver dans une autre vous oblige à faire presque tout le travail manuellement. Mais si vous devez le faire de toute façon, l'utilisation d'Hibernate n'est qu'un travail supplémentaire.

13 votes

Je déteste aussi l'hibernation... et les bases de données... Après tous les problèmes qu'elles m'ont causés, je pense qu'il est plus facile d'utiliser un fichier texte (je plaisante, mais quand même...).

0 votes

Dans mon cas, de nombreux objets ont le même identifiant 0, parce qu'ils sont nouveaux et n'en ont pas. La base de données les génère. J'ai lu quelque part que les signaux 0 ne sont pas définis. La façon intuitive de les persister est d'itérer sur eux et de dire hibernate pour sauvegarder les objets. . J'ai besoin de faire exactement cela. Pourriez-vous me dire quelle est la "méthode hibernate" pour faire cela ?

0 votes

Dans mon cas, j'ai dû utiliser session.merge(myobject) car j'avais deux instances de cet objet. Cela se produit généralement lorsqu'une entité est persistée et détachée de la session. Une autre instance de cette entité est demandée à l'hibernation. Cette seconde instance reste attachée à la session. La première instance est modifiée. En savoir plus getj2ee.over-blog.com/

17voto

Rahul N Points 36

USe session.evict(object); La fonction de evict() est utilisée pour supprimer l'instance du cache de session. Ainsi, pour la première sauvegarde de l'objet, il convient d'enregistrer l'objet en appelant la méthode session.save(object) avant d'expulser l'objet du cache. De la même manière, la mise à jour de l'objet se fait en appelant la méthode session.saveOrUpdate(object) o session.update(object) avant d'appeler evict().

3voto

user372467 Points 36

Obtenir l'objet à l'intérieur de la session, voici un exemple :

MyObject ob = null;
ob = (MyObject) session.get(MyObject.class, id);

3 votes

Bien essayé, mais l'objet "ob" est renvoyé sans les données mises à jour (étant donné qu'il a été mis à jour par l'application pendant l'exécution, entre l'extraction des objets de la base de données et leur enregistrement).

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