Bonjour,

j'ai une entité Membre, et une entité QuestionnaireReduit. Les deux sont liées par une association ManyToMany implémentée par une entité ListeQuestionnaire avec une clé composite.
Je me suis appuyée sur le tuto de Serge Tahé pour aboutir aux différentes classes en utilisant une classe Embeddable pour la clé composite.

J'ai créé des Dao pour ces trois entités. Aucun problème pour Membre et pour QuestionnaireReduit, par contre lors des tests unitaires du Dao de ListeQuestionnaire, j'obtiens l'erreur suivante :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
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
javax.persistence.EntityNotFoundException: Unable to find fr.statlife.protoE4N.data.entites.Membre with id ben.joris
	at org.hibernate.ejb.Ejb3Configuration$Ejb3EntityNotFoundDelegate.handleEntityNotFound(Ejb3Configuration.java:132)
	at org.hibernate.event.def.DefaultLoadEventListener.load(DefaultLoadEventListener.java:233)
	at org.hibernate.event.def.DefaultLoadEventListener.proxyOrLoad(DefaultLoadEventListener.java:285)
	at org.hibernate.event.def.DefaultLoadEventListener.onLoad(DefaultLoadEventListener.java:152)
	at org.hibernate.impl.SessionImpl.fireLoad(SessionImpl.java:1080)
	at org.hibernate.impl.SessionImpl.internalLoad(SessionImpl.java:1028)
	at org.hibernate.type.EntityType.resolveIdentifier(EntityType.java:623)
	at org.hibernate.type.EntityType.resolve(EntityType.java:431)
	at org.hibernate.type.EntityType.replace(EntityType.java:291)
	at org.hibernate.type.AbstractType.replace(AbstractType.java:177)
	at org.hibernate.type.TypeFactory.replace(TypeFactory.java:583)
	at org.hibernate.event.def.DefaultMergeEventListener.copyValues(DefaultMergeEventListener.java:600)
	at org.hibernate.event.def.DefaultMergeEventListener.mergeTransientEntity(DefaultMergeEventListener.java:337)
	at org.hibernate.event.def.DefaultMergeEventListener.entityIsTransient(DefaultMergeEventListener.java:303)
	at org.hibernate.event.def.DefaultMergeEventListener.entityIsDetached(DefaultMergeEventListener.java:464)
	at org.hibernate.event.def.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:255)
	at org.hibernate.event.def.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:84)
	at org.hibernate.impl.SessionImpl.fireMerge(SessionImpl.java:859)
	at org.hibernate.impl.SessionImpl.merge(SessionImpl.java:843)
	at org.hibernate.impl.SessionImpl.merge(SessionImpl.java:847)
	at org.hibernate.ejb.AbstractEntityManagerImpl.merge(AbstractEntityManagerImpl.java:682)
	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.orm.jpa.ExtendedEntityManagerCreator$ExtendedEntityManagerInvocationHandler.invoke(ExtendedEntityManagerCreator.java:365)
	at $Proxy26.merge(Unknown Source)
	at fr.statlife.protoE4N.data.dao.jpa.AbstractDaoJPAImpl.saveOne(AbstractDaoJPAImpl.java:43)
	at fr.statlife.protoE4N.data.dao.jpa.TestListeQuestionnaireDao.startTransaction(TestListeQuestionnaireDao.java:50)
	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.RunBefores.evaluate(RunBefores.java:27)
	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)
Le truc, c'est que je ne sais pas si ça vient de mon implémentation du Dao, ou si ça vient de l'entité elle même... et mes recherches sur le forum et sur le net m'ont pas vraiment aidé.
Cela dit, vu l'erreur, je penche plus vers un problème dans le Dao.

En fait, j'utilise une classe abstraite générique implémentant mon interface Dao :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
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
public abstract class AbstractDaoJPAImpl<T extends DomainObject> implements Dao<T> {
 
	private Class<T> domainClass;
 
	@PersistenceContext(type=PersistenceContextType.EXTENDED)
	private EntityManager em;
 
 
	public AbstractDaoJPAImpl(Class<T> domainClass) {
		this.domainClass = domainClass;
	}
 
	public void deleteOne(T object)
	{ 
		em.remove(object);
	}
 
	public T getOne(Serializable id)
	{
		return (T) em.find(domainClass, id);
	}
 
	public T saveOne(T object)
	{
		return em.merge(object);
	}
 
	/*
	 * Getters and setters
	 */
	public EntityManager getEm() {
		return em;
	}
 
