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 ); 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..78e52a5a2 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 @@ -12,6 +12,7 @@ import org.hibernate.annotations.FetchMode; import org.junit.After; +import org.junit.Ignore; import org.junit.Test; import jakarta.persistence.CascadeType; @@ -22,6 +23,7 @@ import jakarta.persistence.Id; import jakarta.persistence.JoinColumn; import jakarta.persistence.ManyToOne; + import java.io.Serializable; import java.util.Collection; import java.util.List; @@ -65,20 +67,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 +110,8 @@ static class Foo { Foo() { } - @GeneratedValue @Id + @GeneratedValue long id; @ManyToOne(cascade = CascadeType.PERSIST, fetch = FetchType.EAGER) @Fetch(FetchMode.JOIN) @@ -124,8 +144,8 @@ static class Bar implements Serializable { Bar() { } - @GeneratedValue @Id + @GeneratedValue long id; @Column(name = "nat_key", unique = true) String key;