Dans mon application, qui utilise Spring et Hibernate, j'analyse un fichier CSV et je complète la base de données en appelant handleRow()
chaque fois qu'un enregistrement est lu à partir du fichier CSV.
Mon modèle de domaine:
«Famille» a beaucoup de «Sous-famille»
'Sous-famille' a beaucoup de 'Locus'
un "locus" appartient à une "espèce"
Family <-> SubFamily <-> Locus
sont tous des mappages bidirectionnels.
Code:
public void handleRow(Family dummyFamily, SubFamily dummySubFamily, Locus dummyLocus) {
//Service method which access DAO layers
CommonService serv = ctx.getCommonService();
boolean newFamily=false;
Family family=serv.getFamilyByFamilyId(dummyFamily.getFamilyId());
if(family==null){
newFamily=true;
family=new Family();
family.setFamilyId(dummyFamily.getFamilyId());
family.setFamilyIPRId(dummyFamily.getFamilyIPRId());
family.setFamilyName(dummyFamily.getFamilyName());
family.setFamilyPattern(dummyFamily.getFamilyPattern());
family.setRifID(dummyFamily.getRifID());
}
SubFamily subFamily = family.getSubFamilyBySubFamilyId( dummySubFamily.getSubFamilyId() );
if(subFamily==null){
subFamily=new SubFamily();
subFamily.setRifID(dummySubFamily.getRifID());
subFamily.setSubFamilyId(dummySubFamily.getSubFamilyId());
subFamily.setSubFamilyIPRId(dummySubFamily.getSubFamilyIPRId());
subFamily.setSubFamilyName(dummySubFamily.getSubFamilyName());
subFamily.setSubFamilyPattern(dummySubFamily.getSubFamilyPattern());
family.addSubFamily(subFamily);
}
//use the save reference, to update from GFF handler
Locus locus = dummyLocus;
subFamily.addLocus(locus);
assignSpecies(serv,locus);
//Persist object
if(newFamily){
serv.createFamily(family);
} else {
serv.updateFamily(family);
}
}
une espèce est assignée à un locus en utilisant la méthode suivante, qui accède simplement à la couche DAO:
private void assignSpecies (CommonService serv, Locus locus) {
String locusId = locus.getLocusId();
String speciesId = CommonUtils.getLocusSpecies(locusId, ctx.getSpeciesList()).getSpeciesId();
//Simply get Species object from DAO
Species sp = serv.getSpeciesBySpeciesId(speciesId);
locus.setSpecies(sp);
}
Hibernate donne l'erreur suivante:
[INFO] Starting scheduled refresh cache with period [5000ms]
Hibernate: insert into species (species_id, name) values (?, ?)
Hibernate: insert into species (species_id, name) values (?, ?)
Hibernate: insert into species (species_id, name) values (?, ?)
############################ROW#####################1
SubFamiyID#######RIF0005913
Hibernate: select this_.id as id1_0_, this_.family_id as family2_1_0_, this_.rif_iD as rif3_1_0_, this_.family_name as family4_1_0_, this_.family_ipr_id as family5_1_0_, this_.family_pattern as family6_1_0_ from family this_ where this_.family_id=?
Creating NEW SubFamiyID#######RIF0005913
Hibernate: select this_.id as id3_0_, this_.species_id as species2_3_0_, this_.name as name3_0_ from species this_ where this_.species_id=?
Hibernate: insert into family (family_id, rif_iD, family_name, family_ipr_id, family_pattern) values (?, ?, ?, ?, ?)
Hibernate: insert into subfamily (sub_family_id, rif_iD, sub_family_name, sub_family_ipr_id, sub_family_pattern, family_id, sub_family_index) values (?, ?, ?, ?, ?, ?, ?)
Hibernate: insert into locus (locus_id, refTrans_id, function, species_id, sub_family_id, sub_family_index) values (?, ?, ?, ?, ?, ?)
Hibernate: update species set species_id=?, name=? where id=?
Hibernate: update subfamily set family_id=?, sub_family_index=? where id=?
Hibernate: update locus set sub_family_id=?, sub_family_index=? where id=?
############################ROW#####################2
SubFamiyID#######RIF0005913
Hibernate: select this_.id as id1_0_, this_.family_id as family2_1_0_, this_.rif_iD as rif3_1_0_, this_.family_name as family4_1_0_, this_.family_ipr_id as family5_1_0_, this_.family_pattern as family6_1_0_ from family this_ where this_.family_id=?
Hibernate: select subfamilie0_.family_id as family7_1_, subfamilie0_.id as id1_, subfamilie0_.sub_family_index as sub8_1_, subfamilie0_.id as id0_0_, subfamilie0_.sub_family_id as sub2_0_0_, subfamilie0_.rif_iD as rif3_0_0_, subfamilie0_.sub_family_name as sub4_0_0_, subfamilie0_.sub_family_ipr_id as sub5_0_0_, subfamilie0_.sub_family_pattern as sub6_0_0_, subfamilie0_.family_id as family7_0_0_ from subfamily subfamilie0_ where subfamilie0_.family_id=?
Hibernate: select locuslist0_.sub_family_id as sub5_1_, locuslist0_.id as id1_, locuslist0_.sub_family_index as sub7_1_, locuslist0_.id as id2_0_, locuslist0_.locus_id as locus2_2_0_, locuslist0_.refTrans_id as refTrans3_2_0_, locuslist0_.function as function2_0_, locuslist0_.sub_family_id as sub5_2_0_, locuslist0_.species_id as species6_2_0_ from locus locuslist0_ where locuslist0_.sub_family_id=?
Hibernate: select species0_.id as id3_0_, species0_.species_id as species2_3_0_, species0_.name as name3_0_ from species species0_ where species0_.id=?
Hibernate: select this_.id as id1_0_, this_.family_id as family2_1_0_, this_.rif_iD as rif3_1_0_, this_.family_name as family4_1_0_, this_.family_ipr_id as family5_1_0_, this_.family_pattern as family6_1_0_ from family this_ where this_.family_id=?
Hibernate: select this_.id as id3_0_, this_.species_id as species2_3_0_, this_.name as name3_0_ from species this_ where this_.species_id=?
Exception in thread "main" [INFO] Closing Compass [compass]
org.springframework.orm.hibernate3.HibernateSystemException: a different object with the same identifier value was already associated with the session: [com.bigg.nihonbare.common.domain.Species#1]; nested exception is org.hibernate.NonUniqueObjectException: a different object with the same identifier value was already associated with the session: [com.bigg.nihonbare.common.domain.Species#1]
Caused by: org.hibernate.NonUniqueObjectException: a different object with the same identifier value was already associated with the session: [com.bigg.nihonbare.common.domain.Species#1]
at org.hibernate.engine.StatefulPersistenceContext.checkUniqueness(StatefulPersistenceContext.Java:590)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.performUpdate(DefaultSaveOrUpdateEventListener.Java:284)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.entityIsDetached(DefaultSaveOrUpdateEventListener.Java:223)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.performSaveOrUpdate(DefaultSaveOrUpdateEventListener.Java:89)
at org.hibernate.event.def.DefaultSaveOrUpdateEventListener.onSaveOrUpdate(DefaultSaveOrUpdateEventListener.Java:70)
at org.hibernate.impl.SessionImpl.fireSaveOrUpdate(SessionImpl.Java:507)
at org.hibernate.impl.SessionImpl.saveOrUpdate(SessionImpl.Java:499)
at org.hibernate.engine.CascadingAction$5.cascade(CascadingAction.Java:218)
at org.hibernate.engine.Cascade.cascadeToOne(Cascade.Java:268)
Des conseils?
Utilisez merge()
. L'exception signifie que la session en cours est déjà consciente de l'entité que vous passez. Sinon, vérifiez comment vous avez remplacé hashCode()
et equals()
- il devrait retourner des valeurs différentes pour différentes entités.
Vous pouvez également rencontrer ce problème si vous effectuez une delete()
ou une update()
. Le problème est susceptible de se produire si vous créez vous-même le pojo hibernate-mappé, éventuellement à partir d'un DTO. Ce pojo a maintenant le même identifiant que celui qui se trouve déjà dans la variable Session
, ce qui pose problème.
Vous avez maintenant deux options. Soit ce que @Bozho a dit et la première merge()
l'objet. Cela prend en charge la mise à jour. Pour la suppression, prenez l'objet renvoyé par merge()
et supprimez-le.
L'autre option consiste à interroger d'abord la Session
à l'aide de l'ID de l'objet, puis à le supprimer ou le mettre à jour.
J'ai résolu donc: Sur la méthode de suppression:
this.getHibernateTemplate().clear();
this.getHibernateTemplate().delete(obj);
// Esta línea realiza el "commit" del comando
this.getHibernateTemplate().flush();
Sur la méthode de mise à jour:
this.getHibernateTemplate().merge(obj);
// Esta línea realiza el "commit" del comando
this.getHibernateTemplate().flush();
Si vous mettez à jour un objet evict () à partir d'une session après l'appel de saveOrUpdate (), vérifiez également l'implémentation hashCode de l'objet.
J'ai vu cela lorsqu'une entité ne possède pas d'annotation GeneratedValue pour sa colonne ID:
@GeneratedValue(strategy = GenerationType.AUTO)
Vous avez peut-être créé deux instances de Session
Session session = factory.openSession();
Si vous avez ouvert une session dans une fonction et en avez exécuté une autre en créant une autre session, ce problème se produit.