From 28d9c652931e9964a4d2d3bdfcc0a4847050e1c9 Mon Sep 17 00:00:00 2001 From: Marco Belladelli Date: Wed, 19 Jul 2023 14:52:16 +0200 Subject: [PATCH] HHH-16908 Mapping error when using unowned associations as identifiers --- .../model/internal/OneToOneSecondPass.java | 2 +- .../boot/model/internal/ToOneBinder.java | 25 +++++++++++++++++-- 2 files changed, 24 insertions(+), 3 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/OneToOneSecondPass.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/OneToOneSecondPass.java index 8f92b91a1f..e90383c396 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/OneToOneSecondPass.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/OneToOneSecondPass.java @@ -208,7 +208,7 @@ public class OneToOneSecondPass implements SecondPass { final KeyValue targetEntityIdentifier = targetEntity.getIdentifier(); boolean referenceToPrimaryKey = mappedBy == null || targetEntityIdentifier instanceof Component - && !( (Component) targetEntityIdentifier ).hasProperty( mappedBy ); + && ( (Component) targetEntityIdentifier ).hasProperty( mappedBy ); oneToOne.setReferenceToPrimaryKey( referenceToPrimaryKey ); final String propertyRef = oneToOne.getReferencedPropertyName(); diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/ToOneBinder.java b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/ToOneBinder.java index 757ddf9565..991831d986 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/internal/ToOneBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/internal/ToOneBinder.java @@ -90,11 +90,18 @@ public class ToOneBinder { if ( property.isAnnotationPresent( Column.class ) || property.isAnnotationPresent( Columns.class ) ) { throw new AnnotationException( - "Property '"+ getPath( propertyHolder, inferredData ) + "Property '" + getPath( propertyHolder, inferredData ) + "' is a '@ManyToOne' association and may not use '@Column' to specify column mappings (use '@JoinColumn' instead)" ); } + if ( joinColumns.hasMappedBy() && isIdentifier( propertyHolder, propertyBinder, isIdentifierMapper ) ) { + throw new AnnotationException( + "Property '" + getPath( propertyHolder, inferredData ) + + "' is the inverse side of a '@ManyToOne' association and cannot be used as identifier" + ); + } + final Cascade hibernateCascade = property.getAnnotation( Cascade.class ); final NotFound notFound = property.getAnnotation( NotFound.class ); final NotFoundAction notFoundAction = notFound == null ? null : notFound.action(); @@ -124,6 +131,13 @@ public class ToOneBinder { ); } + private static boolean isIdentifier( + PropertyHolder propertyHolder, + PropertyBinder propertyBinder, + boolean isIdentifierMapper) { + return propertyBinder.isId() || propertyHolder.isOrWithinEmbeddedId() || propertyHolder.isInIdClass() || isIdentifierMapper; + } + private static boolean isMandatory(boolean optional, XProperty property, NotFoundAction notFoundAction) { // @MapsId means the columns belong to the pk; // A @MapsId association (obviously) must be non-null when the entity is first persisted. @@ -421,12 +435,19 @@ public class ToOneBinder { if ( property.isAnnotationPresent( Column.class ) || property.isAnnotationPresent( Columns.class ) ) { throw new AnnotationException( - "Property '"+ getPath( propertyHolder, inferredData ) + "Property '" + getPath( propertyHolder, inferredData ) + "' is a '@OneToOne' association and may not use '@Column' to specify column mappings" + " (use '@PrimaryKeyJoinColumn' instead)" ); } + if ( joinColumns.hasMappedBy() && isIdentifier( propertyHolder, propertyBinder, isIdentifierMapper ) ) { + throw new AnnotationException( + "Property '" + getPath( propertyHolder, inferredData ) + + "' is the inverse side of a '@OneToOne' association and cannot be used as identifier" + ); + } + //FIXME support a proper PKJCs final boolean trueOneToOne = property.isAnnotationPresent( PrimaryKeyJoinColumn.class ) || property.isAnnotationPresent( PrimaryKeyJoinColumns.class );