	public void setEm(EntityManager em) {
		this.em = em;
	}
}
et chacun de mes Dao étends cette classe. Ce qui donne pour ListeQuestionnaire :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@Repository
public class ListeQuestionnaireDaoImpl extends AbstractDaoJPAImpl<ListeQuestionnaire> implements
		ListeQuestionnaireDao {
 
	public ListeQuestionnaireDaoImpl(){
		super(ListeQuestionnaire.class);
	}
 
	public List<ListeQuestionnaire> findAll() {
		TypedQuery<ListeQuestionnaire> query = getEm().createQuery("select listeQ from ListeQuestionnaire listeQ",
				ListeQuestionnaire.class);
 
		return query.getResultList();
	}
 
	public int countAll() {
		TypedQuery<Long> query = getEm().createQuery("select count(listeQ) from ListeQuestionnaire listeQ", Long.class);
 
		return (query.getSingleResult()).intValue();
	}
}
Voici la classe de test :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
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
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("TestDao-context.xml")
@DirtiesContext
public class TestListeQuestionnaireDao {
 
	@Autowired
	private ListeQuestionnaireDao listeQuestionnaireDao;
	@Autowired
	private MembreDao membreDao;
	@Autowired
	private QuestionnaireReduitDao qReduitDao;
	private ListeQuestionnaire listeQuestionnaire;
 
	@Before
	public void startTransaction() throws ParseException{
		Membre benji = new Membre();
		benji.setIdMembre("ben.joris");
		benji = membreDao.saveOne(benji);
 
		QuestionnaireReduit qReduit = new QuestionnaireReduit();
		qReduit = qReduitDao.saveOne(qReduit);
 
		listeQuestionnaire = new ListeQuestionnaire(benji, qReduit);
		listeQuestionnaire.setaRepondu(false);
		listeQuestionnaire = listeQuestionnaireDao.saveOne(listeQuestionnaire);
	}
 
	@Test
	@Transactional
	@Rollback
	public void testFindAll() {
		List<ListeQuestionnaire> qReduitsAttendus = new ArrayList<ListeQuestionnaire>();
		qReduitsAttendus.add(listeQuestionnaire);
 
		Assert.assertEquals(qReduitsAttendus, listeQuestionnaireDao.findAll());
	}
 
	@Test @Transactional
	@Rollback
	public void testCountAll() {
		Assert.assertEquals(1, listeQuestionnaireDao.countAll());
	}
 
	@Test @Transactional
	@Rollback
	public void testDelete() {
		listeQuestionnaireDao.deleteOne(listeQuestionnaire);
		Assert.assertEquals(0, listeQuestionnaireDao.countAll());
	}
 
	@Test @Transactional
	@Rollback
	public void testLoad() {
		ListeQuestionnaire qReduit2 = listeQuestionnaireDao.getOne(listeQuestionnaire.getId());
		Assert.assertEquals(listeQuestionnaire, qReduit2);
	}
 
	@Test @Transactional
	@Rollback
	public void testSave() {
		//if we have got this far then save works
	}
}
l'erreur apparait lors du listeQuestionnaire = listeQuestionnaireDao.saveOne(listeQuestionnaire); à chaque appel de la méthode startTransaction.

ça fait un moment que je bloque sur cette erreur, alors j'étudierai la moindre piste !

au cas où ça pourrait aider, voici le code des trois entités :
Membre :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
 
@Entity
public class Membre  extends DomainObject {
	private static final long serialVersionUID = -80426809311125204L;
 
	@Id
	private String idMembre;
 
	@Temporal(TemporalType.DATE)
	private Date dateNaissance;
	private Character sexe;
	private String password;
	private String codeIdentification;
 
	@OneToOne(cascade=CascadeType.ALL, fetch=FetchType.LAZY)
	@JoinColumn(unique=true, nullable=true)
	private InfosPerso infosPerso;
 
        //Getters and Setters
}
QuestionnaireReduit:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Entity
public class QuestionnaireReduit extends DomainObject {
	private static final long serialVersionUID = 6829338996989112101L;
 
	@Id
	@GeneratedValue(strategy = GenerationType.AUTO)
	private Long idQuestionnaireReduit;
 
	private String numero;
	private String titre;
	private Character sexeDestinataire;
 
	/*
	 * Getters and setters
	 */
}
et surtout ListeQuestionnaire :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
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 Id id = new Id();
 
	/*
	 * 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
	@JoinColumn(name="idMembre", insertable=false, updatable=false)
	private Membre membre;
	@ManyToOne
	@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;
	}
 
 
 
	/**
         * Classe définissant la clé primaire composite
         */
	@Embeddable
	public static class Id implements Serializable{
		private static final long serialVersionUID = 1L;
 
		//Composantes de la clé primaire composite
		@Column(name="idMembre")
		private String idMembre;
		@Column(name="idQuestionnaireReduit")
		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
	 */
	}