From fcfe7aafba35b7d4bb00bf19800b1d548c55e2c9 Mon Sep 17 00:00:00 2001 From: Andrea Boriero Date: Fri, 3 Nov 2023 09:42:11 +0100 Subject: [PATCH 1/2] HHH-17380 Add test for issue --- .../EntityWithNullVersionAndMapsIdTest.java | 104 ++++++++++++++++++ 1 file changed, 104 insertions(+) create mode 100644 hibernate-core/src/test/java/org/hibernate/orm/test/version/EntityWithNullVersionAndMapsIdTest.java diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/version/EntityWithNullVersionAndMapsIdTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/version/EntityWithNullVersionAndMapsIdTest.java new file mode 100644 index 000000000000..be0cf12e066b --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/version/EntityWithNullVersionAndMapsIdTest.java @@ -0,0 +1,104 @@ +package org.hibernate.orm.test.version; + +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.JiraKey; +import org.hibernate.testing.orm.junit.SessionFactory; +import org.hibernate.testing.orm.junit.SessionFactoryScope; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.Test; + +import jakarta.persistence.Entity; +import jakarta.persistence.Id; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.MapsId; +import jakarta.persistence.OneToOne; +import jakarta.persistence.Version; + +@DomainModel( + annotatedClasses = { + EntityWithNullVersionAndMapsIdTest.Person.class, + EntityWithNullVersionAndMapsIdTest.Address.class, + } +) +@SessionFactory +@JiraKey("HHH-17380") +public class EntityWithNullVersionAndMapsIdTest { + + @AfterEach + public void tearDown(SessionFactoryScope scope) { + scope.inTransaction( + session -> { + session.createMutationQuery( "delete from Person" ); + session.createMutationQuery( "delete from Address" ); + + } + ); + } + + @Test + public void testPersistEntityWithMapsId(SessionFactoryScope scope) { + Address address = new Address( "Alex" ); + scope.inTransaction( + session -> { + session.persist( address ); + Person person = new Person( address ); + session.persist( person ); + } + ); + } + + @Entity(name = "Person") + public static class Person { + + @Id + private String name; + + @Version + private Long version; + + private String description; + + @MapsId + @OneToOne + @JoinColumn(name = "name") + private Address address; + + public Person() { + } + + public Person(Address address) { + this.name = address.getName(); + this.address = address; + } + + public String getName() { + return name; + } + + public Address getAddress() { + return address; + } + } + + @Entity(name = "Address") + public static class Address { + @Id + private String name; + + @Version + private Long version; + + private String description; + + public Address() { + } + + public Address(String name) { + this.name = name; + } + + public String getName() { + return name; + } + } +} From 9e79e4121e1a1fcf9b29bc43cb390ca552d402ed Mon Sep 17 00:00:00 2001 From: Andrea Boriero Date: Mon, 6 Nov 2023 09:21:09 +0100 Subject: [PATCH 2/2] HHH-17380 Persisting an entity with a non generated id and @MapsId throws PropertyValueException --- .../entity/AbstractEntityPersister.java | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java index 8633a1d7b8f8..8f626ca77593 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java @@ -107,6 +107,7 @@ import org.hibernate.graph.spi.RootGraphImplementor; import org.hibernate.id.Assigned; import org.hibernate.id.BulkInsertionCapableIdentifierGenerator; +import org.hibernate.id.ForeignGenerator; import org.hibernate.id.IdentifierGenerator; import org.hibernate.id.OptimizableGenerator; import org.hibernate.id.PostInsertIdentityPersister; @@ -4124,13 +4125,16 @@ public Boolean isTransient(Object entity, SharedSessionContractImplementor sessi return false; } } - final Boolean unsaved = identifierMapping.getUnsavedStrategy().isUnsaved( id ); - if ( unsaved != null && !unsaved ) { - throw new PropertyValueException( - "Detached entity with generated id '" + id + "' has an uninitialized version value '" + version + "'", - getEntityName(), - getVersionColumnName() - ); + final Generator identifierGenerator = getGenerator(); + if ( identifierGenerator != null && !( identifierGenerator instanceof ForeignGenerator ) ) { + final Boolean unsaved = identifierMapping.getUnsavedStrategy().isUnsaved( id ); + if ( unsaved != null && !unsaved ) { + throw new PropertyValueException( + "Detached entity with generated id '" + id + "' has an uninitialized version value '" + version + "'", + getEntityName(), + getVersionColumnName() + ); + } } } return isUnsaved;