J'ai des problèmes avec une NonUniqueObjectException
lancée par Hibernate.
En lisant la documentation et le ce blog, j'ai remplacé l'appel de update()
à merge()
et le problème a été résolu.
Je crois comprendre la raison de l'exception et la raison pour laquelle le changement de méthode a résolu le problème en termes d'objets déconnectés et de limites de session.
Ma question est la suivante: étant donné que merge()
résoudra toujours l'objet de session ou le récupérera s'il n'existe pas, appeler merge () est-il généralement une alternative plus sûre que update()
?
Quel est l'inconvénient d'utiliser merge()
sur update()
?
L'appel de fusion () est-il généralement une alternative plus sûre que update ()?
Pour éviter NonUniqueObjectException, oui. Je pense que cela explique pourquoi JPA ne permet pas une méthode de mise à jour.
Quel est l'inconvénient d'utiliser merge () sur update ()?
Un utilisateur non conseillé peut penser qu'il dispose d'une nouvelle entité gérée. Quelque chose comme
// myEntity (passed as parameter does not become managed)
// Only the one returned by the merge operation is a managed entity
session.merge(myEntity);
// "newValue" is not commited because myEntity is not managed
myEntity.setMyProperty("newValue");
Et si votre contexte de persistance ne contient pas votre entité, vous ne voulez peut-être pas le comportement par défaut de la sélection avant la mise à jour. Mais cela peut être évité
...
public void updateMyEntity(MyEntity updateableMyEntity);
// load does not hit the database
MyEntity myEntity = (MyEntity) session.load(MyEntity.class, updateableMyEntity.getId());
BeanUtils.copyProperties(myEntity, updateableMyEntity);
}
De cette façon, vous pouvez mettre à jour votre entité sans méthode de fusion ou de mise à jour. Consultez cette question pour plus d'informations: Le meilleur moyen de mettre à jour certains champs d'un objet détaché sur Hibernate?
Utilisez update () si vous êtes certain que la session ne contient pas d'instance déjà persistante avec le même identifiant et merge () si vous souhaitez fusionner vos modifications à tout moment sans prendre en compte l'état de la session. En d'autres termes, update () est généralement la première méthode que vous appelez dans une nouvelle session en vous assurant que la réattachement de vos instances détachées est la première opération exécutée.
SessionFactory factory = cfg.buildSessionFactory();
Session session1 = factory.openSession();
Student s1 = null;
Object o = session1.get(Student.class, new Integer(101));
s1 = (Student)o;
session1.close();
s1.setMarks(97);
Session session2 = factory.openSession();
Student s2 = null;
Object o1 = session2.get(Student.class, new Integer(101));
s2 = (Student)o1;
Transaction tx=session2.beginTransaction();
session2.merge(s1);
Explication
Voir les lignes 4 à 7, nous avons simplement chargé un objet s1 dans le cache de la session1 et fermé la session1 à la ligne 7, de sorte que l'objet s1 du cache de la session1 sera détruit car le cache de la session1 expirera chaque fois que nous dirons session1.close()
.
Maintenant, l'objet s1 sera dans un emplacement RAM, pas dans le cache de la session1. Ici, s1 est à l'état détaché, et à la ligne 8, nous avons modifié l'objet détaché s1. Désormais, si nous appelons la méthode update()
, hibernate génère une erreur, car nous ne pouvons mettre à jour l'objet que dans la session.
Nous avons donc ouvert une autre session [session2] à la ligne 10 et avons à nouveau chargé le même objet étudiant à partir de la base de données, mais avec le nom s2. Donc, dans cette session2, nous avons appelé session2.merge(s1);
à présent dans l'objet s2. Les modifications s1 seront fusionnées et enregistrées dans la base de données.