From 1634d56c369e7f2c7b7df1a4f80ce3d79b8a6ec1 Mon Sep 17 00:00:00 2001 From: Gail Badner Date: Fri, 1 Feb 2013 13:00:02 -0800 Subject: [PATCH] HHH-7983 : RelationalValueBindingContainer --- .../hibernate/metamodel/internal/Binder.java | 278 ++++-------------- .../metamodel/internal/ForeignKeyHelper.java | 172 +++++++++++ .../metamodel/internal/MetadataImpl.java | 6 +- ...mpositePluralAttributeIndexSourceImpl.java | 2 +- ...uentialPluralAttributeIndexSourceImpl.java | 2 +- ...actCompositeAttributeBindingContainer.java | 6 + ...AbstractPluralAttributeElementBinding.java | 22 ++ ...ctSingularAssociationAttributeBinding.java | 10 +- .../AbstractSingularAttributeBinding.java | 7 +- .../spi/binding/BackRefAttributeBinding.java | 16 +- .../spi/binding/BasicAttributeBinding.java | 17 +- .../BasicPluralAttributeElementBinding.java | 20 +- .../binding/CompositeAttributeBinding.java | 13 +- ...ompositePluralAttributeElementBinding.java | 14 +- .../CompositePluralAttributeIndexBinding.java | 5 +- ...anyToAnyPluralAttributeElementBinding.java | 9 +- ...nyToManyPluralAttributeElementBinding.java | 16 +- ...neToManyPluralAttributeElementBinding.java | 16 +- .../PluralAttributeElementBinding.java | 6 + .../binding/PluralAttributeKeyBinding.java | 81 +++-- .../RelationalValueBindingContainer.java | 41 +-- .../AbstractCollectionPersister.java | 5 +- .../collection/OneToManyPersister.java | 3 +- .../AbstractBasicCollectionBindingTests.java | 29 +- ...ctUnidirectionalOneToManyBindingTests.java | 26 +- ...UnidirCollectionWithMultipleOwnerTest.java | 1 - .../collection/map/PersistentMapTest.java | 1 - 27 files changed, 390 insertions(+), 434 deletions(-) create mode 100644 hibernate-core/src/main/java/org/hibernate/metamodel/internal/ForeignKeyHelper.java diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/Binder.java b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/Binder.java index 425d887e07..990afb3477 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/Binder.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/Binder.java @@ -203,12 +203,14 @@ public class Binder { private final LinkedList inheritanceTypes = new LinkedList(); private final LinkedList entityModes = new LinkedList(); private final HibernateTypeHelper typeHelper; // todo: refactor helper and remove redundant methods in this class + private final ForeignKeyHelper foreignKeyHelper; public Binder(final MetadataImplementor metadata, final IdentifierGeneratorFactory identifierGeneratorFactory) { this.metadata = metadata; this.identifierGeneratorFactory = identifierGeneratorFactory; this.typeHelper = new HibernateTypeHelper( this, metadata ); + this.foreignKeyHelper = new ForeignKeyHelper( this ); this.nameNormalizer = metadata.getObjectNameNormalizer(); } @@ -678,9 +680,9 @@ public class Binder { ); // TODO: make the foreign key column the primary key??? - final ForeignKey foreignKey = bindForeignKey( + final ForeignKey foreignKey = locateOrCreateForeignKey( quotedIdentifier( secondaryTableSource.getExplicitForeignKeyName() ), - extractColumnsFromRelationalValueBindings( joinRelationalValueBindings ), + joinRelationalValueBindings, determineForeignKeyTargetColumns( entityBinding, secondaryTableSource ) ); SecondaryTable secondaryTable = new SecondaryTable( table, foreignKey ); @@ -692,6 +694,34 @@ public class Binder { } } + public ForeignKey locateOrCreateForeignKey( + final String foreignKeyName, + final List sourceRelationalValueBindings, + final List targetColumns) { + return foreignKeyHelper.locateOrCreateForeignKey( + foreignKeyName, + extractColumnsFromRelationalValueBindings( sourceRelationalValueBindings ), + targetColumns + ); + } + + // TODO: try to get rid of this... + private static List extractColumnsFromRelationalValueBindings( + final List valueBindings) { + List columns = new ArrayList( valueBindings.size() ); + for ( RelationalValueBinding relationalValueBinding : valueBindings ) { + final Value value = relationalValueBinding.getValue(); + // todo : currently formulas are not supported here... :( + if ( !Column.class.isInstance( value ) ) { + throw new NotYetImplementedException( + "Derived values are not supported when creating a foreign key that targets columns." + ); + } + columns.add( (Column) value ); + } + return columns; + } + //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ identifier binding relates methods private void bindIdentifier( final EntityBinding rootEntityBinding, @@ -1159,10 +1189,10 @@ public class Binder { attributeBinding.getHibernateTypeDescriptor().getResolvedTypeMapping(), attributeBinding.getRelationalValueBindings() ); - if ( !hasDerivedValue( attributeBinding.getRelationalValueBindings() ) ) { - bindForeignKey( + if ( !attributeBinding.hasDerivedValue() ) { + locateOrCreateForeignKey( quotedIdentifier( attributeSource.getExplicitForeignKeyName() ), - extractColumnsFromRelationalValueBindings( attributeBinding.getRelationalValueBindings() ), + attributeBinding.getRelationalValueBindings(), determineForeignKeyTargetColumns( attributeBinding.getReferencedEntityBinding(), attributeSource @@ -1271,19 +1301,18 @@ public class Binder { toOneAttributeBindingContext ); if ( attributeSource.getForeignKeyDirection() == ForeignKeyDirection.FROM_PARENT ) { - List foreignKeyColumns = extractColumnsFromRelationalValueBindings( + List foreignKeyRelationalValueBindings = attributeBinding .getContainer() .seekEntityBinding() .getHierarchyDetails() .getEntityIdentifier() .getAttributeBinding() - .getRelationalValueBindings() - ); + .getRelationalValueBindings(); - bindForeignKey( + locateOrCreateForeignKey( quotedIdentifier( attributeSource.getExplicitForeignKeyName() ), - foreignKeyColumns, + foreignKeyRelationalValueBindings, determineForeignKeyTargetColumns( attributeBinding.getReferencedEntityBinding(), attributeSource @@ -1865,10 +1894,10 @@ public class Binder { ); if ( !elementBinding.getPluralAttributeBinding().getPluralAttributeKeyBinding().isInverse() && - !hasDerivedValue( elementBinding.getRelationalValueBindings() ) ) { - bindForeignKey( + !elementBinding.hasDerivedValue() ) { + locateOrCreateForeignKey( quotedIdentifier( elementSource.getExplicitForeignKeyName() ), - extractColumnsFromRelationalValueBindings( elementBinding.getRelationalValueBindings() ), + elementBinding.getRelationalValueBindings(), targetColumns ); } @@ -1927,7 +1956,6 @@ public class Binder { referencedAttributeBinding.getReferencedAttributeBinding() .getHibernateTypeDescriptor() ); - boolean isUpdatable = false; List sourceColumnBindings = referencedAttributeBinding.getRelationalValueBindings(); List sourceColumns = new ArrayList(); for ( RelationalValueBinding relationalValueBinding : sourceColumnBindings ) { @@ -1935,14 +1963,13 @@ public class Binder { if ( Column.class.isInstance( v ) ) { sourceColumns.add( Column.class.cast( v ) ); } - isUpdatable = isUpdatable || relationalValueBinding.isIncludeInUpdate(); } for ( ForeignKey fk : referencedEntityBinding.getPrimaryTable().getForeignKeys() ) { if ( fk.getSourceColumns().equals( sourceColumns ) ) { - keyBinding.setForeignKey( fk ); + keyBinding.setCascadeDeleteEnabled( fk.getDeleteRule() == ForeignKey.ReferentialAction.CASCADE ); } } - keyBinding.setUpdatable( isUpdatable ); + keyBinding.setRelationalValueBindings( sourceColumnBindings ); } else { bindCollectionTableForeignKey( attributeBinding, attributeSource.getKeySource(), collectionTable ); @@ -2300,7 +2327,7 @@ public class Binder { ) ); } - if ( hasAnyNonNullableColumns( elementBinding.getRelationalValueBindings() ) ) { + if ( elementBinding.hasNonNullableValue() ) { bindSetCollectionTablePrimaryKey( attributeBinding ); } else { @@ -2315,9 +2342,10 @@ public class Binder { final PrimaryKey primaryKey = attributeBinding.getPluralAttributeKeyBinding() .getCollectionTable() .getPrimaryKey(); - final ForeignKey foreignKey = attributeBinding.getPluralAttributeKeyBinding().getForeignKey(); - for ( final Column foreignKeyColumn : foreignKey.getSourceColumns() ) { - primaryKey.addColumn( foreignKeyColumn ); + final List keyValueBindings = + attributeBinding.getPluralAttributeKeyBinding().getRelationalValueBindings(); + for ( final RelationalValueBinding keyRelationalValueBinding : keyValueBindings ) { + primaryKey.addColumn( (Column) keyRelationalValueBinding.getValue() ); } for ( final RelationalValueBinding elementValueBinding : elementBinding.getRelationalValueBindings() ) { if ( !elementValueBinding.isDerived() && !elementValueBinding.isNullable() ) { @@ -2357,7 +2385,7 @@ public class Binder { ); } - List sourceColumnBindings = + List sourceRelationalBindings = bindValues( attributeBindingContainer, keySource, @@ -2367,33 +2395,14 @@ public class Binder { attributeBinding.getPluralAttributeElementBinding() .getNature() != PluralAttributeElementBinding.Nature.ONE_TO_MANY ); - // Determine if the foreign key (source) column is updatable and also extract the columns out - // of the RelationalValueBindings. - boolean isInsertable = false; - boolean isUpdatable = false; - List sourceColumns = new ArrayList( sourceColumnBindings.size() ); - for ( RelationalValueBinding relationalValueBinding : sourceColumnBindings ) { - final Value value = relationalValueBinding.getValue(); - // todo : currently formulas are not supported here... :( - if ( !Column.class.isInstance( value ) ) { - throw new NotYetImplementedException( - "Derived values are not supported when creating a foreign key that targets columns." - ); - } - isInsertable = isInsertable || relationalValueBinding.isIncludeInInsert(); - isUpdatable = isUpdatable || relationalValueBinding.isIncludeInUpdate(); - sourceColumns.add( (Column) value ); - } - keyBinding.setInsertable( isInsertable ); - keyBinding.setUpdatable( isUpdatable ); - - ForeignKey foreignKey = bindForeignKey( + keyBinding.setRelationalValueBindings( sourceRelationalBindings ); + ForeignKey foreignKey = locateOrCreateForeignKey( quotedIdentifier( keySource.getExplicitForeignKeyName() ), - sourceColumns, + sourceRelationalBindings, targetColumns ); foreignKey.setDeleteRule( keySource.getOnDeleteAction() ); - keyBinding.setForeignKey( foreignKey ); + keyBinding.setCascadeDeleteEnabled( keySource.getOnDeleteAction() == ForeignKey.ReferentialAction.CASCADE ); final HibernateTypeDescriptor pluralAttributeKeyTypeDescriptor = keyBinding.getHibernateTypeDescriptor(); pluralAttributeKeyTypeDescriptor.copyFrom( @@ -2402,15 +2411,15 @@ public class Binder { ); final Type resolvedKeyType = pluralAttributeKeyTypeDescriptor.getResolvedTypeMapping(); - Iterator fkColumnIterator = keyBinding.getForeignKey().getSourceColumns().iterator(); + Iterator fkColumnIterator = keyBinding.getRelationalValueBindings().iterator(); if ( resolvedKeyType.isComponentType() ) { ComponentType componentType = (ComponentType) resolvedKeyType; for ( Type subType : componentType.getSubtypes() ) { - typeHelper.bindJdbcDataType( subType, fkColumnIterator.next() ); + typeHelper.bindJdbcDataType( subType, fkColumnIterator.next().getValue() ); } } else { - typeHelper.bindJdbcDataType( resolvedKeyType, fkColumnIterator.next() ); + typeHelper.bindJdbcDataType( resolvedKeyType, fkColumnIterator.next().getValue() ); } } @@ -2522,7 +2531,7 @@ public class Binder { subclassEntitySource ); - ForeignKey foreignKey = bindForeignKey( + ForeignKey foreignKey = foreignKeyHelper.locateOrCreateForeignKey( quotedIdentifier( subclassEntitySource.getExplicitForeignKeyName() ), sourceColumns, targetColumns @@ -2538,64 +2547,6 @@ public class Binder { } - private ForeignKey bindForeignKey( - final String foreignKeyName, - final List sourceColumns, - final List targetColumns) { - ForeignKey foreignKey = null; - if ( foreignKeyName != null ) { - foreignKey = locateAndBindForeignKeyByName( foreignKeyName, sourceColumns, targetColumns ); - } - if ( foreignKey == null ) { - foreignKey = locateForeignKeyByColumnMapping( sourceColumns, targetColumns ); - if ( foreignKey != null && foreignKeyName != null ) { - if ( foreignKey.getName() == null ) { - // the foreign key name has not be initialized; set it to foreignKeyName - foreignKey.setName( foreignKeyName ); - } - else { - // the foreign key name has already been initialized so cannot rename it - // TODO: should this just be INFO? - log.warn( - String.format( - "A foreign key mapped as %s will not be created because foreign key %s already exists with the same column mapping.", - foreignKeyName, - foreignKey.getName() - ) - ); - } - } - } - if ( foreignKey == null ) { - // no foreign key found; create one - final TableSpecification sourceTable = sourceColumns.get( 0 ).getTable(); - final TableSpecification targetTable = targetColumns.get( 0 ).getTable(); - foreignKey = sourceTable.createForeignKey( targetTable, foreignKeyName ); - bindForeignKeyColumns( foreignKey, sourceColumns, targetColumns ); - } - return foreignKey; - } - - private void bindForeignKeyColumns( - final ForeignKey foreignKey, - final List sourceColumns, - final List targetColumns) { - if ( sourceColumns.size() != targetColumns.size() ) { - throw bindingContext().makeMappingException( - String.format( - "Non-matching number columns in foreign key source columns [%s : %s] and target columns [%s : %s]", - sourceColumns.get( 0 ).getTable().getLogicalName().getText(), - sourceColumns.size(), - targetColumns.get( 0 ).getTable().getLogicalName().getText(), - targetColumns.size() - ) - ); - } - for ( int i = 0; i < sourceColumns.size(); i++ ) { - foreignKey.addColumnMapping( sourceColumns.get( i ), targetColumns.get( i ) ); - } - } - private TableSpecification locateDefaultTableSpecificationForAttribute( final AttributeBindingContainer attributeBindingContainer, final SingularAttributeSource attributeSource) { @@ -2771,7 +2722,7 @@ public class Binder { new ColumnNamingStrategyHelper( defaultName, isDefaultAttributeName ) ); final Column column = table.locateOrCreateColumn( resolvedColumnName ); - resolveColumnNullabl( columnSource, forceNotNull, isNullableByDefault, column ); + resolveColumnNullable( columnSource, forceNotNull, isNullableByDefault, column ); column.setDefaultValue( columnSource.getDefaultValue() ); column.setSqlType( columnSource.getSqlType() ); column.setSize( columnSource.getSize() ); @@ -2784,7 +2735,7 @@ public class Binder { return column; } - private void resolveColumnNullabl( + private void resolveColumnNullable( final ColumnSource columnSource, final boolean forceNotNull, final boolean isNullableByDefault, @@ -2958,50 +2909,6 @@ public class Binder { } } - - private ForeignKey locateAndBindForeignKeyByName( - final String foreignKeyName, - final List sourceColumns, - final List targetColumns) { - if ( foreignKeyName == null ) { - throw new AssertionFailure( "foreignKeyName must be non-null." ); - } - final TableSpecification sourceTable = sourceColumns.get( 0 ).getTable(); - final TableSpecification targetTable = targetColumns.get( 0 ).getTable(); - ForeignKey foreignKey = sourceTable.locateForeignKey( foreignKeyName ); - if ( foreignKey != null ) { - if ( !targetTable.equals( foreignKey.getTargetTable() ) ) { - throw bindingContext().makeMappingException( - String.format( - "Unexpected target table defined for foreign key \"%s\"; expected \"%s\"; found \"%s\"", - foreignKeyName, - targetTable.getLogicalName(), - foreignKey.getTargetTable().getLogicalName() - ) - ); - } - // check if source and target columns have been bound already - if ( foreignKey.getColumnSpan() == 0 ) { - // foreign key was found, but no columns bound to it yet - bindForeignKeyColumns( foreignKey, sourceColumns, targetColumns ); - } - else { - // The located foreign key already has columns bound; - // Make sure they are the same columns. - if ( !foreignKey.getSourceColumns().equals( sourceColumns ) || - foreignKey.getTargetColumns().equals( targetColumns ) ) { - throw bindingContext().makeMappingException( - String.format( - "Attempt to bind exisitng foreign key \"%s\" with different columns.", - foreignKeyName - ) - ); - } - } - } - return foreignKey; - } - //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ simple instance helper methods private void mapSourcesByName(final EntitySource rootEntitySource) { String entityName = rootEntitySource.getEntityName(); @@ -3086,10 +2993,11 @@ public class Binder { final PrimaryKey primaryKey = attributeBinding.getPluralAttributeKeyBinding() .getCollectionTable() .getPrimaryKey(); - final ForeignKey foreignKey = attributeBinding.getPluralAttributeKeyBinding().getForeignKey(); + final List keyRelationalValueBindings = + attributeBinding.getPluralAttributeKeyBinding().getRelationalValueBindings(); final PluralAttributeIndexBinding indexBinding = attributeBinding.getPluralAttributeIndexBinding(); - for ( final Column foreignKeyColumn : foreignKey.getSourceColumns() ) { - primaryKey.addColumn( foreignKeyColumn ); + for ( final RelationalValueBinding keyRelationalValueBinding : keyRelationalValueBindings ) { + primaryKey.addColumn( (Column) keyRelationalValueBinding.getValue() ); } for ( RelationalValueBinding relationalValueBinding : indexBinding.getRelationalValueBindings() ) { if ( !relationalValueBinding.isDerived() ) { @@ -3122,16 +3030,6 @@ public class Binder { return fullPath.substring( attributeBinding.getContainer().seekEntityBinding().getEntityName().length() + 1 ); } - private static boolean hasDerivedValue( - final List relationalValueBindings) { - for ( RelationalValueBinding relationalValueBinding : relationalValueBindings ) { - if ( DerivedValue.class.isInstance( relationalValueBinding.getValue() ) ) { - return true; - } - } - return false; - } - // TODO: should this be moved to CascadeStyles as a static method? // TODO: sources already factor in default cascade; should that be done here instead? private static CascadeStyle determineCascadeStyle( @@ -3203,60 +3101,12 @@ public class Binder { .createSingularAttribute( attributeSource.getName() ); } - private static ForeignKey locateForeignKeyByColumnMapping( - final List sourceColumns, - final List targetColumns) { - final TableSpecification sourceTable = sourceColumns.get( 0 ).getTable(); - final TableSpecification targetTable = targetColumns.get( 0 ).getTable(); - // check for an existing foreign key with the same source/target columns - ForeignKey foreignKey = null; - Iterable possibleForeignKeys = sourceTable.locateForeignKey( targetTable ); - if ( possibleForeignKeys != null ) { - for ( ForeignKey possibleFK : possibleForeignKeys ) { - if ( possibleFK.getSourceColumns().equals( sourceColumns ) && - possibleFK.getTargetColumns().equals( targetColumns ) ) { - // this is the foreign key - foreignKey = possibleFK; - break; - } - } - } - return foreignKey; - } - private static String attributeSourcesByNameKey( final String entityName, final String attributeName) { return entityName + "." + attributeName; } - // TODO: try to get rid of this... - private static List extractColumnsFromRelationalValueBindings( - final List valueBindings) { - List columns = new ArrayList( valueBindings.size() ); - for ( RelationalValueBinding relationalValueBinding : valueBindings ) { - final Value value = relationalValueBinding.getValue(); - // todo : currently formulas are not supported here... :( - if ( !Column.class.isInstance( value ) ) { - throw new NotYetImplementedException( - "Derived values are not supported when creating a foreign key that targets columns." - ); - } - columns.add( (Column) value ); - } - return columns; - } - - private static boolean hasAnyNonNullableColumns( - final List relationalValueBindings) { - for ( RelationalValueBinding relationalValueBinding : relationalValueBindings ) { - if ( Column.class.isInstance( relationalValueBinding.getValue() ) && !relationalValueBinding.isNullable() ) { - return true; - } - } - return false; - } - static String createAttributePath( final AttributeBinding attributeBinding) { return attributeBinding.getContainer().getPathBase() + '.' + attributeBinding.getAttribute().getName(); diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/ForeignKeyHelper.java b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/ForeignKeyHelper.java new file mode 100644 index 0000000000..b6e23bcbf6 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/ForeignKeyHelper.java @@ -0,0 +1,172 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2013, Red Hat Inc. or third-party contributors as + * indicated by the @author tags or express copyright attribution + * statements applied by the authors. All third-party contributions are + * distributed under license by Red Hat Inc. + * + * This copyrighted material is made available to anyone wishing to use, modify, + * copy, or redistribute it subject to the terms and conditions of the GNU + * Lesser General Public License, as published by the Free Software Foundation. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY + * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License + * for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this distribution; if not, write to: + * Free Software Foundation, Inc. + * 51 Franklin Street, Fifth Floor + * Boston, MA 02110-1301 USA + */ +package org.hibernate.metamodel.internal; + +import java.util.List; + +import org.jboss.logging.Logger; + +import org.hibernate.AssertionFailure; +import org.hibernate.internal.CoreMessageLogger; +import org.hibernate.metamodel.spi.relational.Column; +import org.hibernate.metamodel.spi.relational.ForeignKey; +import org.hibernate.metamodel.spi.relational.TableSpecification; + +/** + * @author Gail Badner + */ +public class ForeignKeyHelper { + private static final CoreMessageLogger log = Logger.getMessageLogger( + CoreMessageLogger.class, + ForeignKeyHelper.class.getName() + ); + + private final Binder binder; + + public ForeignKeyHelper(Binder binder) { + this.binder = binder; + } + + public ForeignKey locateOrCreateForeignKey( + final String foreignKeyName, + final List sourceColumns, + final List targetColumns) { + ForeignKey foreignKey = null; + if ( foreignKeyName != null ) { + foreignKey = locateAndBindForeignKeyByName( foreignKeyName, sourceColumns, targetColumns ); + } + if ( foreignKey == null ) { + foreignKey = locateForeignKeyByColumnMapping( sourceColumns, targetColumns ); + if ( foreignKey != null && foreignKeyName != null ) { + if ( foreignKey.getName() == null ) { + // the foreign key name has not be initialized; set it to foreignKeyName + foreignKey.setName( foreignKeyName ); + } + else { + // the foreign key name has already been initialized so cannot rename it + // TODO: should this just be INFO? + log.warn( + String.format( + "A foreign key mapped as %s will not be created because foreign key %s already exists with the same column mapping.", + foreignKeyName, + foreignKey.getName() + ) + ); + } + } + } + if ( foreignKey == null ) { + // no foreign key found; create one + final TableSpecification sourceTable = sourceColumns.get( 0 ).getTable(); + final TableSpecification targetTable = targetColumns.get( 0 ).getTable(); + foreignKey = sourceTable.createForeignKey( targetTable, foreignKeyName ); + bindForeignKeyColumns( foreignKey, sourceColumns, targetColumns ); + } + return foreignKey; + } + + private static ForeignKey locateForeignKeyByColumnMapping( + final List sourceColumns, + final List targetColumns) { + final TableSpecification sourceTable = sourceColumns.get( 0 ).getTable(); + final TableSpecification targetTable = targetColumns.get( 0 ).getTable(); + // check for an existing foreign key with the same source/target columns + ForeignKey foreignKey = null; + Iterable possibleForeignKeys = sourceTable.locateForeignKey( targetTable ); + if ( possibleForeignKeys != null ) { + for ( ForeignKey possibleFK : possibleForeignKeys ) { + if ( possibleFK.getSourceColumns().equals( sourceColumns ) && + possibleFK.getTargetColumns().equals( targetColumns ) ) { + // this is the foreign key + foreignKey = possibleFK; + break; + } + } + } + return foreignKey; + } + + private void bindForeignKeyColumns( + final ForeignKey foreignKey, + final List sourceColumns, + final List targetColumns) { + if ( sourceColumns.size() != targetColumns.size() ) { + throw binder.bindingContext().makeMappingException( + String.format( + "Non-matching number columns in foreign key source columns [%s : %s] and target columns [%s : %s]", + sourceColumns.get( 0 ).getTable().getLogicalName().getText(), + sourceColumns.size(), + targetColumns.get( 0 ).getTable().getLogicalName().getText(), + targetColumns.size() + ) + ); + } + for ( int i = 0; i < sourceColumns.size(); i++ ) { + foreignKey.addColumnMapping( sourceColumns.get( i ), targetColumns.get( i ) ); + } + } + + private ForeignKey locateAndBindForeignKeyByName( + final String foreignKeyName, + final List sourceColumns, + final List targetColumns) { + if ( foreignKeyName == null ) { + throw new AssertionFailure( "foreignKeyName must be non-null." ); + } + final TableSpecification sourceTable = sourceColumns.get( 0 ).getTable(); + final TableSpecification targetTable = targetColumns.get( 0 ).getTable(); + ForeignKey foreignKey = sourceTable.locateForeignKey( foreignKeyName ); + if ( foreignKey != null ) { + if ( !targetTable.equals( foreignKey.getTargetTable() ) ) { + throw binder.bindingContext().makeMappingException( + String.format( + "Unexpected target table defined for foreign key \"%s\"; expected \"%s\"; found \"%s\"", + foreignKeyName, + targetTable.getLogicalName(), + foreignKey.getTargetTable().getLogicalName() + ) + ); + } + // check if source and target columns have been bound already + if ( foreignKey.getColumnSpan() == 0 ) { + // foreign key was found, but no columns bound to it yet + bindForeignKeyColumns( foreignKey, sourceColumns, targetColumns ); + } + else { + // The located foreign key already has columns bound; + // Make sure they are the same columns. + if ( !foreignKey.getSourceColumns().equals( sourceColumns ) || + foreignKey.getTargetColumns().equals( targetColumns ) ) { + throw binder.bindingContext().makeMappingException( + String.format( + "Attempt to bind exisitng foreign key \"%s\" with different columns.", + foreignKeyName + ) + ); + } + } + } + return foreignKey; + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/MetadataImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/MetadataImpl.java index b81681a271..3a8a851932 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/MetadataImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/MetadataImpl.java @@ -408,7 +408,7 @@ public class MetadataImpl implements MetadataImplementor, Serializable { entityBindingMap.get( pluralAttributeBinding.getPluralAttributeElementBinding().getHibernateTypeDescriptor(). getResolvedTypeMapping().getName() ); - List columns = keyBinding.getForeignKey().getColumns(); + List keyValueBindings = keyBinding.getRelationalValueBindings(); boolean bidirectional = false; for ( AttributeBinding attributeBinding : referencedEntityBinding.attributeBindings() ) { if ( !(attributeBinding instanceof ManyToOneAttributeBinding) ) { @@ -423,12 +423,12 @@ public class MetadataImpl implements MetadataImplementor, Serializable { // Check if the many-to-one attribute binding's columns match the one-to-many attribute binding's FK columns // (meaning this is a bidirectional association, and no back reference should be created) List valueBindings = manyToOneAttributeBinding.getRelationalValueBindings(); - if ( columns.size() != valueBindings.size() ) { + if ( keyValueBindings.size() != valueBindings.size() ) { continue; } bidirectional = true; for ( int ndx = valueBindings.size(); --ndx >= 0; ) { - if ( columns.get(ndx) != valueBindings.get( ndx ).getValue() ) { + if ( keyValueBindings.get(ndx) != valueBindings.get( ndx ) ) { bidirectional = false; break; } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/hbm/CompositePluralAttributeIndexSourceImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/hbm/CompositePluralAttributeIndexSourceImpl.java index 9da7e87998..0c39bfe5e6 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/hbm/CompositePluralAttributeIndexSourceImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/hbm/CompositePluralAttributeIndexSourceImpl.java @@ -153,7 +153,7 @@ public class CompositePluralAttributeIndexSourceImpl @Override public boolean areValuesIncludedInUpdateByDefault() { - return true; + return false; } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/hbm/SequentialPluralAttributeIndexSourceImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/hbm/SequentialPluralAttributeIndexSourceImpl.java index 8dc0c2776c..7dd376fa80 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/hbm/SequentialPluralAttributeIndexSourceImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/hbm/SequentialPluralAttributeIndexSourceImpl.java @@ -131,7 +131,7 @@ public class SequentialPluralAttributeIndexSourceImpl extends AbstractHbmSourceN @Override public boolean areValuesIncludedInUpdateByDefault() { - return true; + return false; } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/AbstractCompositeAttributeBindingContainer.java b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/AbstractCompositeAttributeBindingContainer.java index 82dc9dbef3..8a610565f6 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/AbstractCompositeAttributeBindingContainer.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/AbstractCompositeAttributeBindingContainer.java @@ -100,6 +100,12 @@ public abstract class AbstractCompositeAttributeBindingContainer protected abstract boolean isModifiable(); + protected RelationalValueBindingContainer getRelationalValueBindingContainer() { + final RelationalValueBindingContainer bindingContainer = new RelationalValueBindingContainer(); + collectRelationalValueBindings( bindingContainer ); + return bindingContainer; + } + @Override public BasicAttributeBinding makeBasicAttributeBinding( SingularAttribute attribute, diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/AbstractPluralAttributeElementBinding.java b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/AbstractPluralAttributeElementBinding.java index 5b8dbdf63f..821f712711 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/AbstractPluralAttributeElementBinding.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/AbstractPluralAttributeElementBinding.java @@ -48,4 +48,26 @@ public abstract class AbstractPluralAttributeElementBinding implements PluralAtt public HibernateTypeDescriptor getHibernateTypeDescriptor() { return hibernateTypeDescriptor; } + + protected abstract RelationalValueBindingContainer getRelationalValueContainer(); + + @Override + public List getRelationalValueBindings() { + return getRelationalValueContainer().relationalValueBindings(); + } + + @Override + public boolean isNullable() { + return getRelationalValueContainer().hasNullableRelationalValueBinding(); + } + + @Override + public boolean hasDerivedValue() { + return getRelationalValueContainer().hasDerivedValue(); + } + + @Override + public boolean hasNonNullableValue() { + return getRelationalValueContainer().hasNonNullableRelationalValueBinding(); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/AbstractSingularAssociationAttributeBinding.java b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/AbstractSingularAssociationAttributeBinding.java index 2282a973fd..3efc76f9ad 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/AbstractSingularAssociationAttributeBinding.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/AbstractSingularAssociationAttributeBinding.java @@ -36,7 +36,7 @@ import org.hibernate.metamodel.spi.source.MetaAttributeContext; /** * @author Gail Badner */ -public class AbstractSingularAssociationAttributeBinding extends AbstractSingularAttributeBinding +public abstract class AbstractSingularAssociationAttributeBinding extends AbstractSingularAttributeBinding implements SingularAssociationAttributeBinding { protected final EntityBinding referencedEntityBinding; protected final SingularAttributeBinding referencedAttributeBinding; @@ -85,12 +85,6 @@ public class AbstractSingularAssociationAttributeBinding extends AbstractSingula return isNotFoundAnException; } - @Override - public boolean hasDerivedValue() { - // TODO: support derived value - return false; - } - @Override public boolean isAssociation() { return true; @@ -166,6 +160,6 @@ public class AbstractSingularAssociationAttributeBinding extends AbstractSingula @Override protected void collectRelationalValueBindings(RelationalValueBindingContainer relationalValueBindingContainer) { - relationalValueBindingContainer.addRelationalValueBindings( this.relationalValueBindingContainer); + relationalValueBindingContainer.addRelationalValueBindings( this.relationalValueBindingContainer ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/AbstractSingularAttributeBinding.java b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/AbstractSingularAttributeBinding.java index f444373775..130185ff66 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/AbstractSingularAttributeBinding.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/AbstractSingularAttributeBinding.java @@ -58,9 +58,14 @@ public abstract class AbstractSingularAttributeBinding return getRelationalValueBindingContainer().relationalValueBindings(); } + @Override + public boolean hasDerivedValue() { + return getRelationalValueBindingContainer().hasDerivedValue(); + } + @Override public boolean isNullable() { - return getRelationalValueBindingContainer().hasNullableRelationalValueBinding(); + return !getRelationalValueBindingContainer().hasNonNullableRelationalValueBinding(); } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/BackRefAttributeBinding.java b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/BackRefAttributeBinding.java index ac382c133e..a154bf1447 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/BackRefAttributeBinding.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/BackRefAttributeBinding.java @@ -70,8 +70,9 @@ public class BackRefAttributeBinding extends BasicAttributeBinding { } else { relationalValueBindings = new ArrayList( ); - for ( Column column : pluralAttributeBinding.getPluralAttributeKeyBinding().getForeignKey().getSourceColumns() ) { - relationalValueBindings.add( new RelationalValueBinding( column, true, false ) ); + for ( RelationalValueBinding keyRelationalValueBindings : pluralAttributeBinding.getPluralAttributeKeyBinding().getRelationalValueBindings() ) { + Column keyColumn = (Column) keyRelationalValueBindings.getValue(); + relationalValueBindings.add( new RelationalValueBinding( keyColumn, true, false ) ); } } return relationalValueBindings; @@ -99,18 +100,9 @@ public class BackRefAttributeBinding extends BasicAttributeBinding { return isIndexBackRef; } - @Override - public boolean hasDerivedValue() { - return false; - } - - @Override - public boolean isNullable() { - return false; - } - @Override public boolean isIncludedInUpdate() { + //TODO: should be able to rely on super method, but that seems broken currently. return false; } } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/BasicAttributeBinding.java b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/BasicAttributeBinding.java index 1dde4408a7..b7033d7741 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/BasicAttributeBinding.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/BasicAttributeBinding.java @@ -23,7 +23,6 @@ */ package org.hibernate.metamodel.spi.binding; -import java.util.Collections; import java.util.List; import org.hibernate.mapping.PropertyGeneration; @@ -40,7 +39,6 @@ public class BasicAttributeBinding implements SingularNonAssociationAttributeBinding { private final RelationalValueBindingContainer relationalValueBindingContainer; - private boolean hasDerivedValue; private final PropertyGeneration generation; BasicAttributeBinding( @@ -62,11 +60,7 @@ public class BasicAttributeBinding naturalIdMutability, metaAttributeContext ); - this.relationalValueBindingContainer = - new RelationalValueBindingContainer( relationalValueBindings ); - for ( RelationalValueBinding relationalValueBinding : relationalValueBindings ) { - this.hasDerivedValue = this.hasDerivedValue || relationalValueBinding.isDerived(); - } + this.relationalValueBindingContainer = new RelationalValueBindingContainer( relationalValueBindings ); this.generation = generation; } @@ -75,15 +69,6 @@ public class BasicAttributeBinding return false; } - public List getRelationalValueBindings() { - return relationalValueBindingContainer.relationalValueBindings(); - } - - @Override - public boolean hasDerivedValue() { - return hasDerivedValue; - } - public PropertyGeneration getGeneration() { return generation; } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/BasicPluralAttributeElementBinding.java b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/BasicPluralAttributeElementBinding.java index bd9789eebc..c9bc4ac131 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/BasicPluralAttributeElementBinding.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/BasicPluralAttributeElementBinding.java @@ -34,29 +34,23 @@ import java.util.List; */ public class BasicPluralAttributeElementBinding extends AbstractPluralAttributeElementBinding { - private boolean hasDerivedValue; - private boolean isNullable = true; - private List relationalValueBindings; + private RelationalValueBindingContainer relationalValueBindingContainer; public BasicPluralAttributeElementBinding(AbstractPluralAttributeBinding binding) { super( binding ); } + @Override + protected RelationalValueBindingContainer getRelationalValueContainer() { + return relationalValueBindingContainer; + } + @Override public Nature getNature() { return Nature.BASIC; } - @Override - public List getRelationalValueBindings() { - return relationalValueBindings; - } - public void setRelationalValueBindings(List relationalValueBindings) { - this.relationalValueBindings = Collections.unmodifiableList( relationalValueBindings ); - for ( RelationalValueBinding relationalValueBinding : getRelationalValueBindings() ) { - this.hasDerivedValue = this.hasDerivedValue || relationalValueBinding.isDerived(); - this.isNullable = this.isNullable && relationalValueBinding.isNullable(); - } + this.relationalValueBindingContainer = new RelationalValueBindingContainer( relationalValueBindings ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/CompositeAttributeBinding.java b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/CompositeAttributeBinding.java index 36a08a18cc..44a2025783 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/CompositeAttributeBinding.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/CompositeAttributeBinding.java @@ -215,9 +215,7 @@ public class CompositeAttributeBinding @Override protected RelationalValueBindingContainer getRelationalValueBindingContainer() { - final RelationalValueBindingContainer relationalValueBindingContainer = new RelationalValueBindingContainer(); - collectRelationalValueBindings( relationalValueBindingContainer ); - return relationalValueBindingContainer; + return compositeAttributeBindingContainer.getRelationalValueBindingContainer(); } @Override @@ -279,7 +277,6 @@ public class CompositeAttributeBinding return true; } - @Override public boolean isIncludedInInsert() { // if the attribute is synthetic, this attribute binding (as a whole) is not insertable; @@ -314,13 +311,9 @@ public class CompositeAttributeBinding return false; } - @Override + @Override protected void collectRelationalValueBindings(RelationalValueBindingContainer relationalValueBindingContainer) { - for ( AttributeBinding subAttributeBinding : attributeBindings() ) { - if ( AbstractSingularAttributeBinding.class.isInstance( subAttributeBinding ) ) { - ( (AbstractSingularAttributeBinding) subAttributeBinding ).collectRelationalValueBindings( relationalValueBindingContainer ); - } - } + compositeAttributeBindingContainer.collectRelationalValueBindings( relationalValueBindingContainer ); } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/CompositePluralAttributeElementBinding.java b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/CompositePluralAttributeElementBinding.java index 1e2b7f6f13..c5f762a35f 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/CompositePluralAttributeElementBinding.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/CompositePluralAttributeElementBinding.java @@ -23,9 +23,7 @@ */ package org.hibernate.metamodel.spi.binding; -import java.util.ArrayList; import java.util.LinkedHashMap; -import java.util.List; import java.util.Map; import org.hibernate.engine.spi.CascadeStyle; @@ -51,6 +49,11 @@ public class CompositePluralAttributeElementBinding super( binding ); } + @Override + protected RelationalValueBindingContainer getRelationalValueContainer() { + return compositeAttributeBindingContainer.getRelationalValueBindingContainer(); + } + @Override public Nature getNature() { return Nature.AGGREGATE; @@ -94,13 +97,6 @@ public class CompositePluralAttributeElementBinding return compositeAttributeBindingContainer; } - @Override - public List getRelationalValueBindings() { - final RelationalValueBindingContainer bindingContainer = new RelationalValueBindingContainer(); - compositeAttributeBindingContainer.collectRelationalValueBindings( bindingContainer ); - return bindingContainer.relationalValueBindings(); - } - @Override public CascadeStyle getCascadeStyle() { return cascadeStyle; diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/CompositePluralAttributeIndexBinding.java b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/CompositePluralAttributeIndexBinding.java index dc01f6bb88..06295cc52b 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/CompositePluralAttributeIndexBinding.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/CompositePluralAttributeIndexBinding.java @@ -23,7 +23,6 @@ */ package org.hibernate.metamodel.spi.binding; -import java.util.ArrayList; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; @@ -91,8 +90,6 @@ public class CompositePluralAttributeIndexBinding extends AbstractPluralAttribut @Override public List getRelationalValueBindings() { - final RelationalValueBindingContainer bindingContainer = new RelationalValueBindingContainer(); - compositeAttributeBindingContainer.collectRelationalValueBindings( bindingContainer ); - return bindingContainer.relationalValueBindings(); + return compositeAttributeBindingContainer.getRelationalValueBindingContainer().relationalValueBindings(); } } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/ManyToAnyPluralAttributeElementBinding.java b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/ManyToAnyPluralAttributeElementBinding.java index c54638c1a9..def92f83e4 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/ManyToAnyPluralAttributeElementBinding.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/ManyToAnyPluralAttributeElementBinding.java @@ -36,13 +36,14 @@ public class ManyToAnyPluralAttributeElementBinding extends AbstractPluralAttrib super( binding ); } + @Override + protected RelationalValueBindingContainer getRelationalValueContainer() { + return null; //To change body of implemented methods use File | Settings | File Templates. + } + @Override public Nature getNature() { return Nature.MANY_TO_ANY; } - @Override - public List getRelationalValueBindings() { - return null; //To change body of implemented methods use File | Settings | File Templates. - } } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/ManyToManyPluralAttributeElementBinding.java b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/ManyToManyPluralAttributeElementBinding.java index b9e5f3e23a..a2aa8ebf81 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/ManyToManyPluralAttributeElementBinding.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/ManyToManyPluralAttributeElementBinding.java @@ -24,11 +24,9 @@ package org.hibernate.metamodel.spi.binding; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; import org.hibernate.internal.FilterConfiguration; -import org.hibernate.metamodel.spi.relational.Value; /** * Describes plural attributes of {@link org.hibernate.metamodel.spi.binding.PluralAttributeElementBinding.Nature#MANY_TO_MANY} elements @@ -41,24 +39,24 @@ public class ManyToManyPluralAttributeElementBinding extends AbstractPluralAttri private String manyToManyWhere; private String manyToManyOrderBy; // TODO: really should have value defined (which defines table), but may not know - List relationalValueBindings; + private RelationalValueBindingContainer relationalValueBindingContainer; ManyToManyPluralAttributeElementBinding(AbstractPluralAttributeBinding binding) { super( binding ); } + @Override + protected RelationalValueBindingContainer getRelationalValueContainer() { + return relationalValueBindingContainer; + } + @Override public Nature getNature() { return Nature.MANY_TO_MANY; } - @Override - public List getRelationalValueBindings() { - return relationalValueBindings; - } - public void setRelationalValueBindings(List relationalValueBindings) { - this.relationalValueBindings = relationalValueBindings; + this.relationalValueBindingContainer = new RelationalValueBindingContainer( relationalValueBindings ); } public String getManyToManyWhere() { diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/OneToManyPluralAttributeElementBinding.java b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/OneToManyPluralAttributeElementBinding.java index 4db88b05a9..8c03876b3a 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/OneToManyPluralAttributeElementBinding.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/OneToManyPluralAttributeElementBinding.java @@ -33,23 +33,25 @@ import java.util.List; */ public class OneToManyPluralAttributeElementBinding extends AbstractPluralAttributeAssociationElementBinding { private EntityIdentifier elementEntityIdentifier; + private RelationalValueBindingContainer relationalValueBindingContainer; OneToManyPluralAttributeElementBinding(AbstractPluralAttributeBinding binding) { super( binding ); } + @Override + protected RelationalValueBindingContainer getRelationalValueContainer() { + return relationalValueBindingContainer; + } + @Override public Nature getNature() { return Nature.ONE_TO_MANY; } public void setElementEntityIdentifier(EntityIdentifier elementEntityIdentifier) { - this.elementEntityIdentifier = elementEntityIdentifier; - } - - @Override - public List getRelationalValueBindings() { - // TODO: ugh, can't call this until after the EntityIdentifier is completely bound... - return elementEntityIdentifier.getAttributeBinding().getRelationalValueBindings(); + this.relationalValueBindingContainer = new RelationalValueBindingContainer( + elementEntityIdentifier.getAttributeBinding().getRelationalValueBindings() + ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/PluralAttributeElementBinding.java b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/PluralAttributeElementBinding.java index 2f48d8f1c3..4b8d8cccea 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/PluralAttributeElementBinding.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/PluralAttributeElementBinding.java @@ -46,6 +46,12 @@ public interface PluralAttributeElementBinding { */ public List getRelationalValueBindings(); + public boolean isNullable(); + + public boolean hasDerivedValue(); + + public boolean hasNonNullableValue(); + /** * Retrieves an enumeration describing the mapping nature of the collection's elements. * diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/PluralAttributeKeyBinding.java b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/PluralAttributeKeyBinding.java index 7271006086..255a12599e 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/PluralAttributeKeyBinding.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/PluralAttributeKeyBinding.java @@ -23,9 +23,10 @@ */ package org.hibernate.metamodel.spi.binding; +import java.util.List; + import org.hibernate.AssertionFailure; -import org.hibernate.metamodel.spi.relational.Column; -import org.hibernate.metamodel.spi.relational.ForeignKey; +import org.hibernate.cfg.NotYetImplementedException; import org.hibernate.metamodel.spi.relational.TableSpecification; /** @@ -36,10 +37,9 @@ import org.hibernate.metamodel.spi.relational.TableSpecification; public class PluralAttributeKeyBinding { private final AbstractPluralAttributeBinding pluralAttributeBinding; private final SingularAttributeBinding referencedAttributeBinding; - private ForeignKey foreignKey; + private RelationalValueBindingContainer relationalValueBindingContainer; + private boolean isCascadeDeleteEnabled; private boolean inverse; - private boolean insertable; - private boolean updatable; // this knowledge can be implicitly resolved based on the typing information on the referenced owner attribute private HibernateTypeDescriptor hibernateTypeDescriptor = new HibernateTypeDescriptor(); @@ -69,17 +69,9 @@ public class PluralAttributeKeyBinding { return referencedAttributeBinding; } - /** - * The foreign key that defines the scope of this relationship. - * - * @return The foreign key being bound to. - */ - public ForeignKey getForeignKey() { - return foreignKey; - } - public TableSpecification getCollectionTable() { - return foreignKey.getSourceTable(); + // TODO: get table directly from relationalValueBindingContainer + return relationalValueBindingContainer.relationalValueBindings().get( 0 ).getValue().getTable(); } /** @@ -105,48 +97,47 @@ public class PluralAttributeKeyBinding { this.hibernateTypeDescriptor = hibernateTypeDescriptor; } - public void setForeignKey(ForeignKey foreignKey) { - if ( foreignKey == null ) { - throw new AssertionFailure( "foreignKey argument must be non-null." ); + public List getRelationalValueBindings() { + return relationalValueBindingContainer.relationalValueBindings(); + } + + public void setRelationalValueBindings(List relationalValueBindings) { + if ( relationalValueBindings == null || relationalValueBindings.isEmpty() ) { + throw new AssertionFailure( "relationalValueBindings argument must be non-null and non-empty." ); } - if ( this.foreignKey != null ) { - throw new AssertionFailure( "Foreign key already initialized" ); + if ( this.relationalValueBindingContainer != null ) { + throw new AssertionFailure( "Relational value bindings have already initialized" ); } - this.foreignKey = foreignKey; + this.relationalValueBindingContainer = new RelationalValueBindingContainer( relationalValueBindings ); + if ( this.relationalValueBindingContainer.hasDerivedValue() ) { + throw new NotYetImplementedException( + "Derived values are not supported when creating a foreign key that targets columns." + ); + } + } + + public boolean isCascadeDeleteEnabled() { + return isCascadeDeleteEnabled; + } + + public void setCascadeDeleteEnabled(boolean isCascadeDeleteEnabled) { + this.isCascadeDeleteEnabled = isCascadeDeleteEnabled; } public boolean isNullable() { - if ( foreignKey == null || foreignKey.getSourceColumns().isEmpty() ) { - throw new IllegalStateException( "Foreign key has no columns." ); - } - // cannot be nullable if the foreign key source columns are included in the primary key . - if ( foreignKey.getTable().getPrimaryKey().getColumns().containsAll( foreignKey.getSourceColumns() ) ) { + // cannot be nullable if the foreign key source columns are included in the primary key + // TODO: move this into RelationalValueBindingContainer. + if ( getCollectionTable().getPrimaryKey().getColumns().containsAll( relationalValueBindingContainer.columns() ) ) { return false; } - for ( Column column : foreignKey.getSourceColumns() ) { - if ( column.isNullable() ) { - return true; - } - } - return false; - } - - public void setInsertable( boolean insertable ){ - this.insertable = insertable; + return relationalValueBindingContainer.hasNullableRelationalValueBinding(); } public boolean isInsertable() { - return insertable; - } - - public void setUpdatable( boolean updatable ){ - // The key is updatable if the foreign key *source* columns are updatable; - // We don't have the RelationalValueBindings for the FK source columns stored in ForeignKey - // so it needs to be set explicitly. - this.updatable = updatable; + return relationalValueBindingContainer.hasInsertableRelationalValueBinding(); } public boolean isUpdatable() { - return updatable; + return relationalValueBindingContainer.hasUpdateableRelationalValueBinding(); } } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/RelationalValueBindingContainer.java b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/RelationalValueBindingContainer.java index 496abebe54..748b793240 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/RelationalValueBindingContainer.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/binding/RelationalValueBindingContainer.java @@ -43,7 +43,6 @@ public class RelationalValueBindingContainer { this.isListModifiable = false; } - public RelationalValueBindingContainer() { this.relationalValueBindings = new ArrayList(); this.isListModifiable = true; @@ -81,11 +80,12 @@ public class RelationalValueBindingContainer { } public boolean hasDerivedValue() { - boolean hasDerivedValue = false; for ( RelationalValueBinding relationalValueBinding : relationalValueBindings ) { - hasDerivedValue = hasDerivedValue || relationalValueBinding.isDerived(); + if (relationalValueBinding.isDerived() ) { + return true; + } } - return hasDerivedValue; + return false; } public boolean hasNullableRelationalValueBinding() { @@ -123,35 +123,4 @@ public class RelationalValueBindingContainer { } return false; } - -/* - protected static boolean hasNullableRelationalValueBinding(List relationalValueBindings) { - for ( RelationalValueBinding relationalValueBinding : relationalValueBindings ) { - if ( relationalValueBinding.isNullable() ) { - return true; - } - } - return false; - } - - protected static boolean hasInsertableRelationalValueBinding(List relationalValueBindings) { - for ( RelationalValueBinding relationalValueBinding : relationalValueBindings ) { - if ( relationalValueBinding.isIncludeInInsert() ) { - return true; - } - } - return false; - } - - protected static boolean hasUpdateableRelationalValueBinding(List relationalValueBindings) { - for ( RelationalValueBinding relationalValueBinding : relationalValueBindings ) { - if ( relationalValueBinding.isIncludeInUpdate() ) { - return true; - } - } - return false; - } - */ - - -} \ No newline at end of file +} diff --git a/hibernate-core/src/main/java/org/hibernate/persister/collection/AbstractCollectionPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/collection/AbstractCollectionPersister.java index 17aaa215af..c4c3f345ef 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/collection/AbstractCollectionPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/collection/AbstractCollectionPersister.java @@ -746,11 +746,12 @@ public abstract class AbstractCollectionPersister PluralAttributeKeyBinding keyBinding = collection.getPluralAttributeKeyBinding(); keyType = keyBinding.getHibernateTypeDescriptor().getResolvedTypeMapping(); - int keySpan = keyBinding.getForeignKey().getColumnSpan(); + int keySpan = keyBinding.getRelationalValueBindings().size(); keyColumnNames = new String[keySpan]; keyColumnAliases = new String[keySpan]; int k = 0; - for ( Column keyColumn : keyBinding.getForeignKey().getSourceColumns() ) { + for ( RelationalValueBinding keyRelationalValueBinding : keyBinding.getRelationalValueBindings() ) { + Column keyColumn = (Column) keyRelationalValueBinding.getValue(); // NativeSQL: collect key column and auto-aliases keyColumnNames[k] = keyColumn.getColumnName().getText( dialect ); // TODO: does the owner root table need to be in alias? diff --git a/hibernate-core/src/main/java/org/hibernate/persister/collection/OneToManyPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/collection/OneToManyPersister.java index 88e9618a48..ea262a61ec 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/collection/OneToManyPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/collection/OneToManyPersister.java @@ -110,8 +110,7 @@ public class OneToManyPersister extends AbstractCollectionPersister { ); } final PluralAttributeKeyBinding keyBinding = collection.getPluralAttributeKeyBinding(); - cascadeDeleteEnabled = keyBinding.getForeignKey().getDeleteRule() == ForeignKey.ReferentialAction.CASCADE && - factory.getDialect().supportsCascadeDelete();; + cascadeDeleteEnabled = keyBinding.isCascadeDeleteEnabled() && factory.getDialect().supportsCascadeDelete(); keyIsNullable = keyBinding.isNullable(); keyIsUpdateable = keyBinding.isUpdatable(); } diff --git a/hibernate-core/src/test/java/org/hibernate/metamodel/spi/binding/basiccollections/AbstractBasicCollectionBindingTests.java b/hibernate-core/src/test/java/org/hibernate/metamodel/spi/binding/basiccollections/AbstractBasicCollectionBindingTests.java index 1d803b0a9e..0c41b5e281 100644 --- a/hibernate-core/src/test/java/org/hibernate/metamodel/spi/binding/basiccollections/AbstractBasicCollectionBindingTests.java +++ b/hibernate-core/src/test/java/org/hibernate/metamodel/spi/binding/basiccollections/AbstractBasicCollectionBindingTests.java @@ -24,6 +24,7 @@ package org.hibernate.metamodel.spi.binding.basiccollections; import java.util.Collection; +import java.util.List; import java.util.Set; import org.junit.After; @@ -45,6 +46,7 @@ import org.hibernate.metamodel.spi.binding.PluralAttributeKeyBinding; import org.hibernate.metamodel.spi.binding.RelationalValueBinding; import org.hibernate.metamodel.spi.binding.SingularAttributeBinding; import org.hibernate.metamodel.spi.domain.PluralAttribute; +import org.hibernate.metamodel.spi.relational.Column; import org.hibernate.metamodel.spi.relational.ForeignKey; import org.hibernate.metamodel.spi.relational.Identifier; import org.hibernate.metamodel.spi.relational.TableSpecification; @@ -174,24 +176,19 @@ public abstract class AbstractBasicCollectionBindingTests extends BaseUnitTestCa assertEquals( expectedFetchTiming, collectionBinding.getFetchTiming() ); assertEquals( expectedFetchTiming != FetchTiming.IMMEDIATE, collectionBinding.isLazy() ); - ForeignKey fk = keyBinding.getForeignKey(); - assertNotNull( fk ); - assertSame( collectionTable, fk.getSourceTable() ); - assertEquals( 1, fk.getColumnSpan() ); + List keyRelationalValueBindings = keyBinding.getRelationalValueBindings(); + assertNotNull( keyRelationalValueBindings ); + for( RelationalValueBinding keyRelationalValueBinding : keyRelationalValueBindings ) { + assertSame( collectionTable, keyRelationalValueBinding.getValue().getTable() ); + } + assertEquals( 1, keyRelationalValueBindings.size() ); assertEquals( 1, expectedKeyTargetAttributeBinding.getRelationalValueBindings().size() ); Value expectedFKTargetValue = expectedKeyTargetAttributeBinding.getRelationalValueBindings().get( 0 ).getValue(); - assertEquals( fk.getColumns(), fk.getSourceColumns() ); - assertEquals( 1, fk.getSourceColumns().size() ); - assertEquals( 1, fk.getTargetColumns().size() ); - assertEquals( expectedKeySourceColumnName, fk.getSourceColumns().get( 0 ).getColumnName() ); - assertSame( expectedFKTargetValue, fk.getTargetColumns().get( 0 ) ); - assertSame( collectionOwnerBinding.getPrimaryTable(), fk.getTargetTable() ); - assertEquals( expectedFKTargetValue.getJdbcDataType(), fk.getSourceColumns().get( 0 ).getJdbcDataType() ); + assertFalse( keyRelationalValueBindings.get( 0 ).isDerived() ); + assertEquals( expectedKeySourceColumnName, ( (Column) keyRelationalValueBindings.get( 0 ).getValue() ).getColumnName() ); + assertEquals( expectedFKTargetValue.getJdbcDataType(), keyRelationalValueBindings.get( 0 ).getValue().getJdbcDataType() ); - assertSame( ForeignKey.ReferentialAction.NO_ACTION, fk.getDeleteRule() ); - assertSame( ForeignKey.ReferentialAction.NO_ACTION, fk.getUpdateRule() ); - // FK name is null because no default FK name is generated until HHH-7092 is fixed - assertNull( fk.getName() ); + assertFalse( keyBinding.isCascadeDeleteEnabled() ); checkEquals( expectedKeyTargetAttributeBinding.getHibernateTypeDescriptor(), keyBinding.getHibernateTypeDescriptor() @@ -222,7 +219,7 @@ public abstract class AbstractBasicCollectionBindingTests extends BaseUnitTestCa } else { assertEquals( 2, collectionTable.getPrimaryKey().getColumnSpan() ); - assertSame( fk.getSourceColumns().get( 0 ), collectionTable.getPrimaryKey().getColumns().get( 0 ) ); + assertSame( keyRelationalValueBindings.get( 0 ).getValue(), collectionTable.getPrimaryKey().getColumns().get( 0 ) ); assertSame( elementRelationalValueBinding.getValue(), collectionTable.getPrimaryKey().getColumns().get( 1 ) ); } } diff --git a/hibernate-core/src/test/java/org/hibernate/metamodel/spi/binding/onetomany/AbstractUnidirectionalOneToManyBindingTests.java b/hibernate-core/src/test/java/org/hibernate/metamodel/spi/binding/onetomany/AbstractUnidirectionalOneToManyBindingTests.java index f8c4cde1c1..f41b8648ac 100644 --- a/hibernate-core/src/test/java/org/hibernate/metamodel/spi/binding/onetomany/AbstractUnidirectionalOneToManyBindingTests.java +++ b/hibernate-core/src/test/java/org/hibernate/metamodel/spi/binding/onetomany/AbstractUnidirectionalOneToManyBindingTests.java @@ -43,6 +43,7 @@ import org.hibernate.metamodel.spi.binding.HibernateTypeDescriptor; import org.hibernate.metamodel.spi.binding.PluralAttributeBinding; import org.hibernate.metamodel.spi.binding.PluralAttributeElementBinding; import org.hibernate.metamodel.spi.binding.PluralAttributeKeyBinding; +import org.hibernate.metamodel.spi.binding.RelationalValueBinding; import org.hibernate.metamodel.spi.binding.SingularAttributeBinding; import org.hibernate.metamodel.spi.relational.Column; import org.hibernate.metamodel.spi.relational.ForeignKey; @@ -202,18 +203,12 @@ public abstract class AbstractUnidirectionalOneToManyBindingTests extends BaseUn expectedCollectionTypeClass.cast( collectionHibernateTypeDescriptor.getResolvedTypeMapping() ).getRole() ); - ForeignKey fk = keyBinding.getForeignKey(); - assertNotNull( fk ); - assertSame( ForeignKey.ReferentialAction.NO_ACTION, fk.getDeleteRule() ); - assertSame( ForeignKey.ReferentialAction.NO_ACTION, fk.getUpdateRule() ); - // FK name is null because no default FK name is generated until HHH-7092 is fixed - assertNull( fk.getName() ); + List keyRelationalValueBinding = keyBinding.getRelationalValueBindings(); + assertNotNull( keyRelationalValueBinding ); + assertFalse( keyBinding.isCascadeDeleteEnabled() ); - assertSame( expectedElementEntityBinding.getPrimaryTable(), fk.getSourceTable() ); - assertEquals( 1, fk.getColumnSpan() ); - assertEquals( fk.getColumns(), fk.getSourceColumns() ); - assertEquals( 1, fk.getSourceColumns().size() ); - assertEquals( 1, fk.getTargetColumns().size() ); + assertSame( expectedElementEntityBinding.getPrimaryTable(), keyBinding.getCollectionTable() ); + assertEquals( 1, keyRelationalValueBinding.size() ); SingularAttributeBinding keySourceAttributeBinding = ( SingularAttributeBinding ) expectedElementEntityBinding.locateAttributeBinding( @@ -229,19 +224,12 @@ public abstract class AbstractUnidirectionalOneToManyBindingTests extends BaseUn assertTrue( keySourceValue instanceof Column ); Column keySourceColumn = ( Column ) keySourceValue; assertEquals( expectedKeySourceColumnName, keySourceColumn.getColumnName() ); - assertSame( keySourceColumn, fk.getColumns().get( 0 ) ); - assertSame( keySourceColumn, fk.getSourceColumns().get( 0 ) ); } - assertSame( collectionOwnerBinding.getPrimaryTable(), fk.getTargetTable() ); assertEquals( 1, expectedKeyTargetAttributeBinding.getRelationalValueBindings().size() ); - assertSame( - expectedKeyTargetAttributeBinding.getRelationalValueBindings().get( 0 ).getValue(), - fk.getTargetColumns().get( 0 ) - ); assertEquals( expectedKeyTargetAttributeBinding.getRelationalValueBindings().get( 0 ).getValue().getJdbcDataType(), - fk.getColumns().get( 0 ).getJdbcDataType() + keyRelationalValueBinding.get( 0 ).getValue().getJdbcDataType() ); checkEquals( diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/engine/collection/UnidirCollectionWithMultipleOwnerTest.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/engine/collection/UnidirCollectionWithMultipleOwnerTest.java index ec8fb3a971..515ec5ab06 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/annotations/engine/collection/UnidirCollectionWithMultipleOwnerTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/engine/collection/UnidirCollectionWithMultipleOwnerTest.java @@ -33,7 +33,6 @@ import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; /** * @author Emmanuel Bernard */ -@FailureExpectedWithNewMetamodel public class UnidirCollectionWithMultipleOwnerTest extends BaseCoreFunctionalTestCase { @Test public void testUnidirCollectionWithMultipleOwner() throws Exception { diff --git a/hibernate-core/src/test/java/org/hibernate/test/collection/map/PersistentMapTest.java b/hibernate-core/src/test/java/org/hibernate/test/collection/map/PersistentMapTest.java index 941240fe4e..5d228b7500 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/collection/map/PersistentMapTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/collection/map/PersistentMapTest.java @@ -28,7 +28,6 @@ import org.junit.Test; import org.hibernate.Session; import org.hibernate.collection.internal.PersistentMap; -import org.hibernate.testing.FailureExpectedWithNewMetamodel; import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; import static org.junit.Assert.assertEquals;