Saving ManyToMany with @ChangeTracking relation throws a PersistenceException

When I try to maintain the ManyToMany relationship, I get a database exception:

Exception in thread "main" javax.persistence.PersistenceException: Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.6.2.v20151217-774c696): org.eclipse.persistence.exceptions.DatabaseException Internal Exception: org.h2.jdbc.JdbcSQLException: NULL not allowed for column "INVERSES_ID"; SQL statement: INSERT INTO m2m_owner_inverse (inverses_ID, owners_ID) VALUES (?, ?) [23502-184] Error Code: 23502 Call: INSERT INTO m2m_owner_inverse (inverses_ID, owners_ID) VALUES (?, ?) bind => [null, 1] 

Strange, as I see in the log that both instances are inserted:

 [EL Fine]: sql: 2016-02-22 13:18:32.67--ClientSession(1546269015)--Connection(1894667608)--INSERT INTO M2MOWNER (NAME) VALUES (?) bind => [null] [EL Fine]: sql: 2016-02-22 13:18:32.676--ClientSession(1546269015)--Connection(1894667608)--CALL IDENTITY() [EL Fine]: sql: 2016-02-22 13:18:32.716--ClientSession(1546269015)--Connection(1894667608)--INSERT INTO M2MINVERSE (NAME) VALUES (?) bind => [null] [EL Fine]: sql: 2016-02-22 13:18:32.718--ClientSession(1546269015)--Connection(1894667608)--CALL IDENTITY() 

ChangeTracking is an eclipselink function, and the application requires javaagent to run:

 java -javaagent:eclipselink.jar 

Without ChangeTracking and the agent, it works as expected, the insert occurs. It also works if I keep the owner side (see Commented line)

Files can be found on github: https://github.com/zbiro/many2many

Sample can be run using

 gradle start 

Java files:

 public class M2MTest { public static void main(String[] args) { EntityManagerFactory emf = Persistence.createEntityManagerFactory("m2m-pu"); EntityManager em = emf.createEntityManager(); em.getTransaction().begin(); M2MOwner owner = em.merge(new M2MOwner()); em.flush(); M2MInverse inverse = new M2MInverse(); owner.getInverses().add(inverse); inverse.getOwners().add(owner); inverse = em.merge(inverse); // does not work if agent is used //owner = em.merge(owner); // works in all cases em.flush(); em.getTransaction().commit(); em.close(); emf.close(); } } @Entity @ChangeTracking(ChangeTrackingType.ATTRIBUTE) public class M2MOwner { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Integer id; private String name; @ManyToMany(cascade={CascadeType.ALL}) @JoinTable(name="m2m_owner_inverse") private Set<M2MInverse> inverses = new HashSet<>(); public Set<M2MInverse> getInverses() { return inverses; } } @Entity @ChangeTracking(ChangeTrackingType.ATTRIBUTE) public class M2MInverse { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Integer id; private String name; @javax.persistence.ManyToMany( cascade = { CascadeType.ALL }, mappedBy="inverses") private Set<M2MOwner> owners = new HashSet<>(); public Set<M2MOwner> getOwners() { return owners; } } 

persistence.xml

 <?xml version="1.0" encoding="UTF-8" ?> <persistence xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd" version="2.0" xmlns="http://java.sun.com/xml/ns/persistence"> <persistence-unit name="m2m-pu" transaction-type="RESOURCE_LOCAL"> <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider> <class>M2MOwner</class> <class>M2MInverse</class> <exclude-unlisted-classes>false</exclude-unlisted-classes> <properties> <property name="javax.persistence.jdbc.driver" value="org.h2.Driver" /> <property name="javax.persistence.jdbc.url" value="jdbc:h2:mem:tests;LOCK_TIMEOUT=10000" /> <property name="javax.persistence.jdbc.user" value="sa" /> <property name="eclipselink.ddl-generation" value="drop-and-create-tables" /> <property name="eclipselink.ddl-generation.output-mode" value="database" /> <property name="eclipselink.logging.parameters" value="true" /> <property name="eclipselink.logging.level.sql" value="FINEST" /> </properties> </persistence-unit> </persistence> 

build.gradle

 apply plugin: "java" repositories { mavenCentral() } configurations { eclipseLink { transitive = false } } ext.libs = [:] libs.eclipseLink = 'org.eclipse.persistence:eclipselink:2.6.2' dependencies { compile 'com.h2database:h2:1.4.191' compile libs.eclipseLink eclipseLink libs.eclipseLink } task start(type: JavaExec) { dependsOn build classpath = sourceSets.main.runtimeClasspath main = 'M2MTest' jvmArgs = ["-javaagent:${configurations.eclipseLink.singleFile}"] } 

My question is why this is happening and how I could avoid it.

+7
java jpa eclipselink load-time-weaving
source share

No one has answered this question yet.

See related questions:

5
With Eclipselink / JPA, can I have a foreign composite key that shares the field with the primary composite key?
3
Spring Boot with application-driven persistence context
2
Saving object graph with JPA without em.flush ()
2
How to get Eclipselink Entity Manager?
2
Java JPA (EclipseLink) How to get the next GeneratedValue before saving the actual object?
one
Netbeans Code for Postgresql and Eclipselink - Defining Question Relationships
one
JPA, MySQL, Hibernate & Maven Skeleton
one
The correct way to insert entity + foreign key into database (usage: Mysql, JPA)
0
since Java 10.0 NullPointer when searching for persistence - JPA eclipselink 2.6.5
0
why does MyEclipse show that join_table was not found during compilation error

All Articles