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 963dfa2419e7..8b40fe0dec78 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 @@ -83,6 +83,7 @@ import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.engine.spi.ValueInclusion; +import org.hibernate.id.ForeignGenerator; import org.hibernate.id.IdentifierGenerator; import org.hibernate.id.PostInsertIdentifierGenerator; import org.hibernate.id.PostInsertIdentityPersister; @@ -130,6 +131,7 @@ import org.hibernate.sql.Template; import org.hibernate.sql.Update; import org.hibernate.tuple.GenerationTiming; +import org.hibernate.tuple.IdentifierProperty; import org.hibernate.tuple.InDatabaseValueGenerationStrategy; import org.hibernate.tuple.InMemoryValueGenerationStrategy; import org.hibernate.tuple.NonIdentifierAttribute; @@ -4731,14 +4733,17 @@ public Boolean isTransient(Object entity, SharedSessionContractImplementor sessi .getUnsavedValue().isUnsaved( version ); if ( isUnsaved != null ) { if ( isUnsaved ) { - final Boolean unsaved = entityMetamodel.getIdentifierProperty() - .getUnsavedValue().isUnsaved( id ); - if ( unsaved != null && !unsaved ) { - throw new PropertyValueException( - "Detached entity with generated id '" + id + "' has an uninitialized version value '" + version + "'", - getEntityName(), - getVersionColumnName() - ); + final IdentifierProperty identifierProperty = entityMetamodel.getIdentifierProperty(); + final IdentifierGenerator identifierGenerator = identifierProperty.getIdentifierGenerator(); + if ( identifierGenerator != null && !( identifierGenerator instanceof ForeignGenerator ) ) { + final Boolean unsaved = identifierProperty.getUnsavedValue().isUnsaved( id ); + if ( unsaved != null && !unsaved ) { + throw new PropertyValueException( + "Detached entity with generated id '" + id + "' has an uninitialized version value '" + version + "'", + getEntityName(), + getVersionColumnName() + ); + } } } diff --git a/hibernate-core/src/test/java/org/hibernate/test/version/EntityWithNullVersionAndMapsIdTest.java b/hibernate-core/src/test/java/org/hibernate/test/version/EntityWithNullVersionAndMapsIdTest.java new file mode 100644 index 000000000000..d70215f7585f --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/version/EntityWithNullVersionAndMapsIdTest.java @@ -0,0 +1,91 @@ +package org.hibernate.test.version; + +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.MapsId; +import javax.persistence.OneToOne; +import javax.persistence.Version; + +import org.hibernate.testing.TestForIssue; +import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; +import org.junit.Test; + +@TestForIssue(jiraKey = "HHH-17380") +public class EntityWithNullVersionAndMapsIdTest extends BaseCoreFunctionalTestCase { + + @Override + protected Class[] getAnnotatedClasses() { + return new Class[] { + Person.class, + Address.class + }; + } + + @Test + public void testPersistEntityWithMapsId() { + Address address = new Address( "Alex" ); + 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; + } + } +}