From 8e8844d485086c41392747230ff60a81f2cf18ba Mon Sep 17 00:00:00 2001 From: Christian Beikov Date: Wed, 11 Nov 2020 19:18:59 +0100 Subject: [PATCH] HHH-14322 Fix HBM many-to-one property ref support --- .../AbstractPluralAttributeSourceImpl.java | 58 ++++++++++++++++--- .../hbm/PluralAttributeKeySourceImpl.java | 31 +++++++--- 2 files changed, 74 insertions(+), 15 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/source/internal/hbm/AbstractPluralAttributeSourceImpl.java b/hibernate-core/src/main/java/org/hibernate/boot/model/source/internal/hbm/AbstractPluralAttributeSourceImpl.java index 88905125d6..a3463d12e2 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/source/internal/hbm/AbstractPluralAttributeSourceImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/source/internal/hbm/AbstractPluralAttributeSourceImpl.java @@ -6,10 +6,14 @@ */ package org.hibernate.boot.model.source.internal.hbm; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; import java.util.Optional; import org.hibernate.AssertionFailure; import org.hibernate.boot.MappingException; +import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmColumnType; import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmFilterType; import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmManyToOneType; import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmRootEntityType; @@ -72,17 +76,58 @@ public abstract class AbstractPluralAttributeSourceImpl Optional jaxbHbmManyToOneTypeOptional = Optional.empty(); - if ( pluralAttributeJaxbMapping.isInverse() && pluralAttributeJaxbMapping.getOneToMany() != null ) { + // Our goal here is to find the inverse side of a one to many to figure out against what to join + if ( pluralAttributeJaxbMapping.isInverse() && pluralAttributeJaxbMapping.getOneToMany() != null && pluralAttributeJaxbMapping.getKey().getPropertyRef() == null ) { String childClass = pluralAttributeJaxbMapping.getOneToMany().getClazz(); if ( childClass != null ) { + // We match by columns as defined in the key + final List keyColumnNames; + if ( pluralAttributeJaxbMapping.getKey().getColumnAttribute() == null ) { + keyColumnNames = new ArrayList<>( pluralAttributeJaxbMapping.getKey().getColumn().size() ); + for ( JaxbHbmColumnType jaxbHbmColumnType : pluralAttributeJaxbMapping.getKey().getColumn() ) { + keyColumnNames.add( jaxbHbmColumnType.getName() ); + } + } + else { + keyColumnNames = new ArrayList<>( 1 ); + keyColumnNames.add( pluralAttributeJaxbMapping.getKey().getColumnAttribute() ); + } jaxbHbmManyToOneTypeOptional = mappingDocument.getDocumentRoot().getClazz() .stream() .filter( (JaxbHbmRootEntityType entityType) -> childClass.equals( entityType.getName() ) ) .flatMap( jaxbHbmRootEntityType -> jaxbHbmRootEntityType.getAttributes().stream() ) - .filter( - attribute -> attribute instanceof JaxbHbmManyToOneType && - ( (JaxbHbmManyToOneType) attribute ).getPropertyRef() != null ) + .filter( attribute -> { + if ( attribute instanceof JaxbHbmManyToOneType ) { + JaxbHbmManyToOneType manyToOneType = (JaxbHbmManyToOneType) attribute; + String manyToOneTypeClass = manyToOneType.getClazz(); + String containerClass = container.getAttributeRoleBase().getFullPath(); + // Consider many to ones that have no class defined or equal the owner class of the one to many + if ( manyToOneTypeClass == null || manyToOneTypeClass.equals( containerClass ) ) { + if ( manyToOneType.getColumnAttribute() == null ) { + List columns = manyToOneType.getColumnOrFormula(); + if ( columns.size() != keyColumnNames.size() ) { + return false; + } + for ( int i = 0; i < columns.size(); i++ ) { + Serializable column = columns.get( i ); + String keyColumn = keyColumnNames.get( i ); + if ( !( column instanceof JaxbHbmColumnType ) || !( (JaxbHbmColumnType) column ) + .getName() + .equals( keyColumn ) ) { + return false; + } + } + } + else { + return keyColumnNames.size() == 1 && keyColumnNames.get( 0 ) + .equals( manyToOneType.getColumnAttribute() ); + } + return true; + } + } + return false; + }) .map( JaxbHbmManyToOneType.class::cast ) .findFirst(); } @@ -91,13 +136,12 @@ public abstract class AbstractPluralAttributeSourceImpl this.keySource = jaxbHbmManyToOneTypeOptional .map( jaxbHbmManyToOneType -> new PluralAttributeKeySourceImpl( sourceMappingDocument(), + pluralAttributeJaxbMapping.getKey(), jaxbHbmManyToOneType, container ) ).orElseGet( () -> new PluralAttributeKeySourceImpl( sourceMappingDocument(), - pluralAttributeJaxbMapping.isInverse() ? - pluralAttributeJaxbMapping.getKey() : - pluralAttributeJaxbMapping.getKey(), + pluralAttributeJaxbMapping.getKey(), container ) ); diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/source/internal/hbm/PluralAttributeKeySourceImpl.java b/hibernate-core/src/main/java/org/hibernate/boot/model/source/internal/hbm/PluralAttributeKeySourceImpl.java index 30caba025b..3a105cbe85 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/source/internal/hbm/PluralAttributeKeySourceImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/source/internal/hbm/PluralAttributeKeySourceImpl.java @@ -74,16 +74,31 @@ public class PluralAttributeKeySourceImpl public PluralAttributeKeySourceImpl( MappingDocument mappingDocument, - final JaxbHbmManyToOneType jaxbKey, + final JaxbHbmKeyType jaxbKey, + final JaxbHbmManyToOneType jaxbManyToOne, final AttributeSourceContainer container) { super( mappingDocument ); - this.explicitFkName = StringHelper.nullIfEmpty( jaxbKey.getForeignKey() ); - this.referencedPropertyName = StringHelper.nullIfEmpty( jaxbKey.getPropertyRef() ); - this.cascadeDeletesAtFkLevel = jaxbKey.getOnDelete() != null - && "cascade".equals( jaxbKey.getOnDelete().value() ); - this.nullable = jaxbKey.isNotNull() == null || !jaxbKey.isNotNull(); - this.updateable = jaxbKey.isUpdate(); + this.explicitFkName = StringHelper.nullIfEmpty( jaxbManyToOne.getForeignKey() ); + this.referencedPropertyName = StringHelper.nullIfEmpty( jaxbManyToOne.getPropertyRef() ); + if ( jaxbKey.getOnDelete() == null ) { + this.cascadeDeletesAtFkLevel = jaxbManyToOne.getOnDelete() != null && "cascade".equals( jaxbManyToOne.getOnDelete().value() ); + } + else { + this.cascadeDeletesAtFkLevel = "cascade".equals( jaxbKey.getOnDelete().value() ); + } + if ( jaxbKey.isNotNull() == null ) { + this.nullable = jaxbManyToOne.isNotNull() == null || !jaxbManyToOne.isNotNull(); + } + else { + this.nullable = !jaxbKey.isNotNull(); + } + if ( jaxbKey.isUpdate() == null ) { + this.updateable = jaxbManyToOne.isUpdate(); + } + else { + this.updateable = jaxbKey.isUpdate(); + } this.valueSources = RelationalValueSourceHelper.buildValueSources( sourceMappingDocument(), @@ -106,7 +121,7 @@ public class PluralAttributeKeySourceImpl @Override public List getColumnOrFormulaElements() { - return jaxbKey.getColumnOrFormula(); + return jaxbKey.getColumn(); } }