@OneToMany with @JoinTable throws org.hibernate.exception.ConstraintViolationException

Description

Project reproducing issue is attached.


Possibly related to: https://hibernate.atlassian.net/browse/HHH-6776


Entities:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 package org.hibernate.bugreport.jointable.constraintviolation.entity; import org.hibernate.annotations.GenericGenerator; import javax.persistence.*; import java.util.HashSet; import java.util.Objects; import java.util.Set; @Entity public class Laptop { @Id @GeneratedValue(generator = "UUID") @GenericGenerator( name = "UUID", strategy = "org.hibernate.id.UUIDGenerator" ) private String id; private String brand; private String series; @OneToMany(cascade = CascadeType.ALL) @JoinTable( name = "laptop_components", joinColumns = @JoinColumn( name = "laptop_id", referencedColumnName = "id" ), inverseJoinColumns = @JoinColumn( name = "component_id", referencedColumnName = "id" ) ) private Set<Component> components = new HashSet<>(); public String getId() { return id; } public void setId(String id) { this.id = id; } public String getBrand() { return brand; } public void setBrand(String brand) { this.brand = brand; } public String getSeries() { return series; } public void setSeries(String series) { this.series = series; } public Set<Component> getComponents() { return components; } public void setComponents(Set<Component> components) { this.components = components; } public void addComponent(Component component) { getComponents().add(component); component.setLaptop(this); } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Laptop laptop = (Laptop) o; return Objects.equals(id, laptop.id); } @Override public int hashCode() { return Objects.hash(id); } } package org.hibernate.bugreport.jointable.constraintviolation.entity; import org.hibernate.annotations.GenericGenerator; import javax.persistence.*; import java.util.Objects; @Entity public class Component { @Id @GeneratedValue(generator = "UUID") @GenericGenerator( name = "UUID", strategy = "org.hibernate.id.UUIDGenerator" ) private String id; private String name; @ManyToOne(cascade = CascadeType.ALL) @JoinTable( name = "laptop_components", joinColumns = @JoinColumn( name = "component_id", referencedColumnName = "id" ), inverseJoinColumns = @JoinColumn( name = "laptop_id", referencedColumnName = "id" ) ) private Laptop laptop; public String getId() { return id; } public void setId(String id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public Laptop getLaptop() { return laptop; } public void setLaptop(Laptop laptop) { this.laptop = laptop; } @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; Component component = (Component) o; return Objects.equals(id, component.id); } @Override public int hashCode() { return Objects.hash(id); } }

persistence.xml

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 <persistence xmlns="http://java.sun.com/xml/ns/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" version="1.0"> <persistence-unit name="JoinTableConstraintViolation" transaction-type="RESOURCE_LOCAL"> <class>org.hibernate.bugreport.jointable.constraintviolation.entity.Laptop</class> <class>org.hibernate.bugreport.jointable.constraintviolation.entity.Component</class> <properties> <property name="hibernate.dialect" value="org.hibernate.dialect.H2Dialect"/> <property name="hibernate.hbm2ddl.auto" value="create"/> <property name="hibernate.connection.driver_class" value="org.h2.Driver"/> <property name="hibernate.connection.username" value="sa"/> <property name="hibernate.connection.password" value="password"/> <property name="hibernate.connection.url" value="jdbc:h2:file:~/diaries/diary1"/> </properties> </persistence-unit> </persistence>

Test case:

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 package org.hibernate.bugreport.jointable.constraintviolation; import org.hibernate.bugreport.jointable.constraintviolation.entity.Component; import org.hibernate.bugreport.jointable.constraintviolation.entity.Laptop; import org.junit.Test; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.EntityTransaction; import javax.persistence.Persistence; public class JoinTableTests { @Test public void testSetup() { EntityManagerFactory entityManagerFactory = Persistence.createEntityManagerFactory("JoinTableConstraintViolation"); EntityManager entityManager = entityManagerFactory.createEntityManager(); EntityTransaction transaction = entityManager.getTransaction(); transaction.begin(); Laptop laptop = new Laptop(); laptop.setBrand("Toshiba"); laptop.setSeries("Protege"); Component component = new Component(); component.setName("RAM"); laptop.addComponent(component); entityManager.persist(laptop); transaction.commit(); } }

