Bonjour,

ça fait quelques jours que j'essaie d'implémenter une relation manyToMany porteuse d'information. Au final, j'ai utilisé la solution proposée par ce tuto : un POJO par entité (Membre, Questionnaire et ListeQuestionnaire dans mon cas) plus une entité pour la clé primaire composite (ListeQuestionnaireId).

J'ai un dao pour chacune des 3 entités. Aucun problème pour Membre et pour Questionnaire. Par contre les tests du dao de ListeQuestionnaire plantent :
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
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("TestDao-context.xml")
@DirtiesContext
public class TestListeQuestionnaireDao {
 
	@Autowired
	private ListeQuestionnaireDao listeQuestionnaireDao;
	@Autowired
	private ServiceMembre serviceMembre;
	@Autowired
	private QuestionnaireDao questionnaireDao;
	private ListeQuestionnaire listeQuestionnaire1, listeQ2;
	private Membre benji, lola;
 
	@Before
	@Transactional
	public void startTransaction() throws ParseException{		
		benji = new Membre();
		benji.setIdMembre("ben.joris");
		benji = serviceMembre.saveOne(benji);
 
		Questionnaire q1 = new Questionnaire();
		q1.setNumero("Q1");
		q1.setTitre("Nutrition");
		q1.setSexeDestinataire('b');
		q1 = questionnaireDao.saveOne(q1);
 
		System.out.println("--------- TEST : enregistrement listeQuestionnaire1...");
		listeQuestionnaire1 = new ListeQuestionnaire();
		listeQuestionnaire1.setaRepondu(false);
		listeQuestionnaire1.setMembre(benji);
		listeQuestionnaire1.setQuestionnaire(q1);
		listeQuestionnaire1 = listeQuestionnaireDao.saveOne(listeQuestionnaire1);
 
		System.out.println("--------- TEST : fin startTransaction...");
	}
 
	@Test
	@Transactional
	@Rollback
	public void testFindAll() {
		System.out.println("--------- TEST : testFindAll...");
		List<ListeQuestionnaire> questionnaireAttendus = new ArrayList<ListeQuestionnaire>();
		questionnaireAttendus.add(listeQuestionnaire1);
 
		List<ListeQuestionnaire> questionnairesObtenus = listeQuestionnaireDao.findAll();
 
		Assert.assertEquals(questionnaireAttendus, questionnairesObtenus);
	}
 
	@Test @Transactional
	@Rollback
	public void testCountAll() {
		System.out.println("--------- TEST : testCountAll...");
		Assert.assertEquals(1, listeQuestionnaireDao.countAll());
	}
 
 
	@Test @Transactional
	@Rollback
	public void testLoad() {
		ListeQuestionnaire questionnaire = listeQuestionnaireDao.getOne(listeQuestionnaire1.getId());
		Assert.assertEquals(listeQuestionnaire1, questionnaire);
	}
 
	@Test @Transactional
	@Rollback
	public void testDelete() {
		listeQuestionnaireDao.deleteOne(listeQuestionnaire1);
		listeQuestionnaire1 = listeQuestionnaireDao.getOne(listeQuestionnaire1.getId());
		Assert.assertNull(listeQuestionnaire1);
	}
enfin, les tests findAll et countAll plantent, les deux autres passent.
pour les deux qui plantent, j'obtiens l'erreur :
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
javax.persistence.PersistenceException: org.hibernate.exception.ConstraintViolationException: Could not execute JDBC batch update
	at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1235)
	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:32)
	at fr.statlife.protoE4N.data.dao.jpa.TestListeQuestionnaireDao.testFindAll(TestListeQuestionnaireDao.java:88)
	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.exception.ConstraintViolationException: Could not execute JDBC batch update
	at org.hibernate.exception.SQLStateConverter.convert(SQLStateConverter.java:96)
	at org.hibernate.exception.JDBCExceptionHelper.convert(JDBCExceptionHelper.java:66)
	at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:275)
	at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:262)
	at org.hibernate.engine.ActionQueue.executeActions(ActionQueue.java:178)
	at org.hibernate.event.def.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:321)
	at org.hibernate.event.def.DefaultAutoFlushEventListener.onAutoFlush(DefaultAutoFlushEventListener.java:64)
	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)
	... 31 more
Caused by: java.sql.BatchUpdateException: Cannot add or update a child row: a foreign key constraint fails (`protoe4n`.`listequestionnaire`, CONSTRAINT `FK8C6EC97C87F51B2E` FOREIGN KEY (`idMembre`) REFERENCES `Membre` (`idMembre`))
	at com.mysql.jdbc.PreparedStatement.executeBatchSerially(PreparedStatement.java:2024)
	at com.mysql.jdbc.PreparedStatement.executeBatch(PreparedStatement.java:1449)
	at org.hibernate.jdbc.BatchingBatcher.doExecuteBatch(BatchingBatcher.java:70)
	at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:268)
	... 39 more
Caused by: com.mysql.jdbc.exceptions.jdbc4.MySQLIntegrityConstraintViolationException: Cannot add or update a child row: a foreign key constraint fails (`protoe4n`.`listequestionnaire`, CONSTRAINT `FK8C6EC97C87F51B2E` FOREIGN KEY (`idMembre`) REFERENCES `Membre` (`idMembre`))
	at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
	at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
	at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
	at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
	at com.mysql.jdbc.Util.handleNewInstance(Util.java:411)
	at com.mysql.jdbc.Util.getInstance(Util.java:386)
	at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1039)
	at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3597)
	at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3529)
	at com.mysql.jdbc.MysqlIO.sendCommand(MysqlIO.java:1990)
	at com.mysql.jdbc.MysqlIO.sqlQueryDirect(MysqlIO.java:2151)
	at com.mysql.jdbc.ConnectionImpl.execSQL(ConnectionImpl.java:2625)
	at com.mysql.jdbc.PreparedStatement.executeInternal(PreparedStatement.java:2119)
	at com.mysql.jdbc.PreparedStatement.executeUpdate(PreparedStatement.java:2415)
	at com.mysql.jdbc.PreparedStatement.executeBatchSerially(PreparedStatement.java:1976)
	... 42 more
