From 6f3feca7f4149fdcb9fd292f7cb81ea67bb50d30 Mon Sep 17 00:00:00 2001 From: Andrea Boriero Date: Mon, 20 Mar 2023 14:52:52 +0100 Subject: [PATCH] HHH-16337 Bytecode enhancement : ElementCollection is not deleted when replaced --- .../hibernate/event/internal/WrapVisitor.java | 26 +- .../ElementCollectionFlushAfterQueryTest.java | 128 ++++++++++ ...RecreateCollectionsInDefaultGroupTest.java | 224 ++++++++++++++++++ ...ancementElementCollectionRecreateTest.java | 222 +++++++++++++++++ .../flush/CollectionFlushAfterQueryTest.java | 157 ++++++++++++ .../merge/MergeUnsavedEntitiesTest.java | 39 ++- 6 files changed, 764 insertions(+), 32 deletions(-) create mode 100644 hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/enhancement/collectionelement/flush/ElementCollectionFlushAfterQueryTest.java create mode 100644 hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/enhancement/collectionelement/recreate/BytecodeEnhancementElementCollectionRecreateCollectionsInDefaultGroupTest.java create mode 100644 hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/enhancement/collectionelement/recreate/BytecodeEnhancementElementCollectionRecreateTest.java create mode 100644 hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/enhancement/flush/CollectionFlushAfterQueryTest.java diff --git a/hibernate-core/src/main/java/org/hibernate/event/internal/WrapVisitor.java b/hibernate-core/src/main/java/org/hibernate/event/internal/WrapVisitor.java index ba8b8b4716..2d7d2314e2 100644 --- a/hibernate-core/src/main/java/org/hibernate/event/internal/WrapVisitor.java +++ b/hibernate-core/src/main/java/org/hibernate/event/internal/WrapVisitor.java @@ -12,6 +12,7 @@ import org.hibernate.bytecode.enhance.spi.interceptor.EnhancementAsProxyLaziness import org.hibernate.bytecode.enhance.spi.interceptor.LazyAttributeLoadingInterceptor; import org.hibernate.collection.spi.PersistentCollection; import org.hibernate.engine.spi.CollectionEntry; +import org.hibernate.engine.spi.CollectionKey; import org.hibernate.engine.spi.EntityEntry; import org.hibernate.engine.spi.PersistenceContext; import org.hibernate.engine.spi.PersistentAttributeInterceptor; @@ -114,8 +115,6 @@ public class WrapVisitor extends ProxyVisitor { && ((LazyAttributeLoadingInterceptor)attributeInterceptor).isAttributeLoaded( persister.getAttributeMapping().getAttributeName() ) ) { final EntityEntry entry = persistenceContext.getEntry( entity ); if ( entry.isExistsInDatabase() ) { - // the collection has not been initialized and new collection values have been assigned, - // we need to be sure to delete all the collection elements before inserting the new ones final AbstractEntityPersister entityDescriptor = (AbstractEntityPersister) persister.getOwnerEntityPersister(); final Object key = entityDescriptor.getCollectionKey( @@ -124,14 +123,23 @@ public class WrapVisitor extends ProxyVisitor { entry, session ); - final PersistentCollection collectionInstance = persister.getCollectionSemantics() - .instantiateWrapper( key, persister, session ); - collectionInstance.setOwner( entity ); - persistenceContext.addUninitializedCollection( persister, collectionInstance, key ); + PersistentCollection collectionInstance = persistenceContext.getCollection( + new CollectionKey( persister, key ) + ); - final CollectionEntry collectionEntry = persistenceContext - .getCollectionEntry( collectionInstance ); - collectionEntry.setDoremove( true ); + if ( collectionInstance == null ) { + // the collection has not been initialized and new collection values have been assigned, + // we need to be sure to delete all the collection elements before inserting the new ones + collectionInstance = persister.getCollectionSemantics().instantiateWrapper( + key, + persister, + session + ); + persistenceContext.addUninitializedCollection( persister, collectionInstance, key ); + final CollectionEntry collectionEntry = persistenceContext.getCollectionEntry( + collectionInstance ); + collectionEntry.setDoremove( true ); + } } } } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/enhancement/collectionelement/flush/ElementCollectionFlushAfterQueryTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/enhancement/collectionelement/flush/ElementCollectionFlushAfterQueryTest.java new file mode 100644 index 0000000000..284be4273c --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/enhancement/collectionelement/flush/ElementCollectionFlushAfterQueryTest.java @@ -0,0 +1,128 @@ +package org.hibernate.orm.test.bytecode.enhancement.collectionelement.flush; + +import java.util.HashSet; +import java.util.Set; + +import org.hibernate.testing.TestForIssue; +import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner; +import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; +import org.junit.Test; +import org.junit.runner.RunWith; + +import jakarta.persistence.CollectionTable; +import jakarta.persistence.Column; +import jakarta.persistence.ElementCollection; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; + +@RunWith(BytecodeEnhancerRunner.class) +@TestForIssue(jiraKey = "HHH-16337") +public class ElementCollectionFlushAfterQueryTest extends BaseCoreFunctionalTestCase { + private static final Long MY_ENTITY_ID = 1l; + + @Override + protected Class[] getAnnotatedClasses() { + return new Class[] { + MyEntity.class, + MyOtherEntity.class + }; + } + + @Test + public void testAutoFlush() { + inTransaction( + session -> { + MyEntity myEntity = new MyEntity( MY_ENTITY_ID, "my entity" ); + myEntity.addRedirectUris( "1" ); + session.persist( myEntity ); + } + ); + + inTransaction( + session -> { + MyEntity myEntity = session.find( MyEntity.class, MY_ENTITY_ID ); + + Set set = new HashSet<>(); + set.add( "3" ); + myEntity.setRedirectUris( set ); + + session.createQuery( "from MyOtherEntity ", MyOtherEntity.class ).getResultList(); + } + ); + + inTransaction( + session -> { + MyEntity myEntity = session.find( MyEntity.class, MY_ENTITY_ID ); + Set redirectUris = myEntity.getRedirectUris(); + assertThat( redirectUris.size() ).isEqualTo( 1 ); + assertThat( redirectUris.contains( "3" ) ); + } + ); + + } + + @Entity(name = "MyEntity") + public static class MyEntity { + @Id + private Long id; + + private String name; + + @ElementCollection + @Column(name = "val") + @CollectionTable(name = "REDIRECT_URIS", joinColumns = { @JoinColumn(name = "ID") }) + protected Set redirectUris = new HashSet<>(); + + public MyEntity() { + } + + public MyEntity(Long id, String name) { + this.id = id; + this.name = name; + } + + public Long getId() { + return this.id; + } + + public Set getRedirectUris() { + return redirectUris; + } + + public void setRedirectUris(Set redirectUris) { + this.redirectUris = redirectUris; + } + + public void addRedirectUris(String redirectUri) { + this.redirectUris.add( redirectUri ); + } + } + + @Entity(name = "MyOtherEntity") + public class MyOtherEntity { + + @Id + private Long id; + + private String name; + + public MyOtherEntity() { + } + + public MyOtherEntity(Long id, String name) { + this.id = id; + this.name = name; + } + + public Long getId() { + return this.id; + } + + public void setId(Long id) { + this.id = id; + } + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/enhancement/collectionelement/recreate/BytecodeEnhancementElementCollectionRecreateCollectionsInDefaultGroupTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/enhancement/collectionelement/recreate/BytecodeEnhancementElementCollectionRecreateCollectionsInDefaultGroupTest.java new file mode 100644 index 0000000000..553d0078ef --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/enhancement/collectionelement/recreate/BytecodeEnhancementElementCollectionRecreateCollectionsInDefaultGroupTest.java @@ -0,0 +1,224 @@ +/* + * 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.orm.test.bytecode.enhancement.collectionelement.recreate; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.hibernate.boot.SessionFactoryBuilder; + +import org.hibernate.testing.TestForIssue; +import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner; +import org.hibernate.testing.bytecode.enhancement.EnhancementOptions; +import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import jakarta.persistence.ElementCollection; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.OrderColumn; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.Assert.assertTrue; + +@RunWith(BytecodeEnhancerRunner.class) +@EnhancementOptions(lazyLoading = true) +@TestForIssue(jiraKey = "HHH-14387") +public class BytecodeEnhancementElementCollectionRecreateCollectionsInDefaultGroupTest + extends BaseNonConfigCoreFunctionalTestCase { + + @Override + protected Class[] getAnnotatedClasses() { + return new Class[] { + MyEntity.class + }; + } + + @Override + protected void configureSessionFactoryBuilder(SessionFactoryBuilder sfb) { + super.configureSessionFactoryBuilder( sfb ); + sfb.applyCollectionsInDefaultFetchGroup( true ); + } + + @Before + public void check() { + inSession( + session -> + assertTrue( session.getSessionFactory().getSessionFactoryOptions() + .isCollectionsInDefaultFetchGroupEnabled() ) + ); + } + + + @After + public void tearDown() { + inTransaction( + session -> + session.createQuery( "delete from myentity" ).executeUpdate() + ); + } + + @Test + public void testRecreateCollection() { + inTransaction( session -> { + MyEntity entity = new MyEntity(); + entity.setId( 1 ); + entity.setElements( Arrays.asList( "one", "two", "four" ) ); + session.persist( entity ); + } ); + + inTransaction( session -> { + MyEntity entity = session.get( MyEntity.class, 1 ); + entity.setElements( Arrays.asList( "two", "three" ) ); + session.persist( entity ); + } ); + + inTransaction( session -> { + MyEntity entity = session.get( MyEntity.class, 1 ); + assertThat( entity.getElements() ) + .containsExactlyInAnyOrder( "two", "three" ); + } ); + } + + @Test + public void testRecreateCollectionFind() { + inTransaction( session -> { + MyEntity entity = new MyEntity(); + entity.setId( 1 ); + entity.setElements( Arrays.asList( "one", "two", "four" ) ); + session.persist( entity ); + } ); + + inTransaction( session -> { + MyEntity entity = session.find( MyEntity.class, 1 ); + entity.setElements( Arrays.asList( "two", "three" ) ); + session.persist( entity ); + } ); + + inTransaction( session -> { + MyEntity entity = session.find( MyEntity.class, 1 ); + assertThat( entity.getElements() ) + .containsExactlyInAnyOrder( "two", "three" ); + } ); + } + + @Test + public void testDeleteCollection() { + inTransaction( session -> { + MyEntity entity = new MyEntity(); + entity.setId( 1 ); + entity.setElements( Arrays.asList( "one", "two", "four" ) ); + session.persist( entity ); + } ); + + inTransaction( session -> { + MyEntity entity = session.get( MyEntity.class, 1 ); + entity.setElements( new ArrayList<>() ); + } ); + + inTransaction( session -> { + MyEntity entity = session.get( MyEntity.class, 1 ); + assertThat( entity.getElements() ) + .isEmpty(); + } ); + } + + @Test + public void testDeleteCollectionFind() { + inTransaction( session -> { + MyEntity entity = new MyEntity(); + entity.setId( 1 ); + entity.setElements( Arrays.asList( "one", "two", "four" ) ); + session.persist( entity ); + } ); + + inTransaction( session -> { + MyEntity entity = session.find( MyEntity.class, 1 ); + entity.setElements( new ArrayList<>() ); + } ); + + inTransaction( session -> { + MyEntity entity = session.find( MyEntity.class, 1 ); + assertThat( entity.getElements() ) + .isEmpty(); + } ); + } + + @Test + public void testLoadAndCommitTransactionDoesNotDeleteCollection() { + inTransaction( session -> { + MyEntity entity = new MyEntity(); + entity.setId( 1 ); + entity.setElements( Arrays.asList( "one", "two", "four" ) ); + session.persist( entity ); + } ); + + inTransaction( session -> + session.get( MyEntity.class, 1 ) + ); + + inTransaction( session -> { + MyEntity entity = session.get( MyEntity.class, 1 ); + assertThat( entity.getElements() ) + .containsExactlyInAnyOrder( "one", "two", "four" ); + } ); + + } + + @Test + public void testLoadAndCommitTransactionDoesNotDeleteCollectionFind() { + inTransaction( session -> { + MyEntity entity = new MyEntity(); + entity.setId( 1 ); + entity.setElements( Arrays.asList( "one", "two", "four" ) ); + session.persist( entity ); + } ); + + inTransaction( session -> + session.find( MyEntity.class, 1 ) + ); + + inTransaction( session -> { + MyEntity entity = session.find( MyEntity.class, 1 ); + assertThat( entity.getElements() ) + .containsExactlyInAnyOrder( "one", "two", "four" ); + } ); + + } + + @Entity(name = "myentity") + public static class MyEntity { + @Id + private Integer id; + + @ElementCollection + @OrderColumn + private List elements; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public List getElements() { + return elements; + } + + public void setElements(List elements) { + this.elements = elements; + } + + } + +} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/enhancement/collectionelement/recreate/BytecodeEnhancementElementCollectionRecreateTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/enhancement/collectionelement/recreate/BytecodeEnhancementElementCollectionRecreateTest.java new file mode 100644 index 0000000000..13da5e2f13 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/enhancement/collectionelement/recreate/BytecodeEnhancementElementCollectionRecreateTest.java @@ -0,0 +1,222 @@ +/* + * 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.orm.test.bytecode.enhancement.collectionelement.recreate; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.hibernate.boot.SessionFactoryBuilder; + +import org.hibernate.testing.TestForIssue; +import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner; +import org.hibernate.testing.bytecode.enhancement.EnhancementOptions; +import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import jakarta.persistence.ElementCollection; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.OrderColumn; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.junit.Assert.assertFalse; + +@RunWith(BytecodeEnhancerRunner.class) +@EnhancementOptions(lazyLoading = true) +@TestForIssue(jiraKey = "HHH-14387") +public class BytecodeEnhancementElementCollectionRecreateTest extends BaseNonConfigCoreFunctionalTestCase { + + @Override + protected Class[] getAnnotatedClasses() { + return new Class[] { + MyEntity.class + }; + } + + @Override + protected void configureSessionFactoryBuilder(SessionFactoryBuilder sfb) { + super.configureSessionFactoryBuilder( sfb ); + sfb.applyCollectionsInDefaultFetchGroup( false ); + } + + @Before + public void check() { + inSession( + session -> + assertFalse( session.getSessionFactory().getSessionFactoryOptions() + .isCollectionsInDefaultFetchGroupEnabled() ) + ); + } + + @After + public void tearDown() { + inTransaction( + session -> + session.createQuery( "delete from myentity" ).executeUpdate() + ); + } + + @Test + public void testRecreateCollection() { + inTransaction( session -> { + MyEntity entity = new MyEntity(); + entity.setId( 1 ); + entity.setElements( Arrays.asList( "one", "two", "four" ) ); + session.persist( entity ); + } ); + + inTransaction( session -> { + MyEntity entity = session.get( MyEntity.class, 1 ); + entity.setElements( Arrays.asList( "two", "three" ) ); + session.persist( entity ); + } ); + + inTransaction( session -> { + MyEntity entity = session.get( MyEntity.class, 1 ); + assertThat( entity.getElements() ) + .containsExactlyInAnyOrder( "two", "three" ); + } ); + } + + @Test + public void testRecreateCollectionFind() { + inTransaction( session -> { + MyEntity entity = new MyEntity(); + entity.setId( 1 ); + entity.setElements( Arrays.asList( "one", "two", "four" ) ); + session.persist( entity ); + } ); + + inTransaction( session -> { + MyEntity entity = session.find( MyEntity.class, 1 ); + entity.setElements( Arrays.asList( "two", "three" ) ); + session.persist( entity ); + } ); + + inTransaction( session -> { + MyEntity entity = session.find( MyEntity.class, 1 ); + assertThat( entity.getElements() ) + .containsExactlyInAnyOrder( "two", "three" ); + } ); + } + + @Test + public void testDeleteCollection() { + inTransaction( session -> { + MyEntity entity = new MyEntity(); + entity.setId( 1 ); + entity.setElements( Arrays.asList( "one", "two", "four" ) ); + session.persist( entity ); + } ); + + inTransaction( session -> { + MyEntity entity = session.get( MyEntity.class, 1 ); + entity.setElements( new ArrayList<>() ); + } ); + + inTransaction( session -> { + MyEntity entity = session.get( MyEntity.class, 1 ); + assertThat( entity.getElements() ) + .isEmpty(); + } ); + } + + @Test + public void testDeleteCollectionFind() { + inTransaction( session -> { + MyEntity entity = new MyEntity(); + entity.setId( 1 ); + entity.setElements( Arrays.asList( "one", "two", "four" ) ); + session.persist( entity ); + } ); + + inTransaction( session -> { + MyEntity entity = session.find( MyEntity.class, 1 ); + entity.setElements( new ArrayList<>() ); + } ); + + inTransaction( session -> { + MyEntity entity = session.find( MyEntity.class, 1 ); + assertThat( entity.getElements() ) + .isEmpty(); + } ); + } + + @Test + public void testLoadAndCommitTransactionDoesNotDeleteCollection() { + inTransaction( session -> { + MyEntity entity = new MyEntity(); + entity.setId( 1 ); + entity.setElements( Arrays.asList( "one", "two", "four" ) ); + session.persist( entity ); + } ); + + inTransaction( session -> + session.get( MyEntity.class, 1 ) + ); + + inTransaction( session -> { + MyEntity entity = session.get( MyEntity.class, 1 ); + assertThat( entity.getElements() ) + .containsExactlyInAnyOrder( "one", "two", "four" ); + } ); + + } + + @Test + public void testLoadAndCommitTransactionDoesNotDeleteCollectionFind() { + inTransaction( session -> { + MyEntity entity = new MyEntity(); + entity.setId( 1 ); + entity.setElements( Arrays.asList( "one", "two", "four" ) ); + session.persist( entity ); + } ); + + inTransaction( session -> + session.find( MyEntity.class, 1 ) + ); + + inTransaction( session -> { + MyEntity entity = session.find( MyEntity.class, 1 ); + assertThat( entity.getElements() ) + .containsExactlyInAnyOrder( "one", "two", "four" ); + } ); + + } + + @Entity(name = "myentity") + public static class MyEntity { + @Id + private Integer id; + + @ElementCollection + @OrderColumn + private List elements; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public List getElements() { + return elements; + } + + public void setElements(List elements) { + this.elements = elements; + } + + } + +} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/enhancement/flush/CollectionFlushAfterQueryTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/enhancement/flush/CollectionFlushAfterQueryTest.java new file mode 100644 index 0000000000..d0249bbd8c --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/enhancement/flush/CollectionFlushAfterQueryTest.java @@ -0,0 +1,157 @@ +package org.hibernate.orm.test.bytecode.enhancement.flush; + +import java.util.HashSet; +import java.util.Optional; +import java.util.Set; + +import org.hibernate.testing.TestForIssue; +import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner; +import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; +import org.junit.Test; +import org.junit.runner.RunWith; + +import jakarta.persistence.CascadeType; +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.OneToMany; + +import static org.assertj.core.api.AssertionsForClassTypes.assertThat; + +@RunWith(BytecodeEnhancerRunner.class) +@TestForIssue(jiraKey = "HHH-16337") +public class CollectionFlushAfterQueryTest extends BaseCoreFunctionalTestCase { + + private static final Long MY_ENTITY_ID = 1l; + + @Override + protected Class[] getAnnotatedClasses() { + return new Class[] { + CollectionFlushAfterQueryTest.MyEntity.class, + CollectionFlushAfterQueryTest.MyOtherEntity.class, + CollectionFlushAfterQueryTest.MyAnotherEntity.class + }; + } + + @Test + public void testAutoFlush() { + inTransaction( + session -> { + MyEntity myEntity = new MyEntity( MY_ENTITY_ID, "my entity" ); + MyOtherEntity otherEntity = new MyOtherEntity( 2l, "my other entity" ); + myEntity.addOtherEntity( otherEntity ); + session.persist( otherEntity ); + session.persist( myEntity ); + } + ); + + inTransaction( + session -> { + MyEntity myEntity = session.find( MyEntity.class, MY_ENTITY_ID ); + + MyOtherEntity otherEntity = new MyOtherEntity( 3l, "my new other entity" ); + Set set = new HashSet<>(); + set.add( otherEntity ); + myEntity.setOtherEntities( set ); + + session.createQuery( "from MyAnotherEntity ", MyAnotherEntity.class ).getResultList(); + } + ); + + inTransaction( + session -> { + MyEntity myEntity = session.find( MyEntity.class, MY_ENTITY_ID ); + Set redirectUris = myEntity.getOtherEntities(); + assertThat( redirectUris.size() ).isEqualTo( 1 ); + + Optional first = redirectUris.stream().findFirst(); + assertThat( first.get().getName() ).isEqualTo( "my new other entity" ); + } + ); + + } + + @Entity(name = "MyEntity") + public static class MyEntity { + @Id + private Long id; + + private String name; + + @OneToMany(cascade = CascadeType.ALL) + protected Set otherEntities = new HashSet<>(); + + public MyEntity() { + } + + public MyEntity(Long id, String name) { + this.id = id; + this.name = name; + } + + public Long getId() { + return this.id; + } + + public Set getOtherEntities() { + return otherEntities; + } + + public void setOtherEntities(Set otherEntities) { + this.otherEntities = otherEntities; + } + + public void addOtherEntity(MyOtherEntity otherEntity) { + this.otherEntities.add( otherEntity ); + } + } + + @Entity(name = "MyOtherEntity") + public static class MyOtherEntity { + + @Id + private Long id; + + private String name; + + public MyOtherEntity() { + } + + public MyOtherEntity(Long id, String name) { + this.id = id; + this.name = name; + } + + public Long getId() { + return this.id; + } + + public String getName() { + return name; + } + } + + @Entity(name = "MyAnotherEntity") + public static class MyAnotherEntity { + + @Id + private Long id; + + private String name; + + public MyAnotherEntity() { + } + + public MyAnotherEntity(Long id, String name) { + this.id = id; + this.name = name; + } + + public Long getId() { + return this.id; + } + + public void setId(Long id) { + this.id = id; + } + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/enhancement/merge/MergeUnsavedEntitiesTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/enhancement/merge/MergeUnsavedEntitiesTest.java index 2dd342bd1f..f7b742e383 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/enhancement/merge/MergeUnsavedEntitiesTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/bytecode/enhancement/merge/MergeUnsavedEntitiesTest.java @@ -6,8 +6,8 @@ import java.util.List; import org.hibernate.testing.TestForIssue; import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner; import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; +import org.junit.After; import org.junit.Test; -import org.junit.jupiter.api.AfterEach; import org.junit.runner.RunWith; import jakarta.persistence.Entity; @@ -21,9 +21,11 @@ import static jakarta.persistence.CascadeType.MERGE; import static org.assertj.core.api.AssertionsForClassTypes.assertThat; @RunWith(BytecodeEnhancerRunner.class) -@TestForIssue( jiraKey = "HHH-16322") +@TestForIssue(jiraKey = "HHH-16322") public class MergeUnsavedEntitiesTest extends BaseCoreFunctionalTestCase { + public static final String CHILD_NAME = "first child"; + @Override protected Class[] getAnnotatedClasses() { return new Class[] { @@ -32,23 +34,13 @@ public class MergeUnsavedEntitiesTest extends BaseCoreFunctionalTestCase { }; } - @AfterEach - public void tearDown() { - inTransaction( - session -> { - session.createMutationQuery( "delete from Child" ).executeUpdate(); - session.createMutationQuery( "delete from Parent" ).executeUpdate(); - } - ); - } - @Test public void testMerge() { inTransaction( session -> { Parent parent = new Parent( 1l, 2l ); parent = session.merge( parent ); - Child child = new Child( 2l, "first child" ); + Child child = new Child( 2l, CHILD_NAME ); child = session.merge( child ); parent.addChild( child ); parent.getId(); @@ -59,6 +51,8 @@ public class MergeUnsavedEntitiesTest extends BaseCoreFunctionalTestCase { session -> { Parent parent = session.find( Parent.class, 1l ); assertThat( parent.getChildren().size() ).isEqualTo( 1 ); + Child child = parent.getChildren().get( 0 ); + assertThat( child.getName() ).isEqualTo( CHILD_NAME ); } ); @@ -72,20 +66,16 @@ public class MergeUnsavedEntitiesTest extends BaseCoreFunctionalTestCase { inTransaction( session -> { Parent parent = session.find( Parent.class, 1l ); - parent.setChildren( new ArrayList<>() ); - session.merge( parent ); - } - ); + assertThat( parent.getChildren().size() ).isEqualTo( 1 ); + Child child = parent.getChildren().get( 0 ); + + assertThat( child.getName() ).isEqualTo( CHILD_NAME ); - inTransaction( - session -> { - Parent parent = session.find( Parent.class, 1l ); - assertThat( parent.getChildren().size() ).isEqualTo( 0 ); } ); } - @Entity(name = "parent") + @Entity(name = "Parent") @Table(name = "parent") public static class Parent { @Id @@ -139,7 +129,7 @@ public class MergeUnsavedEntitiesTest extends BaseCoreFunctionalTestCase { } } - @Entity + @Entity(name = "Child") @Table(name = "child") public static class Child { @@ -175,6 +165,9 @@ public class MergeUnsavedEntitiesTest extends BaseCoreFunctionalTestCase { this.parent = parent; } + public String getName() { + return name; + } } }