From c9541834d522e5ce55a716e2361706ba2d7b6db9 Mon Sep 17 00:00:00 2001 From: Vlad Mihalcea Date: Wed, 20 Sep 2017 10:42:39 +0300 Subject: [PATCH] HHH-11996 - order_inserts causing constraint violation (cherry picked from commit 287221e26e1ce7bfcf537b4f0c6d9476f0d5b1ca) --- .../org/hibernate/engine/spi/ActionQueue.java | 3 +- .../InsertOrderingWithMultipleManyToOne.java | 164 ++++++++++++++++++ 2 files changed, 165 insertions(+), 2 deletions(-) create mode 100644 hibernate-core/src/test/java/org/hibernate/test/insertordering/InsertOrderingWithMultipleManyToOne.java diff --git a/hibernate-core/src/main/java/org/hibernate/engine/spi/ActionQueue.java b/hibernate-core/src/main/java/org/hibernate/engine/spi/ActionQueue.java index b77a6ea6b4..ce9f2b9c8a 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/spi/ActionQueue.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/spi/ActionQueue.java @@ -1068,8 +1068,7 @@ public class ActionQueue { } boolean hasAnyChildEntityNames(BatchIdentifier batchIdentifier) { - return childEntityNames.contains( batchIdentifier.getEntityName() ) || - parentEntityNames.contains( batchIdentifier.getRootEntityName() ); + return childEntityNames.contains( batchIdentifier.getEntityName() ); } } diff --git a/hibernate-core/src/test/java/org/hibernate/test/insertordering/InsertOrderingWithMultipleManyToOne.java b/hibernate-core/src/test/java/org/hibernate/test/insertordering/InsertOrderingWithMultipleManyToOne.java new file mode 100644 index 0000000000..e980394cf7 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/insertordering/InsertOrderingWithMultipleManyToOne.java @@ -0,0 +1,164 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.test.insertordering; + +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import javax.persistence.CascadeType; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.ManyToMany; +import javax.persistence.ManyToOne; +import javax.persistence.SequenceGenerator; + +import org.hibernate.cfg.Environment; + +import org.hibernate.testing.TestForIssue; +import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase; +import org.hibernate.test.util.jdbc.PreparedStatementSpyConnectionProvider; +import org.junit.Test; + +import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate; +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; + +/** + * @author Vlad Mihalcea + */ +@TestForIssue(jiraKey = "HHH-11996") +public class InsertOrderingWithMultipleManyToOne + extends BaseNonConfigCoreFunctionalTestCase { + + private PreparedStatementSpyConnectionProvider connectionProvider = new PreparedStatementSpyConnectionProvider(); + + @Override + protected Class[] getAnnotatedClasses() { + return new Class[] { + Parent.class, + ChildA.class, + ChildB.class, + }; + } + + @Override + protected void addSettings(Map settings) { + settings.put( Environment.ORDER_INSERTS, "true" ); + settings.put( Environment.STATEMENT_BATCH_SIZE, "10" ); + settings.put( + org.hibernate.cfg.AvailableSettings.CONNECTION_PROVIDER, + connectionProvider + ); + } + + @Override + public void releaseResources() { + super.releaseResources(); + connectionProvider.stop(); + } + + @Test + public void testBatching() throws SQLException { + doInHibernate( this::sessionFactory, session -> { + Parent parent = new Parent(); + session.persist(parent); + + ChildA childA = new ChildA(); + childA.setParent(parent); + session.persist(childA); + + ChildB childB = new ChildB(); + childB.setParent(parent); + session.persist(childB); + + connectionProvider.clear(); + } ); + + assertEquals( 3, connectionProvider.getPreparedStatements().size() ); + /*PreparedStatement addressPreparedStatement = connectionProvider.getPreparedStatement( + "insert into Address (ID) values (?)" ); + verify( addressPreparedStatement, times( 2 ) ).addBatch(); + verify( addressPreparedStatement, times( 1 ) ).executeBatch(); + PreparedStatement personPreparedStatement = connectionProvider.getPreparedStatement( + "insert into Person (ID) values (?)" ); + verify( personPreparedStatement, times( 4 ) ).addBatch(); + verify( personPreparedStatement, times( 1 ) ).executeBatch();*/ + } + + @Entity(name = "Parent") + public static class Parent { + @Id + @GeneratedValue + private Integer id; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + } + + @Entity(name = "ChildA") + public static class ChildA { + @Id + @GeneratedValue + private Integer id; + + @ManyToOne + private Parent parent; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public Parent getParent() { + return parent; + } + + public void setParent(Parent parent) { + this.parent = parent; + } + } + + @Entity(name = "ChildB") + public static class ChildB { + @Id + @GeneratedValue + private Integer id; + + @ManyToOne + private Parent parent; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public Parent getParent() { + return parent; + } + + public void setParent(Parent parent) { + this.parent = parent; + } + } +}