27 April 2019
Cas interessant pour Email, qui doit faire le lien vers de multiples destinataires et de multiples cc.
Ce que je voudrais faire :
avoir une fonction getTo, qui renvoie une liste de string avec les adresses, et une fonction getCc, qui fait la même chose.
Je vais essayer de m'approcher de ça.
Mapping avec des Entités EmailParticipant.
The best way to map a @OneToMany relationship with JPA and Hibernate
Création d'une classe EmailParticipant
*
Une bonne analyse sur la question de la composition (vs agrégation) :
* JPA Aggregation versus composition and deleting of child entities
Comme il n'y à pas d'Id spécifique, il faut créer une sous classe composite sur le modèle de :
J'ai une classe EmailParticipant, qui possède un EmailParticipantId avec les même champs.
On peut simplifier avec ClassId en indiquant la classe elle même.
* SQL JPA - Multiple columns as primary key
** La bonne réponse
Bilan provisoire
On arrive au resultat suivant :
{
"emailAccount":"devkdm@festival-cannes.fr",
"emailUid":"test1",
"subject":"Ce mail n'existe pas",
"from":"hnlocher@cst.fr",
"sendDate":"2019-04-24T07:08:00.000+0000",
"emldirpath":"2019.04.10+10.52.23-2-%3Cdfdce60f-1d3d-403f-2c2b-c5b642d296a6%40cst.fr%3E/",
"emlfilename":"mail.eml",
"participants":
[
{"relation":"TO","address":"devkdm@festival-cannes.fr"},
{"relation":"CC","address":"hnlocher@free.fr"}
]
}
J'aurais voulu plutot :
"to":
[
{"devkdm@festival-cannes.fr"}
]
"cc":
[
{"hnlocher@free.fr"}
]
Mais ça va être trop long à obtenir pour cette année.
Il y a une piste ici :
L'enregistrement des emails sans participants (TO et CC) et sans attachements d'assets fonctionne rapidement.
Par contre, lorsque l'on ajoute des collections en liaison oneToMany, l'enregistrement ne se fait pas avec la configuration actuelle, ou l'on reprend le champ clef étrangère.
La clef étrangère n'est pas initialisée au moment de l'écriture, et l'écriture échoue. Au moins, la cascade fonctionne.
En rendant la liaison bidirectionnelle (ce qui est idiot pour les participants, qui sont clairement en composition), la sauvegarde fonctionne.
Tout fonctionne au moment des tests, mais lors de l'enregistrement du mail depuis kdmMailFetcher il se passe la chose suivante :
2019-04-28 09:32:10.916 INFO 3772 --- [ main] logFonctionnel : Email from : hnlocher@cst.fr
>>> Id : 12
>>> Subject : Fwd: Insider with enclosings
>>> Date : 2019.04.15 21.53.02
>>> To : devkdm@festival-cannes.fr
>>> Cc :
>>> Bcc :
>>> Nombre de pièces jointes : 1
>>> X-UID : null
>>> Message-ID : <0f7971ed97aef73c5c8ec91fa9d1fb9b@cst.fr>
>>> Is an autoreply :no
2019-04-28 09:32:10.947 DEBUG 3772 --- [ main] o.h.SQL :
insert
into
email
(emailaccount, uid, emldirpath, emlfilename, sender, senddate, subject)
values
(?, ?, ?, ?, ?, ?, ?)
Hibernate:
insert
into
email
(emailaccount, uid, emldirpath, emlfilename, sender, senddate, subject)
values
(?, ?, ?, ?, ?, ?, ?)
2019-04-28 09:32:10.947 TRACE 3772 --- [ main] o.h.t.d.s.BasicBinder : binding parameter [1] as [VARCHAR] - [TODO]
2019-04-28 09:32:10.947 TRACE 3772 --- [ main] o.h.t.d.s.BasicBinder : binding parameter [2] as [VARCHAR] - [<0f7971ed97aef73c5c8ec91fa9d1fb9b@cst.fr>]
2019-04-28 09:32:10.947 TRACE 3772 --- [ main] o.h.t.d.s.BasicBinder : binding parameter [3] as [VARCHAR] - [/to/do/]
2019-04-28 09:32:10.947 TRACE 3772 --- [ main] o.h.t.d.s.BasicBinder : binding parameter [4] as [VARCHAR] - [todo.txt]
2019-04-28 09:32:10.947 TRACE 3772 --- [ main] o.h.t.d.s.BasicBinder : binding parameter [5] as [VARCHAR] - [hnlocher@cst.fr]
2019-04-28 09:32:10.947 TRACE 3772 --- [ main] o.h.t.d.s.BasicBinder : binding parameter [6] as [TIMESTAMP] - [Mon Apr 15 21:53:02 CEST 2019]
2019-04-28 09:32:10.947 TRACE 3772 --- [ main] o.h.t.d.s.BasicBinder : binding parameter [7] as [VARCHAR] - [Fwd: Insider with enclosings]
2019-04-28 09:32:10.963 DEBUG 3772 --- [ main] o.h.SQL :
insert
into
emailassetpresence
(email_idemail, assetuuid, assetkind, creationtime, filename, path)
values
(?, ?, ?, ?, ?, ?)
Hibernate:
insert
into
emailassetpresence
(email_idemail, assetuuid, assetkind, creationtime, filename, path)
values
(?, ?, ?, ?, ?, ?)
2019-04-28 09:32:10.963 TRACE 3772 --- [ main] o.h.t.d.s.BasicBinder : binding parameter [1] as [INTEGER] - [25]
2019-04-28 09:32:10.963 TRACE 3772 --- [ main] o.h.t.d.s.BasicBinder : binding parameter [2] as [VARCHAR] - [urn:uuid:2e564f38-3f0f-4f7a-a0fb-3786af07d8a3]
2019-04-28 09:32:10.963 TRACE 3772 --- [ main] o.h.t.d.s.BasicBinder : binding parameter [3] as [VARCHAR] - [KDM]
2019-04-28 09:32:10.963 TRACE 3772 --- [ main] o.h.t.d.s.BasicBinder : binding parameter [4] as [TIMESTAMP] - [null]
2019-04-28 09:32:10.963 TRACE 3772 --- [ main] o.h.t.d.s.BasicBinder : binding parameter [5] as [VARCHAR] - [null]
2019-04-28 09:32:10.963 TRACE 3772 --- [ main] o.h.t.d.s.BasicBinder : binding parameter [6] as [VARCHAR] - [null]
2019-04-28 09:32:10.963 DEBUG 3772 --- [ main] o.h.SQL :
insert
into
emailassetpresence
(email_idemail, assetuuid, assetkind, creationtime, filename, path)
values
(?, ?, ?, ?, ?, ?)
Hibernate:
insert
into
emailassetpresence
(email_idemail, assetuuid, assetkind, creationtime, filename, path)
values
(?, ?, ?, ?, ?, ?)
2019-04-28 09:32:10.963 TRACE 3772 --- [ main] o.h.t.d.s.BasicBinder : binding parameter [1] as [INTEGER] - [25]
2019-04-28 09:32:10.963 TRACE 3772 --- [ main] o.h.t.d.s.BasicBinder : binding parameter [2] as [VARCHAR] - [urn:uuid:408139f6-70ab-4ed8-9fd1-c63ce1dc0d30]
2019-04-28 09:32:10.963 TRACE 3772 --- [ main] o.h.t.d.s.BasicBinder : binding parameter [3] as [VARCHAR] - [CPL]
2019-04-28 09:32:10.963 TRACE 3772 --- [ main] o.h.t.d.s.BasicBinder : binding parameter [4] as [TIMESTAMP] - [null]
2019-04-28 09:32:10.963 TRACE 3772 --- [ main] o.h.t.d.s.BasicBinder : binding parameter [5] as [VARCHAR] - [null]
2019-04-28 09:32:10.963 TRACE 3772 --- [ main] o.h.t.d.s.BasicBinder : binding parameter [6] as [VARCHAR] - [null]
2019-04-28 09:32:10.963 DEBUG 3772 --- [ main] o.h.SQL :
insert
into
emailparticipant
(relation, email_idemail, adress)
values
(?, ?, ?)
Hibernate:
insert
into
emailparticipant
(relation, email_idemail, adress)
values
(?, ?, ?)
2019-04-28 09:32:10.979 TRACE 3772 --- [ main] o.h.t.d.s.BasicBinder : binding parameter [1] as [VARCHAR] - [TO]
2019-04-28 09:32:10.979 TRACE 3772 --- [ main] o.h.t.d.s.BasicBinder : binding parameter [2] as [INTEGER] - [25]
2019-04-28 09:32:10.979 TRACE 3772 --- [ main] o.h.t.d.s.BasicBinder : binding parameter [3] as [VARCHAR] - [devkdm@festival-cannes.fr]
2019-04-28 09:32:10.979 DEBUG 3772 --- [ main] o.h.SQL :
insert
into
emailparticipant
(relation, email_idemail, adress)
values
(?, ?, ?)
Hibernate:
insert
into
emailparticipant
(relation, email_idemail, adress)
values
(?, ?, ?)
2019-04-28 09:32:10.979 TRACE 3772 --- [ main] o.h.t.d.s.BasicBinder : binding parameter [1] as [VARCHAR] - [CC]
2019-04-28 09:32:10.979 TRACE 3772 --- [ main] o.h.t.d.s.BasicBinder : binding parameter [2] as [INTEGER] - [25]
2019-04-28 09:32:10.979 TRACE 3772 --- [ main] o.h.t.d.s.BasicBinder : binding parameter [3] as [VARCHAR] - [devkdm@festival-cannes.fr]
2019-04-28 09:32:10.994 DEBUG 3772 --- [ main] o.h.SQL :
update
emailassetpresence
set
email_idemail=?
where
email_idemail=?
and assetuuid=?
and assetkind=?
and creationtime=?
and filename=?
and path=?
Hibernate:
update
emailassetpresence
set
email_idemail=?
where
email_idemail=?
and assetuuid=?
and assetkind=?
and creationtime=?
and filename=?
and path=?
2019-04-28 09:32:10.994 TRACE 3772 --- [ main] o.h.t.d.s.BasicBinder : binding parameter [1] as [INTEGER] - [25]
2019-04-28 09:32:10.994 TRACE 3772 --- [ main] o.h.t.d.s.BasicBinder : binding parameter [2] as [INTEGER] - [25]
2019-04-28 09:32:10.994 TRACE 3772 --- [ main] o.h.t.d.s.BasicBinder : binding parameter [3] as [VARCHAR] - [urn:uuid:2e564f38-3f0f-4f7a-a0fb-3786af07d8a3]
2019-04-28 09:32:10.994 TRACE 3772 --- [ main] o.h.t.d.s.BasicBinder : binding parameter [4] as [VARCHAR] - [KDM]
2019-04-28 09:32:10.994 TRACE 3772 --- [ main] o.h.t.d.s.BasicBinder : binding parameter [5] as [TIMESTAMP] - [null]
2019-04-28 09:32:10.994 TRACE 3772 --- [ main] o.h.t.d.s.BasicBinder : binding parameter [6] as [VARCHAR] - [null]
2019-04-28 09:32:10.994 TRACE 3772 --- [ main] o.h.t.d.s.BasicBinder : binding parameter [7] as [VARCHAR] - [null]
2019-04-28 09:32:10.994 ERROR 3772 --- [ main] o.h.i.ExceptionMapperStandardImpl : HHH000346: Error during managed flush [Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1]
2019-04-28 09:32:10.994 INFO 3772 --- [ main] o.h.e.j.b.i.AbstractBatchImpl : HHH000010: On release of batch it still contained JDBC statements
2019-04-28 09:32:11.010 ERROR 3772 --- [ main] logTechnique : Erreur lors de l'appel au handler
org.springframework.orm.ObjectOptimisticLockingFailureException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1; nested exception is org.hibernate.StaleStateException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:338) ~[spring-orm-5.1.4.RELEASE.jar:5.1.4.RELEASE]
at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:253) ~[spring-orm-5.1.4.RELEASE.jar:5.1.4.RELEASE]
at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:536) ~[spring-orm-5.1.4.RELEASE.jar:5.1.4.RELEASE]
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:746) ~[spring-tx-5.1.4.RELEASE.jar:5.1.4.RELEASE]
at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:714) ~[spring-tx-5.1.4.RELEASE.jar:5.1.4.RELEASE]
at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:533) ~[spring-tx-5.1.4.RELEASE.jar:5.1.4.RELEASE]
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:304) ~[spring-tx-5.1.4.RELEASE.jar:5.1.4.RELEASE]
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:98) ~[spring-tx-5.1.4.RELEASE.jar:5.1.4.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.1.4.RELEASE.jar:5.1.4.RELEASE]
at org.springframework.dao.support.PersistenceExceptionTranslationInterceptor.invoke(PersistenceExceptionTranslationInterceptor.java:139) ~[spring-tx-5.1.4.RELEASE.jar:5.1.4.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.1.4.RELEASE.jar:5.1.4.RELEASE]
at org.springframework.data.jpa.repository.support.CrudMethodMetadataPostProcessor$CrudMethodMetadataPopulatingMethodInterceptor.invoke(CrudMethodMetadataPostProcessor.java:135) ~[spring-data-jpa-2.1.4.RELEASE.jar:2.1.4.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.1.4.RELEASE.jar:5.1.4.RELEASE]
at org.springframework.aop.interceptor.ExposeInvocationInterceptor.invoke(ExposeInvocationInterceptor.java:93) ~[spring-aop-5.1.4.RELEASE.jar:5.1.4.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.1.4.RELEASE.jar:5.1.4.RELEASE]
at org.springframework.data.repository.core.support.SurroundingTransactionDetectorMethodInterceptor.invoke(SurroundingTransactionDetectorMethodInterceptor.java:61) ~[spring-data-commons-2.1.4.RELEASE.jar:2.1.4.RELEASE]
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:186) ~[spring-aop-5.1.4.RELEASE.jar:5.1.4.RELEASE]
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:212) ~[spring-aop-5.1.4.RELEASE.jar:5.1.4.RELEASE]
at com.sun.proxy.$Proxy123.save(Unknown Source) ~[?:?]
at fr.cst.rd.digitalCinemaAssetHandler.services.EmailService.saveEmail(EmailService.java:31) ~[digitalCinemaAssetHandler-0.0.20-SNAPSHOT.jar:0.0.20-SNAPSHOT]
at fr.cst.rd.kdmmailfetcher.db.SerialisationAssets.terminate(SerialisationAssets.java:226) ~[classes/:?]
at fr.cst.rd.kdmmailfetcher.DigitalCinemaFileHandler.terminate(DigitalCinemaFileHandler.java:638) ~[classes/:?]
at fr.cst.rd.kdmmailfetcher.DigitalCinemaEmailHandler.handleEmail(DigitalCinemaEmailHandler.java:66) ~[classes/:?]
at fr.cst.rd.kdmmailfetcher.MailBox$UnreadMails.processFetchedMails(MailBox.java:66) [classes/:?]
at fr.cst.rd.kdmmailfetcher.KdmMailFetcherJob.doJob(KdmMailFetcherJob.java:100) [classes/:?]
at fr.cst.rd.kdmmailfetcher.KdmMailFetcher.run(KdmMailFetcher.java:59) [classes/:?]
at org.springframework.boot.SpringApplication.callRunner(SpringApplication.java:813) [spring-boot-2.1.2.RELEASE.jar:2.1.2.RELEASE]
at org.springframework.boot.SpringApplication.callRunners(SpringApplication.java:797) [spring-boot-2.1.2.RELEASE.jar:2.1.2.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:324) [spring-boot-2.1.2.RELEASE.jar:2.1.2.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1260) [spring-boot-2.1.2.RELEASE.jar:2.1.2.RELEASE]
at org.springframework.boot.SpringApplication.run(SpringApplication.java:1248) [spring-boot-2.1.2.RELEASE.jar:2.1.2.RELEASE]
at fr.cst.rd.kdmmailfetcher.KdmMailFetcher.main(KdmMailFetcher.java:37) [classes/:?]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_121]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[?:1.8.0_121]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[?:1.8.0_121]
at java.lang.reflect.Method.invoke(Method.java:498) ~[?:1.8.0_121]
at org.springframework.boot.maven.AbstractRunMojo$LaunchRunner.run(AbstractRunMojo.java:558) [spring-boot-maven-plugin-2.1.2.RELEASE.jar:2.1.2.RELEASE]
at java.lang.Thread.run(Thread.java:745) [?:1.8.0_121]
Caused by: org.hibernate.StaleStateException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1
at org.hibernate.jdbc.Expectations$BasicExpectation.checkBatched(Expectations.java:67) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]
at org.hibernate.jdbc.Expectations$BasicExpectation.verifyOutcome(Expectations.java:54) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]
at org.hibernate.engine.jdbc.batch.internal.NonBatchingBatch.addToBatch(NonBatchingBatch.java:46) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]
at org.hibernate.persister.collection.AbstractCollectionPersister.recreate(AbstractCollectionPersister.java:1340) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]
at org.hibernate.persister.collection.OneToManyPersister.recreate(OneToManyPersister.java:186) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]
at org.hibernate.action.internal.CollectionRecreateAction.execute(CollectionRecreateAction.java:50) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:604) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:478) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]
at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:356) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]
at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:39) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]
at org.hibernate.internal.SessionImpl.doFlush(SessionImpl.java:1454) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]
at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:511) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]
at org.hibernate.internal.SessionImpl.flushBeforeTransactionCompletion(SessionImpl.java:3283) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]
at org.hibernate.internal.SessionImpl.beforeTransactionCompletion(SessionImpl.java:2479) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]
at org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl.beforeTransactionCompletion(JdbcCoordinatorImpl.java:473) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]
at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.beforeCompletionCallback(JdbcResourceLocalTransactionCoordinatorImpl.java:178) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]
at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.access$300(JdbcResourceLocalTransactionCoordinatorImpl.java:39) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]
at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl.commit(JdbcResourceLocalTransactionCoordinatorImpl.java:271) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]
at org.hibernate.engine.transaction.internal.TransactionImpl.commit(TransactionImpl.java:98) ~[hibernate-core-5.3.7.Final.jar:5.3.7.Final]
at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:532) ~[spring-orm-5.1.4.RELEASE.jar:5.1.4.RELEASE]
... 35 more
L'assset urn:uuid:2e564f38-3f0f-4f7a-a0fb-3786af07d8a3 à déjà été écrite, il y a un update de fait dessus. Pourquoi ?
Réponse, c'était l'autre bout le la liaison qui écrit à son tour.
Il faut mettre @JoinColumn(... insertable="false", updatetable="false") du coté opposé.
What's the difference between @JoinColumn and mappedBy when using a JPA @OneToMany association?