IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

Hibernate Java Discussion :

Problème de clé étrangère avec PostgreSQL


Sujet :

Hibernate Java

  1. #1
    Membre habitué
    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2008
    Messages
    379
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 39
    Localisation : France, Val d'Oise (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2008
    Messages : 379
    Points : 129
    Points
    129
    Par défaut Problème de clé étrangère avec PostgreSQL
    Bonjour à tous !

    j'ai une application web avec les technos suivantes : Spring 3 - JPA 2 - Hibernate 3.5.6.
    Au début j'utilisais le SGBD MySQL, mais certains problèmes de gestion des transactions m'ont poussés à essayer avec un autre SGBD (problème en question abordé dans cet autre sujet).

    J'ai donc installé PostgreSQL, changé la configuration JPA, et la magie des applis multicouches a opéré.
    Mais une fois que j'ai enlevé le patch qui contournait le problème de transaction pour MySQL (des @Transactional(propagation=Propagation.NEVER) sur un certain nombre de méthodes), une erreur de clé étrangère est apparue.

    J'en viens donc au problème à proprement parlé (désolée pour le message un peu long, mais je me dis toujours qu'il est plus facile de résoudre un problème quand on a son contexte ) :
    J'ai une entité Questionnaire et une entité Question. un Questionnaire contient plusieurs questions et une question ne se rapporte qu'à un seul questionnaire. Donc j'ai un champs idQuestionnaire dans mon entité Question qui est une clé étrangère vers le Questionnaire. Voici le mapping de ces deux entités :
    Question :
    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 Question extends DomainObject {
    	private static final long serialVersionUID = 1L;
     
    	@Id
    	@GeneratedValue(strategy = GenerationType.AUTO)
    	private Long idQuestion;
     
    	private Integer numQuestion;
    	private String question;
    	private String typeReponse;
     
    	@ManyToOne(fetch = FetchType.LAZY)
    	@JoinColumn(name = "idQuestionnaire")
    	private Questionnaire questionnaire;
    //Constructeurs, getters and setters
    Questionnaire :
    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
    @Entity
    public class Questionnaire extends DomainObject {
     
    	private static final long serialVersionUID = 1L;
     
    	@Id
    	@GeneratedValue(strategy = GenerationType.AUTO)
    	@Column(name = "idQuestionnaire", nullable = false)
    	private Long idQuestionnaire;
     
    	private String numero;
    	private String titre;
    	private Character sexeDestinataire;
    	private Boolean publie;
     
    	@OneToMany(mappedBy = "pk.questionnaire", cascade = {CascadeType.REMOVE}, fetch = FetchType.LAZY)
    	private List<ListeQuestionnaire> listeQuestionnaires = new ArrayList<ListeQuestionnaire>();
     
    	@OneToMany(mappedBy = "questionnaire", cascade={CascadeType.REMOVE}, fetch = FetchType.LAZY)
    	private List<Question> listeQuestions = new ArrayList<Question>();
     
    	@OneToMany(mappedBy = "questionnaire", cascade={CascadeType.REMOVE}, fetch = FetchType.LAZY)
    	private List<Reponse> listeReponses = new ArrayList<Reponse>();
    //Constructeurs, getters and setters
    Mes tests du dao du Questionnaire passent sans problème, par contre les tests du dao des questions passent pas. Lors de la méthode d'initialisation des données :
    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
    @Before
    @Transactional
    public void startTransaction() throws ParseException{
    	Questionnaire q1 = new Questionnaire();
    	q1.setNumero("Q1");
    	q1.setTitre("Nutrition");
    	q1.setSexeDestinataire('b');
    	questionnaire = serviceQuestionnaire.saveOne(q1);
     
    	Question question1 = new Question();
    	question1.setNumQuestion(1);
    	question1.setQuestion("question 1");
    	question1.setTypeReponse("texte");
    	question1.setQuestionnaire(questionnaire);
     
    	question = questionDao.saveOne(question1);
    }
    la ligne question = questionDao.saveOne(question1); génère 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
    59
    60
    WARN  - JDBCExceptionReporter      - SQL Error: 0, SQLState: 23503
    ERROR - JDBCExceptionReporter      - L'élément du batch 0 insert into Question (numQuestion, question, idQuestionnaire, typeReponse, idQuestion) values ('1', 'question 1', '1', 'texte', '2') a été annulé. Appeler getNextException pour en connaître la cause.
    WARN  - JDBCExceptionReporter      - SQL Error: 0, SQLState: 23503
    ERROR - JDBCExceptionReporter      - ERROR: insert or update on table "question" violates foreign key constraint "fkbe5ca00676039098"
      Détail*: Key (idquestionnaire)=(1) is not present in table "questionnaire".
    ERROR - tractFlushingEventListener - Could not synchronize database state with session
    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.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:51)
    	at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1206)
    	at org.hibernate.ejb.AbstractEntityManagerImpl.flush(AbstractEntityManagerImpl.java:791)
    	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 $Proxy30.flush(Unknown Source)
    	at fr.statlife.protoE4N.data.dao.jpa.AbstractDaoJPAImpl.saveOne(AbstractDaoJPAImpl.java:45)
    	at fr.statlife.protoE4N.data.dao.jpa.TestQuestionDao.startTransaction(TestQuestionDao.java:54)
    	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)
    Caused by: java.sql.BatchUpdateException: L'élément du batch 0 insert into Question (numQuestion, question, idQuestionnaire, typeReponse, idQuestion) values ('1', 'question 1', '1', 'texte', '2') a été annulé. Appeler getNextException pour en connaître la cause.
    	at org.postgresql.jdbc2.AbstractJdbc2Statement$BatchResultHandler.handleError(AbstractJdbc2Statement.java:2598)
    	at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:1836)
    	at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:407)
    	at org.postgresql.jdbc2.AbstractJdbc2Statement.executeBatch(AbstractJdbc2Statement.java:2737)
    	at org.hibernate.jdbc.BatchingBatcher.doExecuteBatch(BatchingBatcher.java:70)
    	at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:268)
    	... 42 more
    Alors j'ai bien lu l'erreur, il dit qu'il n'y a pas de questionnaire avec l'id 1, sauf que ce questionnaire a été créé et enregistré dans la base juste avant... Donc normalement, l'enregistrement devrait être dans la base.
    Il est dans le contexte de persistance en tous cas car j'arrive à le récupérer et à l'afficher.
    Alors pourquoi cette erreur?
    J'ai trouvé sur le forum une autre discussion qui rapporte un problème similaire datant de 2006, mais cette discussion n'a jamais été résolue au final...

    Merci d'avance pour toute l'aide que vous pourrez m'apporter

  2. #2
    Membre habitué
    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2008
    Messages
    379
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 39
    Localisation : France, Val d'Oise (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2008
    Messages : 379
    Points : 129
    Points
    129
    Par défaut
    petite précision : voici le code d'une méthode de test
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    	@Test
    	@Transactional//(propagation=Propagation.NEVER)
    	@Rollback
    	public void testFindAll() {
    		List<Question> questionsAttendus = new ArrayList<Question>();
    		questionsAttendus.add(question);
     
    		Assert.assertEquals(questionsAttendus, questionDao.findAll());
    	}
    si je décommente le (propagation=Propagation.NEVER), le test passe et il n'y a plus cette erreur de clé étrangère. J'avais mis cet attribut pour éviter un lock sur mes tables MySQL qui bloquait l'application.
    Si j'ai installé PostgreSQL c'est justement pour ne pas avoir à ajouter cet attribut...

  3. #3
    Membre habitué
    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2008
    Messages
    379
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 39
    Localisation : France, Val d'Oise (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2008
    Messages : 379
    Points : 129
    Points
    129
    Par défaut
    personne n'a de piste de recherche?
    je manque cruellement d'expertise en la matière, y'a personne pour m'aider au boulot, et le problème est vraiment bloquant car si je continue sur d'autres trucs et que ça marche pas, y'a toujours un risque que le problème vienne directement de ce premier problème...

    J'ai sans doute fait plusieurs petites erreurs (car une seule grosse serait sans doute plus évidente à trouver), mais où?
    y'a-t-il des différences entre un mapping MySQL et un mapping PostgreSQL?
    à moins que ça ne soit ma manière de tester qui pose problème?
    je sais vraiment pas dans quelle direction chercher

  4. #4
    Membre éclairé

    Profil pro
    Technicien
    Inscrit en
    Février 2009
    Messages
    338
    Détails du profil
    Informations personnelles :
    Âge : 45
    Localisation : France

    Informations professionnelles :
    Activité : Technicien

    Informations forums :
    Inscription : Février 2009
    Messages : 338
    Points : 791
    Points
    791
    Par défaut
    Bonjour,

    Une piste éventuelle pourrait être de mettre la propriété show_sql à true dans hibernate afin de voir quelles sont les requêtes SQL générées et peut être comprendre ce qui ne va pas.

    Si les requêtes ne sont pas très clair, tu peux aussi te retourner vers p6spy qui fournit le détail des instructions SQL exécutées.

    Benoit

  5. #5
    Membre habitué
    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2008
    Messages
    379
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 39
    Localisation : France, Val d'Oise (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2008
    Messages : 379
    Points : 129
    Points
    129
    Par défaut
    Bonjour Benoit,

    merci de ta réponse.
    En fait, la propriété show SQL était déjà à true. J'en ai pas parlé car y'a rien qui me choquait dans les requêtes SQL. Voici les traces plus complètes dans la console :
    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
    [...]
    INFO  - SchemaExport               - schema export complete
    INFO  - ionalTestExecutionListener - Began transaction (1): transaction manager [org.springframework.orm.jpa.JpaTransactionManager@679b2faf]; rollback [true]
     
    Hibernate: 
        select
            nextval ('hibernate_sequence')
    Hibernate: 
        insert 
        into
            Questionnaire
            (numero, publie, sexeDestinataire, titre, idQuestionnaire) 
        values
            (?, ?, ?, ?, ?)
    Hibernate: 
        select
            nextval ('hibernate_sequence')
    Hibernate: 
        insert 
        into
            Question
            (numQuestion, question, idQuestionnaire, typeReponse, idQuestion) 
        values
            (?, ?, ?, ?, ?)
    WARN  - JDBCExceptionReporter      - SQL Error: 0, SQLState: 23503
    ERROR - JDBCExceptionReporter      - L'élément du batch 0 insert into Question (numQuestion, question, idQuestionnaire, typeReponse, idQuestion) values ('1', 'question 1', '1', 'texte', '2') a été annulé. Appeler getNextException pour en connaître la cause.
    WARN  - JDBCExceptionReporter      - SQL Error: 0, SQLState: 23503
    ERROR - JDBCExceptionReporter      - ERROR: insert or update on table "question" violates foreign key constraint "fkbe5ca00676039098"
      Détail*: Key (idquestionnaire)=(1) is not present in table "questionnaire".
    ERROR - tractFlushingEventListener - Could not synchronize database state with session
    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.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:51)
    	at org.hibernate.impl.SessionImpl.flush(SessionImpl.java:1206)
    	at org.hibernate.ejb.AbstractEntityManagerImpl.flush(AbstractEntityManagerImpl.java:791)
    	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 $Proxy30.flush(Unknown Source)
    	at fr.statlife.protoE4N.data.dao.jpa.AbstractDaoJPAImpl.saveOne(AbstractDaoJPAImpl.java:45)
    	at fr.statlife.protoE4N.data.dao.jpa.TestQuestionDao.startTransaction(TestQuestionDao.java:52)
    	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)
    Caused by: java.sql.BatchUpdateException: L'élément du batch 0 insert into Question (numQuestion, question, idQuestionnaire, typeReponse, idQuestion) values ('1', 'question 1', '1', 'texte', '2') a été annulé. Appeler getNextException pour en connaître la cause.
    	at org.postgresql.jdbc2.AbstractJdbc2Statement$BatchResultHandler.handleError(AbstractJdbc2Statement.java:2598)
    	at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:1836)
    	at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:407)
    	at org.postgresql.jdbc2.AbstractJdbc2Statement.executeBatch(AbstractJdbc2Statement.java:2737)
    	at org.hibernate.jdbc.BatchingBatcher.doExecuteBatch(BatchingBatcher.java:70)
    	at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:268)
    	... 42 more
    INFO  - ionalTestExecutionListener - Rolled back transaction after test execution for test context [[TestContext@57398cac testClass = TestQuestionDao, locations = array<String>['classpath:/fr/statlife/protoE4N/data/dao/jpa/TestDao-context.xml'], testInstance = fr.statlife.protoE4N.data.dao.jpa.TestQuestionDao@3429cf1, testMethod = testFindAll@TestQuestionDao, testException = javax.persistence.PersistenceException: org.hibernate.exception.ConstraintViolationException: Could not execute JDBC batch update]]
    on voit que les requêtes sont dans le bon ordre, il insert d'abord le questionnaire avant d'essayer d'insérer la question. ça ne rend le problème que plus incompréhensible pour moi en fait...

  6. #6
    Membre éclairé

    Profil pro
    Technicien
    Inscrit en
    Février 2009
    Messages
    338
    Détails du profil
    Informations personnelles :
    Âge : 45
    Localisation : France

    Informations professionnelles :
    Activité : Technicien

    Informations forums :
    Inscription : Février 2009
    Messages : 338
    Points : 791
    Points
    791
    Par défaut
    Ok. Du coup je te conseille d'installer p6spy entre hibernate et le sgdb.

    Il te fournira, en plus des requêtes SQL, le retour d'exécution et les valeurs assignées.
    Je pense qu'avec le détail l'erreur paraitra évidente.

    Benoit

  7. #7
    Membre habitué
    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2008
    Messages
    379
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 39
    Localisation : France, Val d'Oise (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2008
    Messages : 379
    Points : 129
    Points
    129
    Par défaut
    ok, merci pour la piste.
    je vais tester ça de ce pas

  8. #8
    Membre habitué
    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2008
    Messages
    379
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 39
    Localisation : France, Val d'Oise (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2008
    Messages : 379
    Points : 129
    Points
    129
    Par défaut
    bon, voilà les traces p6spy
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    1310547602989|3|0|//[creation de la base de données, et des différentes contraintes)]
    1310547603006|17|0|statement||create sequence hibernate_sequence
    1310547604095|25|1|statement|select nextval ('hibernate_sequence')|select nextval ('hibernate_sequence')
    1310547604173|21|1|statement|insert into Questionnaire (numero, publie, sexeDestinataire, titre, idQuestionnaire) values (?, ?, ?, ?, ?)|insert into Questionnaire (numero, publie, sexeDestinataire, titre, idQuestionnaire) values ('Q1', '', 'b', 'Nutrition', 1)
    1310547604185|2|2|statement|select nextval ('hibernate_sequence')|select nextval ('hibernate_sequence')
    1310547604225|39|2|statement|insert into Question (numQuestion, question, idQuestionnaire, typeReponse, idQuestion) values (?, ?, ?, ?, ?)|insert into Question (numQuestion, question, idQuestionnaire, typeReponse, idQuestion) values (1, 'question 1', 1, 'texte', 2)
    1310547604251|0|0|rollback||
    1310547604258|5|1|rollback||
    1310547604259|0|2|rollback||
    si je me trompe pas, la troisième colonne correspond au numéro de la transaction, c'est bien ça?
    donc on voit que les deux requêtes sont exécutées dans des transactions différentes, est ce que le problème peut venir de là?
    Parce qu'au niveau des requêtes elles-même, je vois pas de problème avec les données...

  9. #9
    Membre éclairé

    Profil pro
    Technicien
    Inscrit en
    Février 2009
    Messages
    338
    Détails du profil
    Informations personnelles :
    Âge : 45
    Localisation : France

    Informations professionnelles :
    Activité : Technicien

    Informations forums :
    Inscription : Février 2009
    Messages : 338
    Points : 791
    Points
    791
    Par défaut
    Citation Envoyé par zaboug Voir le message
    bon, voilà les traces p6spy

    si je me trompe pas, la troisième colonne correspond au numéro de la transaction, c'est bien ça?
    Peux-tu me dire où as tu eu cette information ? J'ai cherché mais sans trouver...

    Bon, si ça correspond effectivement à la transaction, le problème peut venir de là (ex : manque un commit en fin de transaction, présence de 2 transactions au lieu d'une...). Peux-tu nous montrer le contenu de l'un des DAO ?

    Je viens aussi de voir une différence dans le test : pour le questionnaire le "service" est appellé, pour la question, le "dao" est appellé. Est-ce que le souci ne pourrait pas venir de là ?

    Benoit

    Ps : je n'ai pas eu l'occassion d'utiliser l'annotation @Transactional, il se peut que certaines subtilités m'échappent...

  10. #10
    Membre habitué
    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2008
    Messages
    379
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 39
    Localisation : France, Val d'Oise (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2008
    Messages : 379
    Points : 129
    Points
    129
    Par défaut
    Citation Envoyé par bboulch Voir le message
    Peux-tu me dire où as tu eu cette information ? J'ai cherché mais sans trouver...
    je ne l'ai trouvé nulle part, simple déduction en fait, donc ça n'a peut être rien à voir

    Citation Envoyé par bboulch Voir le message
    Bon, si ça correspond effectivement à la transaction, le problème peut venir de là (ex : manque un commit en fin de transaction, présence de 2 transactions au lieu d'une...). Peux-tu nous montrer le contenu de l'un des DAO ?
    tous mes dao étendent la classe AbstractDao générique 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
    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);
    		em.flush();
    	}
     
    	public T getOne(Serializable id)
    	{
    		return (T) em.find(domainClass, id);
    	}
     
    	public T saveOne(T object)
    	{
    		T entiteSauvee = em.merge(object);
    		em.flush();
     
    		return entiteSauvee;
    	}
    //getters and setters
    }
    seule les méthodes findAll et countAll sont spécifiques à chaques dao, par exemple pour questionnaire :
    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 QuestionnaireDaoImpl extends AbstractDaoJPAImpl<Questionnaire> implements
    		QuestionnaireDao {
     
    	public QuestionnaireDaoImpl() {
    		super(Questionnaire.class);
    	}
     
    	public List<Questionnaire> findAll() {
    		TypedQuery<Questionnaire> query = em.createQuery("select q from Questionnaire q",
    				Questionnaire.class);
     
    		return query.getResultList();
    	}
     
    	public int countAll() {
    		TypedQuery<Long> query = em.createQuery("select count(*) from Questionnaire", Long.class);
     
    		return (query.getSingleResult()).intValue();
    	}
    }
    et c'est sur mes services que sont les transactions, par exemple pour le serviceQuestionnaire :
    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
    @Service
    public class ServiceQuestionnaireImpl implements
    		ServiceQuestionnaire {
     
    	@Resource
    	private QuestionnaireDao questionnaireDao;
     
    	@Resource
    	private ServiceListeQuestionnaire serviceListeQuestionnaire;
    	@Resource
    	private ServiceMembre serviceMembre;
     
    	@Transactional
    	public void deleteOne(Questionnaire questionnaire) {
    		questionnaireDao.deleteOne(questionnaire);
    	}
     
    	@Transactional
    	public Questionnaire getOne(Serializable id) {
    		return questionnaireDao.getOne(id);
    	}
     
    	@Transactional
    	public List<Questionnaire> findAll() {
    		return questionnaireDao.findAll();
    	}
     
    	@Transactional
    	public int countAll() {
    		return questionnaireDao.countAll();
    	}
     
    	@Transactional
    	public Questionnaire saveOne(Questionnaire questionnaire) {
    		return questionnaireDao.saveOne(questionnaire);
    	}
    //autres méthodes
    Citation Envoyé par bboulch Voir le message
    Je viens aussi de voir une différence dans le test : pour le questionnaire le "service" est appellé, pour la question, le "dao" est appellé. Est-ce que le souci ne pourrait pas venir de là ?

    Benoit

    Ps : je n'ai pas eu l'occassion d'utiliser l'annotation @Transactional, il se peut que certaines subtilités m'échappent...
    j'ai aussi essayé en utilisant le dao de questionnaire à la place du service, mais ça ne change rien. Pour question, vu qu'on est dans la classe de tests unitaire de son dao, ça me semble logique d'utiliser le dao et pas le service (qui te toute manière ne fait qu'appeler le dao )

    Merci de ton aide en tous cas, c'est plus facile de chercher à deux cerveaux (surtout que ça fait trois jours que les recherches avec mon seul cerveau sont complètement infructueuses )

  11. #11
    Membre éclairé

    Profil pro
    Technicien
    Inscrit en
    Février 2009
    Messages
    338
    Détails du profil
    Informations personnelles :
    Âge : 45
    Localisation : France

    Informations professionnelles :
    Activité : Technicien

    Informations forums :
    Inscription : Février 2009
    Messages : 338
    Points : 791
    Points
    791
    Par défaut
    Pour question, vu qu'on est dans la classe de tests unitaire de son dao, ça me semble logique d'utiliser le dao et pas le service
    Ca me parait pas mal. Faut juste qu'il y ait un gestionnaire de transaction qui chapotte le test ou le DAO (ce que j'ai cru voir dans le test unitaire).

    Sur la page http://www.astorm.ch/blog/index.php?...n-%40OneToManyj , juste sous la partie qui parle de l'attribut "mappedBy", il parle d'une subtilité qui n'est pas retrouvé ici dans le test unitaire. Cette subtilité est d'ajouter la question au questionnaire avant de faire l'appel au DAO de la question.

    Benoit

  12. #12
    Membre habitué
    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2008
    Messages
    379
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 39
    Localisation : France, Val d'Oise (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2008
    Messages : 379
    Points : 129
    Points
    129
    Par défaut
    merci pour le lien !
    en effet, j'avais pas fait l'ajout de l'objet question à la collection de Question du questionnaire.
    En suivant l'exemple du lien que tu m'as donné, j'ai commencé par testé ça :
    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
    	@Before
    	@Transactional
    	public void startTransaction() throws ParseException{
    		Questionnaire q1 = new Questionnaire();
    		q1.setNumero("Q1");
    		q1.setTitre("Nutrition");
    		q1.setSexeDestinataire('b');
     
    		Question question1 = new Question();
    		question1.setNumQuestion(1);
    		question1.setQuestion("question 1");
    		question1.setTypeReponse("texte");
     
     
    		//Mise à jour des références
    		question1.setQuestionnaire(q1);
    		q1.getListeQuestions().add(question1);
     
    		//persistence du tout
    		questionnaire = serviceQuestionnaire.saveOne(q1);
    		question = questionDao.saveOne(question1);
    	}
    Mais j'ai obtenu 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
    59
    60
    61
    java.lang.IllegalStateException: org.hibernate.TransientObjectException: object is an unsaved transient instance - save the transient instance before merging: fr.statlife.protoE4N.data.entites.Question
    	at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1232)
    	at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1168)
    	at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1174)
    	at org.hibernate.ejb.AbstractEntityManagerImpl.merge(AbstractEntityManagerImpl.java:691)
    	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 $Proxy30.merge(Unknown Source)
    	at fr.statlife.protoE4N.data.dao.jpa.AbstractDaoJPAImpl.saveOne(AbstractDaoJPAImpl.java:44)
    	at fr.statlife.protoE4N.metier.ServiceQuestionnaireImpl.saveOne(ServiceQuestionnaireImpl.java:54)
    	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 $Proxy38.saveOne(Unknown Source)
    	at fr.statlife.protoE4N.data.dao.jpa.TestQuestionDao.startTransaction(TestQuestionDao.java:56)
    	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)
    Caused by: org.hibernate.TransientObjectException: object is an unsaved transient instance - save the transient instance before merging: fr.statlife.protoE4N.data.entites.Question
    	at org.hibernate.event.def.DefaultMergeEventListener.getTransientCopyCache(DefaultMergeEventListener.java:142)
    	at org.hibernate.event.def.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:90)
    	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)
    	... 48 more
    en gros il est pas content que j'essaie d'ajouter une question qui fait pas partie du contexte de persistance au questionnaire.

    Bon, cela dit, j'ai remarqué que dans l'exemple, pour persister ses objets, il utilise des em.persist() et non des em.merge() comme je le fais .
    Alors j'ai essayé en utilisant moi aussi persist à la place de merge, histoire de voir si ça changeait quelque chose. La méthode saveOne de mon dao générique devient donc :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    public T saveOne(T object)
    {
    	//T entiteSauvee = em.merge(object);
    	em.persist(object);
    	em.flush();
     
    	return object;
    }
    Avec ce code, plus d'erreur de type TransientObjectException, par contre je retrouve mon erreur du début
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    WARN  - JDBCExceptionReporter      - SQL Error: 0, SQLState: 23503
    ERROR - JDBCExceptionReporter      - L'élément du batch 0 insert into Question (numQuestion, question, idQuestionnaire, typeReponse, idQuestion) values ('1', 'question 1', '1', 'texte', '2') a été annulé. Appeler getNextException pour en connaître la cause.
    WARN  - JDBCExceptionReporter      - SQL Error: 0, SQLState: 23503
    ERROR - JDBCExceptionReporter      - ERROR: insert or update on table "question" violates foreign key constraint "fkbe5ca00676039098"
      Détail*: Key (idquestionnaire)=(1) is not present in table "questionnaire".
    ERROR - tractFlushingEventListener - Could not synchronize database state with session
    [...]
    C'est con, j'avais bon espoir que la piste soit la bonne, mais c'est retour à la case départ

  13. #13
    Membre éclairé

    Profil pro
    Technicien
    Inscrit en
    Février 2009
    Messages
    338
    Détails du profil
    Informations personnelles :
    Âge : 45
    Localisation : France

    Informations professionnelles :
    Activité : Technicien

    Informations forums :
    Inscription : Février 2009
    Messages : 338
    Points : 791
    Points
    791
    Par défaut
    Une piste simple mais à ne pas suivre : supprimer définitivement la foreign key.

    Sinon, les requêtes SQL dans p6spy sont toujours les mêmes ?
    As-tu regardé le comportement des données en base au fur et à mesure de l'exécution du test unitaire ? Ca pourrait peut être te donner une éventuelle piste...

    Benoit

    ps : j'ai cru lire hier soir sur une autre page web que la foreign key devait pouvoir prendre la valeur null (l'idée était qu'hibernate fait un insert de la question, du questionnaire puis met à jour la question avec l'id du questionnaire). En fait, supprimer la foreign key uniquement afin de voir comment se comporte hibernate sans elle, ça peut être une autre piste à suivre. Et voir comment la ré-activer ensuite.

  14. #14
    Membre chevronné
    Inscrit en
    Août 2009
    Messages
    1 073
    Détails du profil
    Informations forums :
    Inscription : Août 2009
    Messages : 1 073
    Points : 1 806
    Points
    1 806
    Par défaut
    Il me semble que tu devrais essayer de changer ta propagation, pour CascadeType.ALL dans un premier temps (selon ce que tu comptes faire), et puis ensuite si tu le souhaites tu peux affiner.

  15. #15
    Membre habitué
    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2008
    Messages
    379
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 39
    Localisation : France, Val d'Oise (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2008
    Messages : 379
    Points : 129
    Points
    129
    Par défaut
    merci à vous deux pour vos propositions.
    Après différents essais, c'est pas encore ça mais y'a du mieux :
    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
    @Before
    @Transactional
    public void startTransaction() throws ParseException{
    	Questionnaire q1 = new Questionnaire();
    	q1.setNumero("Q1");
    	q1.setTitre("Nutrition");
    	q1.setSexeDestinataire('b');
    	questionnaire = serviceQuestionnaire.saveOne(q1);
     
    	Question question1 = new Question();
    	question1.setNumQuestion(1);
    	question1.setQuestion("question 1");
    	question1.setTypeReponse("texte");
    	question = questionDao.saveOne(question1);
     
    	//Mise à jour des références
    	question.setQuestionnaire(questionnaire);
    	questionnaire.getListeQuestions().add(question);
    }
    Ce code passe sans problème (que le cascadeType soit en ALL ou juste en REMOVE).
    Donc maintenant, c'est au niveau de certains tests que ça pète :
    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
    @Test
    @Transactional
    @Rollback
    public void testFindAll() {
    	List<Question> questionsAttendus = new ArrayList<Question>();
    	questionsAttendus.add(question);
     
    	Assert.assertEquals(questionsAttendus, questionDao.findAll());
    }
     
    @Test @Transactional
    @Rollback
    public void testCountAll() {
    	Assert.assertEquals(1, questionDao.countAll());
    }
     
    @Test @Transactional
    @Rollback
    public void testDelete() {
    	questionDao.deleteOne(question);
    	Assert.assertEquals(0, questionDao.countAll());
    }
     
    @Test @Transactional
    @Rollback
    public void testLoad() {
    	Question question2 = questionDao.getOne(question.getIdQuestion());
    	Assert.assertEquals(question, question2);
    }
    Les tests load et delete passent. Et j'ai vérifié les requêtes via p6spy, elles sont cohérentes.
    Par contre les tests findAll et countAll passent pas. J'ai la même exception qu'avant :
    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
    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.QuestionDaoImpl.findAll(QuestionDaoImpl.java:22)
    	at fr.statlife.protoE4N.data.dao.jpa.TestQuestionDao.testFindAll(TestQuestionDao.java:66)
    	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:179)
    	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: L'élément du batch 0 update Question set numQuestion='1', question='question 1', idQuestionnaire='1', typeReponse='texte' where idQuestion='2' a été annulé. Appeler getNextException pour en connaître la cause.
    	at org.postgresql.jdbc2.AbstractJdbc2Statement$BatchResultHandler.handleError(AbstractJdbc2Statement.java:2598)
    	at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:1836)
    	at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:407)
    	at org.postgresql.jdbc2.AbstractJdbc2Statement.executeBatch(AbstractJdbc2Statement.java:2737)
    	at com.p6spy.engine.logging.P6LogPreparedStatement.executeBatch(P6LogPreparedStatement.java:329)
    	at org.hibernate.jdbc.BatchingBatcher.doExecuteBatch(BatchingBatcher.java:70)
    	at org.hibernate.jdbc.AbstractBatcher.executeBatch(AbstractBatcher.java:268)
    	... 39 more
    sauf que cette fois elle apparait au moment du query.getResultList() des méthodes findAll et countAll du dao :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    public List<Question> findAll() {
    	TypedQuery<Question> query = em.createQuery("select q from Question q", Question.class);
    	return query.getResultList();
    }
     
    public int countAll() {
    	TypedQuery<Long> query = em.createQuery("select count(*) from Question", Long.class);
     
    	return (query.getSingleResult()).intValue();
    }
    en fait, dans la trace de l'exception, on se rend compte qu'à ce moment il y a un flush qui est fait, une requête update sur question est envoyée (merci p6spy) et c'est elle qui foire. Encore une fois, il dit que le questionnaire est pas en base, alors qu'en toute logique, si, il devrait y être...

    As-tu regardé le comportement des données en base au fur et à mesure de l'exécution du test unitaire ? Ca pourrait peut être te donner une éventuelle piste...
    J'ai essayé plusieurs fois, mais je dois mal m'y prendre j'imagine car j'y arrive pas Je m'explique : quand je mets des breaks dans le déroulement des tests, que je les lance en debug (j'utilise Eclipse Helios), et que je vais voir ce qui se passe dans ma base de données, bah il se passe rien, y'a pas de données dans la base
    Pour aller voir en base, j'utilise le client pgAdminIII.
    Je sais pas si ça veut dire qu'il y a réellement rien dans la base (auquel cas c'est normal qu'il m'envoie cette exception depuis le début ) ou si c'est que je m'y prends mal pour essayer d'aller voir ce qu'il se passe dans la base de données. Je penchais plus vers cette deuxième option, mais j'ai peut être eu tort ?
    Comment vous faites vous pour aller voir dans la base de données en cours de test?

  16. #16
    Membre éclairé

    Profil pro
    Technicien
    Inscrit en
    Février 2009
    Messages
    338
    Détails du profil
    Informations personnelles :
    Âge : 45
    Localisation : France

    Informations professionnelles :
    Activité : Technicien

    Informations forums :
    Inscription : Février 2009
    Messages : 338
    Points : 791
    Points
    791
    Par défaut
    Pour aller voir en base, ta démarche me parait pas mal.
    Par contre, sur mon ancien SGBD, les données n'étaient pas présentes en base tant que le commit n'avait pas eu lieu. Et la présence de @Rollback me laisse penser que tout est roll-backer en fin de test.

    La présence d'un "update" lors d'un "select" me laisse perplexe.

    J'ai une solution un peu lourde à te proposer : séparer la classe de tests en plusieurs classes. Et retirer l'annotation @rollback.

    Tu pourras ainsi t'assurer dans un test qu'un insert simple d'un questionnaire fonctionne et qu'il est bien présent en base en fin de test. Ensuite tu pourras faire le même constat dans un autre test pour le questionnaire et une question. Et pour finir tu pourras tester les countAll().

    Mais une autre personne aura peut être une solution plus simple à te proposer.

    Benoit

  17. #17
    Membre chevronné
    Inscrit en
    Août 2009
    Messages
    1 073
    Détails du profil
    Informations forums :
    Inscription : Août 2009
    Messages : 1 073
    Points : 1 806
    Points
    1 806
    Par défaut
    Citation Envoyé par bboulch Voir le message
    Pour aller voir en base, ta démarche me parait pas mal.
    Par contre, sur mon ancien SGBD, les données n'étaient pas présentes en base tant que le commit n'avait pas eu lieu. Et la présence de @Rollback me laisse penser que tout est roll-backer en fin de test.
    C'est le comportement normal d'un SGBD, de ne pas valider les modifications tant qu'il n'y a pas eu un commit.
    Et en effet, l'annotation @Rollback signifie qu'il y aura un rollback en fin de méthode de test, ce qui veut dire que si c'est créé dans une méthode, une autre méthode ne la trouvera pas en base ...

  18. #18
    Membre habitué
    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2008
    Messages
    379
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 39
    Localisation : France, Val d'Oise (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2008
    Messages : 379
    Points : 129
    Points
    129
    Par défaut
    oui, je connaissais le role du rollback, c'est pour ça que je mettais mes breaks dans la méthode startTransaction, avant tout rollback.
    Par contre j'avais oublié pour le commit. Cela dit, le commit est fait en fin de transaction si je me souviens bien (j'utilise spring, donc il n'y a pas de commit explicite dans mon code), donc vu que je plaçais mes breaks après le questionnaire = serviceQuestionnaire.saveOne(q1); (par exemple), le questionnaire aurait du apparaitre en base, non?

    Bon, toujours est-il que j'ai testé un peu à la manière de la proposition de Bboulch : j'ai laissé la méthode startTransaction telle quelle, mais j'ai commenté tous les tests sauf testLoad dont j'ai commenté l'annotation rollback:
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    	@Test @Transactional
    	//@Rollback
    	public void testLoad() {
    		Question question2 = questionDao.getOne(question.getIdQuestion());
    		Assert.assertEquals(question, question2);
    	}
    J'ai mis un breakpoint au niveau de la ligne 5 du code ci-dessus et je suis allée voir dans la base via pgAdmin. C'est bizarre car la sequence "hibernate_sequence" a bien été incrémentée (valeur au moment du breackpoint : 2), mais qu'aucune donnée n'apparait en base que ce soit dans la table QUESTION ou dans la table QUESTIONNAIRE...
    EDIT : au moment du breakpoint, les requêtes insert n'apparaissent pas encore dans les logs p6spy, ce qui pourrait expliquer qu'on trouve rien dans la base de données...
    Reste à savoir pourquoi les requêtes sont pas exécutées avant le breakpoint?
    Je continue de chercher...

  19. #19
    Membre habitué
    Femme Profil pro
    Ingénieur développement logiciels
    Inscrit en
    Juin 2008
    Messages
    379
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Âge : 39
    Localisation : France, Val d'Oise (Île de France)

    Informations professionnelles :
    Activité : Ingénieur développement logiciels

    Informations forums :
    Inscription : Juin 2008
    Messages : 379
    Points : 129
    Points
    129
    Par défaut
    Re-EDIT : en fait si, les requêtes insert apparaissent bien dans les log au moment du breakpoint, c'est juste que le fichier avait pas du bien être rechargé la première fois que j'ai checké...
    Par contre, toujours rien en base

  20. #20
    Membre éclairé

    Profil pro
    Technicien
    Inscrit en
    Février 2009
    Messages
    338
    Détails du profil
    Informations personnelles :
    Âge : 45
    Localisation : France

    Informations professionnelles :
    Activité : Technicien

    Informations forums :
    Inscription : Février 2009
    Messages : 338
    Points : 791
    Points
    791
    Par défaut
    Euh, es-tu sûr du code affiché ? Je ne vois pas pourquoi la séquence serait incrementée pour une lecture.

    Les données apparaitront en base une fois le commit fait. Quand est-ce que Spring se charge de le faire ?

    Vu que le "rollback" est présent dans les logs de p6spy, le "commit" devrait peut être aussi apparaitre. Et les données seront présentes en base après que le commit "fût" affiché.

    Courage !

    Benoit

+ Répondre à la discussion
Cette discussion est résolue.
Page 1 sur 2 12 DernièreDernière

Discussions similaires

  1. Problèmes lecture/écriture bytea avec Postgresql
    Par Aldouille dans le forum JDBC
    Réponses: 2
    Dernier message: 15/03/2018, 12h51
  2. Problème de requête en PHP avec postgreSQL
    Par Kira07 dans le forum PostgreSQL
    Réponses: 2
    Dernier message: 29/05/2007, 22h52
  3. Réponses: 3
    Dernier message: 11/12/2006, 19h57
  4. [PostgreSQL] [PostgreSQL] Problème de syntaxe (NULL) avec PHP et Postgresql
    Par el_butcho dans le forum PHP & Base de données
    Réponses: 40
    Dernier message: 16/07/2006, 18h28
  5. Problème de login avec Postgresql
    Par maddog2032 dans le forum PostgreSQL
    Réponses: 5
    Dernier message: 27/04/2005, 13h19

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo