web-dev-qa-db-fra.com

Hibernate: un objet différent avec la même valeur d'identifiant était déjà associé à la session

Duplicata possible:
Erreur de mise en veille prolongée: org.hibernate.NonUniqueObjectException: un objet différent avec la même valeur d'identifiant était déjà associé à la session

lorsque j'utilise le DAO.update (userbean), session.SaveOrUpdate(e); lève l'exception: un objet différent avec la même valeur d'identifiant était déjà associé à la session

la fonction est la suivante:

    public E save(E e) {
    Session session = null;
    try {
        session = sessionFactory.openSession();
        log.debug("session="+session.hashCode()+" save "+e);
        session.SaveOrUpdate(e);  //here throws exception 
        session.flush();
    }
    catch (Exception e1) {
        log.err("Cannot open hibernate session "+ e1.getMessage()+" cause : "+e1.getCause());
        e1.printStackTrace();
    }
    finally { if ( session != null ) session.close(); session = null;}
    return e ;
}

le userbean est une instance de la classe UserBean

public class UserBean{
   private List<GroupBean> groups = new ArrayList<GroupBean> ();
   private List<RoleBean> roles = new ArrayList<RoleBean> ();
}

public class GroupBean{
private List<RoleBean> roles = new ArrayList<RoleBean> ();
}

chaque groupbean a une liste de rôles, qui ne sont pas modifiés.

dans la base de données, le groupe et le rôle est un mappage plusieurs-à-plusieurs,

par exemple,

nous avons un groupbean # 1, ce sont des rôles: rolebean # 1, rolebean # 2;

groupbean # 2, quels rôles sont le rolebean # 1.

maintenant je crée un nouveau userbean # 1, c'est groups est groupbean # 1 et si je veux ajouter le rolebean # 1 au userbean # 1, il lèvera l'exception comme la description du titre

Je regarde le server.log et constate que lorsque j'utilise DAO.save, l'ordre saveOrUpdate est:

userbean#1
|---|-----------***userbean.groups
|     |     groupbean#1
|     |         groupbean.roles
|     |             rolebean#1  # save relebean#1 the first time
|     |             ---done rolebean#1
|     |         ------done all rolebeans of group.roles
|     |     ---done groupbean#1
|     |-----------done all groupbeans of userbean.groups
|---|-----------***userbean.roles
     |      rolebean#1          # save rolebean#1 the second time, and throws exception here!
     |      ----done rolebean#1
     |      .....
     |-----------done all rolebeans of userbean.roles

la cause de l'exception est que le bean de rôle # 1 a été enregistré deux fois dans une session et que leur identité est la même.

Dans la fonction save (E e), si j'utilise

session.merge(e);

remplacer

session.SaveOrUpdate(e);

ne lèvera pas d'exception, mais le rolebean # 1 n'est pas associé au userbean # 1

n'importe qui peut donner quelques suggestions à ce sujet?

15
user421851

Il serait plus facile d'identifier la cause exacte si nous pouvons voir le code où vous attribuez le bean de rôle à la fois à l'utilisateur et au groupe.

En général, ce que l'exception nous dit, c'est qu'il existe deux versions de ce bean de rôle (deux instances). Le premier est mis à jour, puis Hibernate frappe le second et reconnaît qu'il s'agit du même identifiant mais d'une version détachée différente du rôle.

Hibernate n'est pas sûr de ce qui est correct, et sous saveOrUpdate, il lève une exception pour vous en informer.

Le contrat de fusion fonctionne différemment, en ce sens qu'il supposera que vous vouliez l'enregistrer à nouveau (c'est-à-dire fusionner toutes mes modifications), et donc rattacher la deuxième version, fusionner toutes les modifications et enregistrer toutes les mises à jour.

J'ai blogué sur SaveOrUpdate vs Merge avec plus de détails pour expliquer ce qui se passe.

Si vous souhaitez vous en tenir à SaveOrUpdate, vous devrez déterminer ce que vous faites dans l'affectation qui entraîne l'attribution d'une instance différente du rôle à la collection de rôles de l'utilisateur et aux groupes.

Sinon, si les effets de la fusion fonctionnent pour vous (ce qui est conforme à la norme JPA), utilisez-le.

29
Stevi Deter