From 46fb816800e371c8fbf4cba272693dbdb54e05df Mon Sep 17 00:00:00 2001 From: Davide D'Alto Date: Sat, 11 Mar 2023 14:04:27 +0100 Subject: [PATCH 1/2] Minor refactoring in DefaultReactiveMergeEventListener Extract copyEntity method from the existing code --- .../DefaultReactiveMergeEventListener.java | 30 +++++++++---------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/event/impl/DefaultReactiveMergeEventListener.java b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/event/impl/DefaultReactiveMergeEventListener.java index 6598241a3..1995f47ef 100644 --- a/hibernate-reactive-core/src/main/java/org/hibernate/reactive/event/impl/DefaultReactiveMergeEventListener.java +++ b/hibernate-reactive-core/src/main/java/org/hibernate/reactive/event/impl/DefaultReactiveMergeEventListener.java @@ -233,31 +233,17 @@ protected CompletionStage entityIsPersistent(MergeEvent event, MergeContex } protected CompletionStage entityIsTransient(MergeEvent event, MergeContext copyCache) { - LOG.trace( "Merging transient instance" ); final Object entity = event.getEntity(); final EventSource session = event.getSession(); - final String entityName = event.getEntityName(); final EntityPersister persister = session.getEntityPersister( entityName, entity ); - final Object id = persister.hasIdentifierProperty() ? persister.getIdentifier( entity, session ) : null; - final Object copy; - final Object existingCopy = copyCache.get( entity ); - if ( existingCopy != null ) { - persister.setIdentifier( copyCache.get( entity ), id, session ); - copy = existingCopy; - } - else { - copy = session.instantiate( persister, id ); - - //before cascade! - copyCache.put( entity, copy, true ); - } + final Object copy = copyEntity( copyCache, entity, session, persister, id ); // cascade first, so that all unsaved objects get their // copy created before we actually copy @@ -286,6 +272,20 @@ protected CompletionStage entityIsTransient(MergeEvent event, MergeContext }); } + private static Object copyEntity(MergeContext copyCache, Object entity, EventSource session, EntityPersister persister, Object id) { + final Object existingCopy = copyCache.get( entity ); + if ( existingCopy != null ) { + persister.setIdentifier( copyCache.get( entity ), id, session ); + return existingCopy; + } + else { + final Object copy = session.instantiate( persister, id ); + //before cascade! + copyCache.put( entity, copy, true ); + return copy; + } + } + private static class CollectionVisitor extends WrapVisitor { CollectionVisitor(Object entity, Object id, EventSource session) { super( entity, id, session ); From a5f38fec455cdcd7b98a376e913beedb35d8a1c7 Mon Sep 17 00:00:00 2001 From: Davide D'Alto Date: Sat, 11 Mar 2023 14:01:00 +0100 Subject: [PATCH 2/2] Ignoring *UniqueKeyTest#testMergeReference and add with persist This is an unusual use case where the association is with an entity column instead of the identifier. It's a specific case and the current mapping, as it is, fails using regular Hibernate ORM anyway. I've added a test with the persist that seems to work as expected. --- .../reactive/EagerUniqueKeyTest.java | 43 +++++++++++++------ .../hibernate/reactive/LazyUniqueKeyTest.java | 30 +++++++++++++ 2 files changed, 59 insertions(+), 14 deletions(-) diff --git a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/EagerUniqueKeyTest.java b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/EagerUniqueKeyTest.java index 3e6416055..bb47f5c0e 100644 --- a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/EagerUniqueKeyTest.java +++ b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/EagerUniqueKeyTest.java @@ -11,7 +11,7 @@ import org.hibernate.annotations.Fetch; import org.hibernate.annotations.FetchMode; -import org.junit.After; +import org.junit.Ignore; import org.junit.Test; import jakarta.persistence.CascadeType; @@ -22,10 +22,14 @@ import jakarta.persistence.Id; import jakarta.persistence.JoinColumn; import jakarta.persistence.ManyToOne; + import java.io.Serializable; import java.util.Collection; import java.util.List; +/** + * @see LazyUniqueKeyTest + */ public class EagerUniqueKeyTest extends BaseReactiveTest { @Override @@ -33,13 +37,6 @@ protected Collection> annotatedEntities() { return List.of( Foo.class, Bar.class ); } - @After - public void cleanDb(TestContext context) { - test( context, getSessionFactory() - .withTransaction( s -> s.createQuery( "delete from Foo" ).executeUpdate() - .thenCompose( v -> s.createQuery( "delete from Bar" ).executeUpdate() ) ) ); - } - @Test public void testFindJoin(TestContext context) { Foo foo = new Foo( new Bar( "unique" ) ); @@ -65,20 +62,38 @@ public void testMergeDetached(TestContext context) { .withTransaction( session -> session.merge( new Foo( bar ) ) ) ) .thenCompose( result -> getSessionFactory() .withTransaction( session -> session.fetch( result.getBar() ) - .thenAccept( b -> context.assertEquals( "unique2", b.getKey() ) ) - ) ) ); + .thenAccept( b -> context.assertEquals( "unique2", b.getKey() ) ) + ) ) ); } + @Ignore // This also fails in ORM @Test public void testMergeReference(TestContext context) { Bar bar = new Bar( "unique3" ); test( context, getSessionFactory() .withTransaction( session -> session.persist( bar ) ) .thenCompose( i -> getSessionFactory() - .withTransaction( session -> session.merge( new Foo( session.getReference( Bar.class, bar.id ) )) ) ) + .withTransaction( session -> session + .merge( new Foo( session.getReference( Bar.class, bar.getId() ) ) ) ) ) .thenCompose( result -> getSessionFactory().withTransaction( session -> session.fetch( result.getBar() ) .thenAccept( b -> context.assertEquals( "unique3", b.getKey() ) ) - ) ) ); + ) ) + ); + } + + @Test + public void testPersistWithReference(TestContext context) { + Bar bar = new Bar( "uniquePersist" ); + test( context, getSessionFactory() + .withTransaction( session -> session.persist( bar ) ) + .thenCompose( i -> getSessionFactory() + .withTransaction( session -> { + Foo foo = new Foo( session.getReference( Bar.class, bar.getId() ) ); + return session.persist( foo ).thenApply( v -> foo ); + } ) ) + .thenCompose( result -> getSessionFactory().withTransaction( session -> session.fetch( result.getBar() ) ) ) + .thenAccept( b -> context.assertEquals( "uniquePersist", b.getKey() ) ) + ); } @Entity(name = "Foo") @@ -90,8 +105,8 @@ static class Foo { Foo() { } - @GeneratedValue @Id + @GeneratedValue long id; @ManyToOne(cascade = CascadeType.PERSIST, fetch = FetchType.EAGER) @Fetch(FetchMode.JOIN) @@ -124,8 +139,8 @@ static class Bar implements Serializable { Bar() { } - @GeneratedValue @Id + @GeneratedValue long id; @Column(name = "nat_key", unique = true) String key; diff --git a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/LazyUniqueKeyTest.java b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/LazyUniqueKeyTest.java index aa3b9f980..c2f11ebe1 100644 --- a/hibernate-reactive-core/src/test/java/org/hibernate/reactive/LazyUniqueKeyTest.java +++ b/hibernate-reactive-core/src/test/java/org/hibernate/reactive/LazyUniqueKeyTest.java @@ -10,6 +10,7 @@ import org.hibernate.annotations.Fetch; import org.hibernate.annotations.FetchMode; +import org.junit.Ignore; import org.junit.Test; import jakarta.persistence.CascadeType; @@ -24,6 +25,9 @@ import java.util.Collection; import java.util.List; +/** + * @see EagerUniqueKeyTest + */ public class LazyUniqueKeyTest extends BaseReactiveTest { @Override @@ -62,6 +66,7 @@ public void testMergeDetached(TestContext context) { ) ) ); } + @Ignore // This also fails in ORM @Test public void testMergeReference(TestContext context) { Bar bar = new Bar( "unique3" ); @@ -76,6 +81,23 @@ public void testMergeReference(TestContext context) { ) ) ); } + @Test + public void testPersistReference(TestContext context) { + Bar bar = new Bar( "unique3" ); + test( context, getSessionFactory() + .withTransaction( session -> session.persist( bar ) ) + .thenCompose( i -> getSessionFactory() + .withTransaction( session-> { + Foo foo = new Foo( session.getReference( Bar.class, bar.id ) ); + return session.persist( foo ).thenApply( v -> foo ); + } ) + ) + .thenCompose( result -> getSessionFactory() + .withTransaction( session-> session.fetch( result.bar ) + .thenAccept( b -> context.assertEquals( "unique3", b.getKey() ) ) + ) ) ); + } + @Entity(name = "Foo") static class Foo { Foo(Bar bar) { @@ -108,5 +130,13 @@ static class Bar implements Serializable { long id; @Column(name = "nat_key", unique = true) String key; + + public String getKey() { + return key; + } + + public void setKey(String key) { + this.key = key; + } } }