Erreur org.hibernate.TransientObjectException lors de requêtes JPQL
Bonjour,
j'ai 3 entités : Membre, Questionnaire et ListeQuestionnaire.
ListeQuestionnaire correspond à l'association ManyToMany entre Membre et Questionnaire.
J'ai aussi 3 dao, un pour chaque entité.
Le problème vient du dao de ListeQuestionnaire : toutes les méthodes faisant directement appel à l'entity manager (genre persist, merge, delete, find) fonctionnent bien.
Par contre, dès que je tente une requête JPQL, ça plante au moment du getResultList() ou getSingleResult() avec l'erreur suivante :
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
| java.lang.IllegalStateException: org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: fr.statlife.protoE4N.data.entites.ListeQuestionnaire.membre -> fr.statlife.protoE4N.data.entites.Membre
at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1232)
at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1168)
at org.hibernate.ejb.QueryImpl.getResultList(QueryImpl.java:250)
at fr.statlife.protoE4N.data.dao.jpa.ListeQuestionnaireDaoImpl.findAll(ListeQuestionnaireDaoImpl.java:33)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.springframework.aop.support.AopUtils.invokeJoinpointUsingReflection(AopUtils.java:309)
at org.springframework.aop.framework.ReflectiveMethodInvocation.invokeJoinpoint(ReflectiveMethodInvocation.java:183)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:150)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:110)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:172)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:202)
at $Proxy28.findAll(Unknown Source)
at fr.statlife.protoE4N.data.dao.jpa.TestListeQuestionnaireDao.testFindAll(TestListeQuestionnaireDao.java:79)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:20)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:74)
at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:82)
at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:240)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:193)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:52)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:191)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:42)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:184)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
at org.junit.runners.ParentRunner.run(ParentRunner.java:236)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:180)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:49)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
Caused by: org.hibernate.TransientObjectException: object references an unsaved transient instance - save the transient instance before flushing: fr.statlife.protoE4N.data.entites.ListeQuestionnaire.membre -> fr.statlife.protoE4N.data.entites.Membre
at org.hibernate.engine.CascadingAction$9.noCascade(CascadingAction.java:387)
at org.hibernate.engine.Cascade.cascade(Cascade.java:172)
at org.hibernate.event.def.AbstractFlushingEventListener.cascadeOnFlush(AbstractFlushingEventListener.java:154)
at org.hibernate.event.def.AbstractFlushingEventListener.prepareEntityFlushes(AbstractFlushingEventListener.java:145)
at org.hibernate.event.def.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:88)
at org.hibernate.event.def.DefaultAutoFlushEventListener.onAutoFlush(DefaultAutoFlushEventListener.java:58)
at org.hibernate.impl.SessionImpl.autoFlushIfRequired(SessionImpl.java:1175)
at org.hibernate.impl.SessionImpl.list(SessionImpl.java:1251)
at org.hibernate.impl.QueryImpl.list(QueryImpl.java:102)
at org.hibernate.ejb.QueryImpl.getResultList(QueryImpl.java:241)
... 42 more |
je comprends pas pourquoi il me dit que le Membre est un objet transient alors que je l'ai bien persisté en base avant de construire l'objet listeQuestionnaire. D'ailleurs sans ça la méthode em.find() ne marcherait pas...
Voici un bon bout de la classe ListeQuestionnaire :
Code:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88
| @Entity
public class ListeQuestionnaire extends DomainObject {
private static final long serialVersionUID = -6692608372646294912L;
//clé primaire composite
@EmbeddedId
private ListeQuestionnaireId id = new ListeQuestionnaireId();
/*
* Pour les deux attributs suivant, on fait le lien entre l'attribut et sa colonne dans la table
* via l'annotation @JoinColumn
* les propriétés (insertable=false, updatable=false) spécifient que JPA ne doit pas gérer ces clés
* étrangères car c'est fait directement dans par l'application via le constructeur
*/
@ManyToOne(optional=false)
@JoinColumn(name="idMembre", insertable=false, updatable=false)
private Membre membre;
@ManyToOne(optional=false)
@JoinColumn(name="idQuestionnaireReduit", insertable=false, updatable=false)
private QuestionnaireReduit questionnaireReduit;
private Boolean aRepondu;
/*
* Constructeurs
*/
public ListeQuestionnaire(){
}
public ListeQuestionnaire(Membre membre,
QuestionnaireReduit questionnaireReduit) {
//On fixe les clés étrangères
getId().setIdMembre(membre.getIdMembre());
getId().setIdQuestionnaireReduit(questionnaireReduit.getIdQuestionnaireReduit());
//Associations bidirectionnelles
this.membre = membre;
this.questionnaireReduit = questionnaireReduit;
membre.getListeQuestionnaires().add(this);
questionnaireReduit.getListeQuestionnaire().add(this);
}
/**
* Classe définissant la clé primaire composite
*/
@Embeddable
public static class ListeQuestionnaireId implements Serializable{
private static final long serialVersionUID = 1L;
//Composantes de la clé primaire composite
private String idMembre;
private Long idQuestionnaireReduit;
/*
* Getters and Setters
*/
public String getIdMembre() {
return idMembre;
}
public void setIdMembre(String idMembre) {
this.idMembre = idMembre;
}
public Long getIdQuestionnaireReduit() {
return idQuestionnaireReduit;
}
public void setIdQuestionnaireReduit(Long idQuestionnaireReduit) {
this.idQuestionnaireReduit = idQuestionnaireReduit;
}
/*
* (non-Javadoc)
* @see java.lang.Object#toString()
*/
@Override
public String toString() {
return "Id [idMembre=" + idMembre + ", idQuestionnaireReduit="
+ idQuestionnaireReduit + "]";
}
}
/*
* Getters and Setters
*/
} |
et un exemple de relation inverse (dans membre):
Code:
1 2 3 4 5
| //Relation inverse de la relation ManyToOne ListeQuestionnaire -> Membre
//Cascade de suppression : la suppression d'un Membre entraine la suppression des
//ListeQuestionnaire correspondant
@OneToMany(mappedBy="membre", cascade={CascadeType.REMOVE}, fetch=FetchType.LAZY)
private Set<ListeQuestionnaire> listeQuestionnaires = new HashSet<ListeQuestionnaire>(); |
merci d'avance pour toutes vos suggestions