Output:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 ug 14, 2019 10:40:26 PM org.hibernate.jpa.internal.util.LogHelper logPersistenceUnitInformation INFO: HHH000204: Processing PersistenceUnitInfo [name: JoinTableConstraintViolation] Aug 14, 2019 10:40:26 PM org.hibernate.Version logVersion INFO: HHH000412: Hibernate Core {5.4.4.Final} Aug 14, 2019 10:40:27 PM org.hibernate.annotations.common.reflection.java.JavaReflectionManager <clinit> INFO: HCANN000001: Hibernate Commons Annotations {5.1.0.Final} Aug 14, 2019 10:40:27 PM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl configure WARN: HHH10001002: Using Hibernate built-in connection pool (not for production use!) Aug 14, 2019 10:40:27 PM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl buildCreator INFO: HHH10001005: using driver [org.h2.Driver] at URL [jdbc:h2:file:~/diaries/diary1] Aug 14, 2019 10:40:27 PM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl buildCreator INFO: HHH10001001: Connection properties: {user=sa, password=****} Aug 14, 2019 10:40:27 PM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl buildCreator INFO: HHH10001003: Autocommit mode: false Aug 14, 2019 10:40:27 PM org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl$PooledConnections <init> INFO: HHH000115: Hibernate connection pool size: 20 (min=1) Aug 14, 2019 10:40:28 PM org.hibernate.dialect.Dialect <init> INFO: HHH000400: Using dialect: org.hibernate.dialect.H2Dialect Aug 14, 2019 10:40:29 PM org.hibernate.resource.transaction.backend.jdbc.internal.DdlTransactionIsolatorNonJtaImpl getIsolatedConnection INFO: HHH10001501: Connection obtained from JdbcConnectionAccess [org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator$ConnectionProviderJdbcConnectionAccess@7d151a] for (non-JTA) DDL execution was not in auto-commit mode; the Connection 'local transaction' will be committed and the Connection will be set into auto-commit mode. Aug 14, 2019 10:40:29 PM org.hibernate.resource.transaction.backend.jdbc.internal.DdlTransactionIsolatorNonJtaImpl getIsolatedConnection INFO: HHH10001501: Connection obtained from JdbcConnectionAccess [org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator$ConnectionProviderJdbcConnectionAccess@7180e701] for (non-JTA) DDL execution was not in auto-commit mode; the Connection 'local transaction' will be committed and the Connection will be set into auto-commit mode. Aug 14, 2019 10:40:29 PM org.hibernate.engine.transaction.jta.platform.internal.JtaPlatformInitiator initiateService INFO: HHH000490: Using JtaPlatform implementation: [org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform] Aug 14, 2019 10:40:29 PM org.hibernate.engine.jdbc.spi.SqlExceptionHelper logExceptions WARN: SQL Error: 23505, SQLState: 23505 Aug 14, 2019 10:40:29 PM org.hibernate.engine.jdbc.spi.SqlExceptionHelper logExceptions ERROR: Unique index or primary key violation: "PUBLIC.PRIMARY_KEY_A ON PUBLIC.LAPTOP_COMPONENTS(LAPTOP_ID, COMPONENT_ID) VALUES 1"; SQL statement: insert into laptop_components (laptop_id, component_id) values (?, ?) [23505-199] Aug 14, 2019 10:40:29 PM org.hibernate.engine.jdbc.batch.internal.AbstractBatchImpl release INFO: HHH000010: On release of batch it still contained JDBC statements javax.persistence.RollbackException: Error while committing the transaction at org.hibernate.internal.ExceptionConverterImpl.convertCommitException(ExceptionConverterImpl.java:81) at org.hibernate.engine.transaction.internal.TransactionImpl.commit(TransactionImpl.java:107) at org.hibernate.bugreport.jointable.constraintviolation.JoinTableTests.testSetup(JoinTableTests.java:31) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47) at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) at org.junit.runners.ParentRunner.run(ParentRunner.java:363) at org.junit.runner.JUnitCore.run(JUnitCore.java:137) at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68) at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47) at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242) at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70) Caused by: javax.persistence.PersistenceException: org.hibernate.exception.ConstraintViolationException: could not execute statement at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:154) at org.hibernate.internal.ExceptionConverterImpl.convert(ExceptionConverterImpl.java:181) at org.hibernate.internal.ExceptionConverterImpl.convertCommitException(ExceptionConverterImpl.java:65) ... 24 more Caused by: org.hibernate.exception.ConstraintViolationException: could not execute statement at org.hibernate.exception.internal.SQLExceptionTypeDelegate.convert(SQLExceptionTypeDelegate.java:59) at org.hibernate.exception.internal.StandardSQLExceptionConverter.convert(StandardSQLExceptionConverter.java:42) at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:113) at org.hibernate.engine.jdbc.spi.SqlExceptionHelper.convert(SqlExceptionHelper.java:99) at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:178) at org.hibernate.engine.jdbc.batch.internal.NonBatchingBatch.addToBatch(NonBatchingBatch.java:45) at org.hibernate.persister.collection.AbstractCollectionPersister.recreate(AbstractCollectionPersister.java:1353) at org.hibernate.action.internal.CollectionRecreateAction.execute(CollectionRecreateAction.java:52) at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:604) at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:478) at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:361) at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:40) at org.hibernate.internal.SessionImpl.doFlush(SessionImpl.java:1493) at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:496) at org.hibernate.internal.SessionImpl.flushBeforeTransactionCompletion(SessionImpl.java:3371) at org.hibernate.internal.SessionImpl.beforeTransactionCompletion(SessionImpl.java:2540) at org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl.beforeTransactionCompletion(JdbcCoordinatorImpl.java:473) at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.beforeCompletionCallback(JdbcResourceLocalTransactionCoordinatorImpl.java:178) at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl.access$300(JdbcResourceLocalTransactionCoordinatorImpl.java:39) at org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorImpl$TransactionDriverControlImpl.commit(JdbcResourceLocalTransactionCoordinatorImpl.java:271) at org.hibernate.engine.transaction.internal.TransactionImpl.commit(TransactionImpl.java:104) ... 23 more Caused by: org.h2.jdbc.JdbcSQLIntegrityConstraintViolationException: Unique index or primary key violation: "PUBLIC.PRIMARY_KEY_A ON PUBLIC.LAPTOP_COMPONENTS(LAPTOP_ID, COMPONENT_ID) VALUES 1"; SQL statement: insert into laptop_components (laptop_id, component_id) values (?, ?) [23505-199] at org.h2.message.DbException.getJdbcSQLException(DbException.java:457) at org.h2.message.DbException.getJdbcSQLException(DbException.java:427) at org.h2.message.DbException.get(DbException.java:205) at org.h2.message.DbException.get(DbException.java:181) at org.h2.index.BaseIndex.getDuplicateKeyException(BaseIndex.java:103) at org.h2.mvstore.db.MVSecondaryIndex.checkUnique(MVSecondaryIndex.java:220) at org.h2.mvstore.db.MVSecondaryIndex.add(MVSecondaryIndex.java:196) at org.h2.mvstore.db.MVTable.addRow(MVTable.java:546) at org.h2.command.dml.Insert.insertRows(Insert.java:180) at org.h2.command.dml.Insert.update(Insert.java:132) at org.h2.command.CommandContainer.update(CommandContainer.java:133) at org.h2.command.Command.executeUpdate(Command.java:267) at org.h2.jdbc.JdbcPreparedStatement.executeUpdateInternal(JdbcPreparedStatement.java:200) at org.h2.jdbc.JdbcPreparedStatement.executeUpdate(JdbcPreparedStatement.java:154) at org.hibernate.engine.jdbc.internal.ResultSetReturnImpl.executeUpdate(ResultSetReturnImpl.java:175) ... 39 more

Environment

None

Status

Assignee

Unassigned

Reporter

Behrang

Fix versions

None

Labels

None

backPortable

None

Suitable for new contributors

None

Requires Release Note

None

Pull Request

None

backportDecision

None

Components

Affects versions

5.4.4

Priority

Blocker
Configure