128 votes

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

J'ai essentiellement quelques objets dans cette configuration (le modèle de données réel est un peu plus complexe) :

  • A a une relation de plusieurs à plusieurs avec B. (B a inverse="true" )
  • B a une relation de plusieurs à un avec C. (J'ai cascade réglé sur "save-update" )
  • C est une sorte de tableau de types/catégories.

En outre, je devrais probablement mentionner que les clés primaires sont générées par la base de données lors de la sauvegarde.

Avec mes données, je rencontre parfois des problèmes où A possède un ensemble d'objets B différents, et ces objets B font référence au même objet C.

Quand j'appelle session.saveOrUpdate(myAObject) j'ai une erreur d'hibernation qui dit : "a different object with the same identifier value was already associated with the session: C" . Je sais qu'Hibernate ne peut pas insérer/mettre à jour/supprimer le même objet deux fois dans la même session, mais existe-t-il un moyen de contourner ce problème ? Il semble que cette situation ne soit pas si rare.

Au cours de mes recherches sur ce problème, j'ai vu des personnes suggérer l'utilisation de session.merge() Mais lorsque je fais cela, tous les objets "conflictuels" sont insérés dans la base de données en tant qu'objets vides avec toutes les valeurs définies comme nulles. Il est clair que ce n'est pas ce que nous voulons.

[Une autre chose que j'ai oublié de mentionner est que (pour des raisons architecturales indépendantes de ma volonté), chaque lecture ou écriture doit être effectuée dans une session séparée.

2voto

Nguyen Vu Quang Points 161

Trouvez l'attribut "Cascade" dans Hibernate et supprimez-le. Lorsque vous définissez l'attribut "Cascade" disponible, il appelle d'autres opérations (sauvegarde, mise à jour et suppression) sur d'autres entités qui ont une relation avec les classes liées. Ainsi, la même valeur d'identité se produira. Cela a fonctionné avec moi.

1voto

Buddhi Points 85

J'ai eu cette erreur il y a quelques jours et j'ai passé trop de temps à réparer cette erreur.

 public boolean save(OrderHeader header) {
    Session session = sessionFactory.openSession();

    Transaction transaction = session.beginTransaction();

    try {
        session.save(header);

        for (OrderDetail detail : header.getDetails()) {
            session.save(detail);
        }

        transaction.commit();
        session.close();

        return true;
    } catch (HibernateException exception) {

        exception.printStackTrace();
        transaction.rollback();
        return false;
    }
}

Avant d'obtenir cette erreur, je n'avais pas mentionné le type de génération d'ID sur l'objet OrderDetail. Si je ne génère pas l'ID de l'OrderDetail, l'ID reste à 0 pour tous les objets OrderDetail. C'est ce que #jbx a expliqué. Oui, c'est la meilleure réponse. Voici un exemple de ce qui se passe.

1voto

juldeh Points 119

Essayez de placer le code de votre requête avant. Cela a réglé mon problème. Par exemple, changez ceci :

query1 
query2 - get the error 
update

à ça :

query2
query1
update

1voto

shubhranshu Points 329

Dans mon cas, seul flush() n'a pas fonctionné. J'ai dû utiliser un clear() après flush().

public Object merge(final Object detachedInstance)
    {
        this.getHibernateTemplate().flush();
        this.getHibernateTemplate().clear();
        try
        {
            this.getHibernateTemplate().evict(detachedInstance);
        }
}

1voto

Sandeep Patel Points 21

Assurez-vous que votre entité a le même type de génération que toutes les entités mappées.

Ex : UserRole

public class UserRole extends AbstractDomain {

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;

private String longName;

private String shortName;

@Enumerated(EnumType.STRING)
private CommonStatus status;

private String roleCode;

private Long level;

@Column(columnDefinition = "integer default 0")
private Integer subRoleCount;

private String modification;

@ManyToOne(fetch = FetchType.LAZY)
private TypeOfUsers licenseType;

}

Module :

public class Modules implements Serializable {

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;

private String longName;

private String shortName;

}

Entité principale avec mappage

public class RoleModules implements Serializable{

@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;

@ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.MERGE)
private UserRole role;

@ManyToOne(fetch = FetchType.LAZY, cascade = CascadeType.MERGE)
private Modules modules;

@Type(type = "yes_no")
private boolean isPrimaryModule;

public boolean getIsPrimaryModule() {
    return isPrimaryModule;
}

}

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