sachant qu'en console j'ai les traces suivantes avant l'erreur :
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
Hibernate: 
    select
        membre0_.idMembre as idMembre1_1_,
        membre0_.codeIdentification as codeIden2_1_1_,
        membre0_.dateNaissance as dateNais3_1_1_,
        membre0_.infosPerso_idInfosPerso as infosPerso6_1_1_,
        membre0_.password as password1_1_,
        membre0_.sexe as sexe1_1_,
        infosperso1_.idInfosPerso as idInfosP1_2_0_,
        infosperso1_.codePostal as codePostal2_0_,
        infosperso1_.email as email2_0_,
        infosperso1_.poids as poids2_0_,
        infosperso1_.taille as taille2_0_,
        infosperso1_.ville as ville2_0_ 
    from
        Membre membre0_ 
    left outer join
        InfosPerso infosperso1_ 
            on membre0_.infosPerso_idInfosPerso=infosperso1_.idInfosPerso 
    where
        membre0_.idMembre=?
Hibernate: 
    insert 
    into
        Questionnaire
        (numero, sexeDestinataire, titre) 
    values
        (?, ?, ?)
--------- TEST : enregistrement listeQuestionnaire1...
Hibernate: 
    select
        listequest0_.idMembre as idMembre4_0_,
        listequest0_.idQuestionnaire as idQuesti2_4_0_,
        listequest0_.aRepondu as aRepondu4_0_ 
    from
        ListeQuestionnaire listequest0_ 
    where
        listequest0_.idMembre=? 
        and listequest0_.idQuestionnaire=?
--------- TEST : fin startTransaction...
--------- TEST : testFindAll...
Hibernate: 
    insert 
    into
        ListeQuestionnaire
        (aRepondu, idMembre, idQuestionnaire) 
    values
        (?, ?, ?)
WARN  - JDBCExceptionReporter      - SQL Error: 1452, SQLState: 23000
ERROR - JDBCExceptionReporter      - Cannot add or update a child row: a foreign key constraint fails (`protoe4n`.`listequestionnaire`, CONSTRAINT `FK8C6EC97C87F51B2E` FOREIGN KEY (`idMembre`) REFERENCES `Membre` (`idMembre`))
ERROR - tractFlushingEventListener - Could not synchronize database state with session
Ce que ça me dis, c'est que l'enregistrement de ListeQuestionnaire n'est pas
fait tant qu'un autoFlush appelé par ma méthode findAll n'est pas appelé. Et aussi biensur qu'une contrainte de clé étrangère échoue.
Par contre, pour les deux tests qui plantent pas, il tente pas de faire d'insert de ListeQuestionnaire, y'a juste la requête select qui est appelée :
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
Hibernate: 
    select
        membre0_.idMembre as idMembre1_1_,
        membre0_.codeIdentification as codeIden2_1_1_,
        membre0_.dateNaissance as dateNais3_1_1_,
        membre0_.infosPerso_idInfosPerso as infosPerso6_1_1_,
        membre0_.password as password1_1_,
        membre0_.sexe as sexe1_1_,
        infosperso1_.idInfosPerso as idInfosP1_2_0_,
        infosperso1_.codePostal as codePostal2_0_,
        infosperso1_.email as email2_0_,
        infosperso1_.poids as poids2_0_,
        infosperso1_.taille as taille2_0_,
        infosperso1_.ville as ville2_0_ 
    from
        Membre membre0_ 
    left outer join
        InfosPerso infosperso1_ 
            on membre0_.infosPerso_idInfosPerso=infosperso1_.idInfosPerso 
    where
        membre0_.idMembre=?
Hibernate: 
    insert 
    into
        Questionnaire
        (numero, sexeDestinataire, titre) 
    values
        (?, ?, ?)
--------- TEST : enregistrement listeQuestionnaire1...
Hibernate: 
    select
        listequest0_.idMembre as idMembre4_0_,
        listequest0_.idQuestionnaire as idQuesti2_4_0_,
        listequest0_.aRepondu as aRepondu4_0_ 
    from
        ListeQuestionnaire listequest0_ 
    where
        listequest0_.idMembre=? 
        and listequest0_.idQuestionnaire=?
--------- TEST : fin startTransaction...
Donc le getOne et le deleteOne fonctionnent, mais j'ai pas l'impression qu'ils interagissent avec la base de données, mais plutôt que ça interagit juste avec le contexte de persistance... Enfin, je vois ça de mes yeux de débutante sur le sujet, donc je me trompe peut être

Je suis débutante avec spring JPA et hibernate, mais j'ai suivi pas mal de tutos sur le sujet. Cela dit, je manque quand même d'expérience sur le sujet et j'arrive pas à comprendre d'où vient le problème d'échec de la clé étrangère, ni pourquoi il sauvegarde pas mon Objet ListeQuestionnaire au moment où j'appelle la méthode saveOne du Dao...

voici le code du 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)
	protected 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;
	}
}
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 = em.createQuery("select listeQ from ListeQuestionnaire listeQ ",
				ListeQuestionnaire.class);
 
		return query.getResultList();
	}
 
	public int countAll() {
		TypedQuery<Long> query = em.createQuery("select count(listeQ) from ListeQuestionnaire listeQ", Long.class);
 
		return (query.getSingleResult()).intValue();
	}
}
un peu d'aide ou des conseils pour combler mes zones d'ombres seraient les bienvenus