From f839cd22ef33b720d5d191b3e5eec48e6e619aba Mon Sep 17 00:00:00 2001 From: Gail Badner Date: Tue, 21 Feb 2012 12:48:11 -0800 Subject: [PATCH] HHH-7052 : Bind PluralAttributeKeyBinding --- .../metamodel/internal/source/Binder.java | 157 +++++++++++------- .../binding/PluralAttributeKeyBinding.java | 9 +- .../binding/BasicCollectionBindingTests.java | 62 ++++++- 3 files changed, 163 insertions(+), 65 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/Binder.java b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/Binder.java index 7707a0d031..15ef211f39 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/Binder.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/Binder.java @@ -52,6 +52,7 @@ import org.hibernate.metamodel.spi.binding.CompositeAttributeBinding; import org.hibernate.metamodel.spi.binding.EntityBinding; import org.hibernate.metamodel.spi.binding.EntityDiscriminator; +import org.hibernate.metamodel.spi.binding.HibernateTypeDescriptor; import org.hibernate.metamodel.spi.binding.IdGenerator; import org.hibernate.metamodel.spi.binding.InheritanceType; import org.hibernate.metamodel.spi.binding.ManyToOneAttributeBinding; @@ -95,6 +96,7 @@ import org.hibernate.metamodel.spi.source.MetadataImplementor; import org.hibernate.metamodel.spi.source.Orderable; import org.hibernate.metamodel.spi.source.PluralAttributeElementSource; +import org.hibernate.metamodel.spi.source.PluralAttributeKeySource; import org.hibernate.metamodel.spi.source.PluralAttributeNature; import org.hibernate.metamodel.spi.source.PluralAttributeSource; import org.hibernate.metamodel.spi.source.PrimaryKeyJoinColumnSource; @@ -261,7 +263,9 @@ private EntityBinding doCreateEntityBinding(EntitySource entitySource, EntityBin final EntityBinding entityBinding = createBasicEntityBinding( entitySource, superEntityBinding ); bindSecondaryTables( entitySource, entityBinding ); + Deque tableStack = new ArrayDeque( ); + tableStack.add( entityBinding.getPrimaryTable() ); bindAttributes( entitySource, entityBinding, tableStack ); bindTableUniqueConstraints( entitySource, entityBinding ); @@ -614,7 +618,10 @@ else if ( attributeSource.isVirtualAttribute() ) { final List relationalValueBindings = createSimpleRelationalValues( attributeSource, attributeBindingContainer, - attribute + attribute, + attributeBindingContainer + .seekEntityBinding() + .getPrimaryTable() ); final String propertyAccessorName = Helper.getPropertyAccessorName( attributeSource.getPropertyAccessorName(), @@ -794,7 +801,10 @@ else if ( attributeSource.isVirtualAttribute() ) { final List relationalValueBindings = createSimpleRelationalValues( attributeSource, attributeBindingContainer, - attribute + attribute, + attributeBindingContainer + .seekEntityBinding() + .getPrimaryTable() ); final String propertyAccessorName = Helper.getPropertyAccessorName( attributeSource.getPropertyAccessorName(), @@ -955,6 +965,8 @@ private void doBasicPluralAttributeBinding(PluralAttributeSource source, Abstrac binding.setCustomSqlDelete( source.getCustomSqlDelete() ); binding.setCustomSqlDeleteAll( source.getCustomSqlDeleteAll() ); + binding.setWhere( source.getWhere() ); + // doBasicAttributeBinding( source, binding ); } @@ -1020,8 +1032,6 @@ public String inferredTableName() { if ( StringHelper.isNotEmpty( attributeSource.getCollectionTableCheck() ) ) { pluralAttributeBinding.getCollectionTable().addCheckConstraint( attributeSource.getCollectionTableCheck() ); } - - pluralAttributeBinding.setWhere( attributeSource.getWhere() ); } private void bindCollectionKey( @@ -1029,56 +1039,91 @@ private void bindCollectionKey( AbstractPluralAttributeBinding pluralAttributeBinding, Deque tableStack) { -// TableSpecification targetTable = tableStack.peekLast(); - pluralAttributeBinding.getPluralAttributeKeyBinding().prepareForeignKey( - attributeSource.getKeySource().getExplicitForeignKeyName(), - //tableStack.peekLast().getLogicalName() - null // todo : handle secondary table names + final PluralAttributeKeySource keySource = attributeSource.getKeySource(); + + String foreignKeyName = ( + StringHelper.isNotEmpty( keySource.getExplicitForeignKeyName() ) ? + quoteIdentifier( keySource.getExplicitForeignKeyName() ) : + null // TODO: is null FK name allowd (is there a default?) ); - pluralAttributeBinding.getPluralAttributeKeyBinding().getForeignKey().setDeleteRule( - attributeSource.getKeySource().getOnDeleteAction() + pluralAttributeBinding.getPluralAttributeKeyBinding().prepareForeignKey( + foreignKeyName, + tableStack.peekLast() ); final ForeignKey foreignKey = pluralAttributeBinding.getPluralAttributeKeyBinding().getForeignKey(); - Iterator targetValueBindings = null; - if ( attributeSource.getKeySource().getReferencedEntityAttributeName() != null ) { - final EntityBinding ownerEntityBinding = pluralAttributeBinding.getContainer().seekEntityBinding(); - final AttributeBinding referencedAttributeBinding = ownerEntityBinding.locateAttributeBinding( - attributeSource.getKeySource().getReferencedEntityAttributeName() + foreignKey.setDeleteRule( keySource.getOnDeleteAction() ); + + if ( keySource.getReferencedEntityAttributeName() == null ) { + bindCollectionKeyTargetingPrimaryKey( attributeSource.getKeySource(), pluralAttributeBinding ); + } + else { + bindCollectionKeyTargetingPropertyRef( attributeSource.getKeySource(), pluralAttributeBinding ); + } + + HibernateTypeDescriptor targetTypeDescriptor = pluralAttributeBinding.getHibernateTypeDescriptor(); + + } + + private void bindCollectionKeyTargetingPrimaryKey( + PluralAttributeKeySource keySource, + AbstractPluralAttributeBinding pluralAttributeBinding) { + + for ( RelationalValueSource valueSource : keySource.getValueSources() ) { + if ( ColumnSource.class.isInstance( valueSource ) ) { + final Column column = makeColumn( + ColumnSource.class.cast( valueSource ), + COLL_KEY_COLUMN_BINDING_DEFAULTS, + pluralAttributeBinding.getCollectionTable(), + pluralAttributeBinding.getAttribute().getName(), + true + ); + pluralAttributeBinding.getPluralAttributeKeyBinding().getForeignKey().addColumn( column ); + } + else { + // TODO: deal with formulas??? + } + } + } + + private void bindCollectionKeyTargetingPropertyRef( + PluralAttributeKeySource keySource, + AbstractPluralAttributeBinding pluralAttributeBinding) { + final EntityBinding ownerEntityBinding = pluralAttributeBinding.getContainer().seekEntityBinding(); + final AttributeBinding referencedAttributeBinding = ownerEntityBinding.locateAttributeBinding( + keySource.getReferencedEntityAttributeName() + ); + final ForeignKey foreignKey = pluralAttributeBinding.getPluralAttributeKeyBinding().getForeignKey(); + if ( ! referencedAttributeBinding.getAttribute().isSingular() ) { + throw new MappingException( + String.format( + "Collection (%s) property-ref is a plural attribute (%s); must be singular.", + pluralAttributeBinding.getAttribute().getRole(), + referencedAttributeBinding + ), + currentBindingContext.getOrigin() ); - if ( ! referencedAttributeBinding.getAttribute().isSingular() ) { + } + Iterator targetValueBindings = + ( (SingularAttributeBinding) referencedAttributeBinding ).getRelationalValueBindings().iterator(); + for ( RelationalValueSource valueSource : keySource.getValueSources() ) { + if ( ! targetValueBindings.hasNext() ) { throw new MappingException( String.format( - "Collection (%s) property-ref is a plural attribute (%s); must be singular.", - pluralAttributeBinding.getAttribute().getRole(), - referencedAttributeBinding + "More collection key source columns than target columns for collection: %s", + pluralAttributeBinding.getAttribute().getRole() ), currentBindingContext.getOrigin() ); } -// targetValueBindings = ( (SingularAttributeBinding) referencedAttributeBinding ).getRelationalValueBindings().iterator(); - } - for ( RelationalValueSource valueSource : attributeSource.getKeySource().getValueSources() ) { - Value targetValue = null; - if ( targetValueBindings != null ) { - if ( ! targetValueBindings.hasNext() ) { - throw new MappingException( - String.format( - "More collection key source columns than target columns for collection: %s", - pluralAttributeBinding.getAttribute().getRole() - ), - currentBindingContext.getOrigin() - ); - } - targetValue = targetValueBindings.next().getValue(); - } + Value targetValue = targetValueBindings.next().getValue(); if ( ColumnSource.class.isInstance( valueSource ) ) { final ColumnSource columnSource = ColumnSource.class.cast( valueSource ); - final Column column = makeColumn( - columnSource, - COLL_KEY_COLUMN_BINDING_DEFAULTS, + final Column column = makeColumn( + columnSource, + COLL_KEY_COLUMN_BINDING_DEFAULTS, pluralAttributeBinding.getCollectionTable(), - pluralAttributeBinding.getAttribute().getName(), + pluralAttributeBinding.getAttribute().getName(), true ); if ( targetValue != null && ! Column.class.isInstance( targetValue ) ) { @@ -1108,7 +1153,6 @@ private void bindCollectionKey( ); } } - private static final ColumnBindingDefaults COLL_KEY_COLUMN_BINDING_DEFAULTS = new ColumnBindingDefaults() { @Override public boolean areValuesIncludedInInsertByDefault() { @@ -1166,7 +1210,8 @@ private void bindBasicPluralElementRelationalValues( createSimpleRelationalValues( relationalValueSourceContainer, elementBinding.getPluralAttributeBinding().getContainer(), - elementBinding.getPluralAttributeBinding().getAttribute() + elementBinding.getPluralAttributeBinding().getAttribute(), + elementBinding.getPluralAttributeBinding().getCollectionTable() ) ); } @@ -1440,23 +1485,26 @@ private void bindTableUniqueConstraints(EntitySource entitySource, EntityBinding private List createSimpleRelationalValues( RelationalValueSourceContainer relationalValueSourceContainer, AttributeBindingContainer attributeBindingContainer, - Attribute attribute) { + Attribute attribute, + TableSpecification defaultTable) { List valueBindings = new ArrayList(); if ( !relationalValueSourceContainer.relationalValueSources().isEmpty() ) { for ( RelationalValueSource valueSource : relationalValueSourceContainer.relationalValueSources() ) { - final TableSpecification table = attributeBindingContainer - .seekEntityBinding() - .locateTable( valueSource.getContainingTableName() ); - + TableSpecification resolvedTable = defaultTable; + if ( valueSource.getContainingTableName() != null ) { + resolvedTable = attributeBindingContainer + .seekEntityBinding() + .locateTable( valueSource.getContainingTableName() ); + } if ( ColumnSource.class.isInstance( valueSource ) ) { final ColumnSource columnSource = ColumnSource.class.cast( valueSource ); final Column column = makeColumn( columnSource, - relationalValueSourceContainer, - table, + relationalValueSourceContainer, + resolvedTable, attribute.getName(), true ); @@ -1474,7 +1522,7 @@ private List createSimpleRelationalValues( else { valueBindings.add( new RelationalValueBinding( - makeDerivedValue( ( (DerivedValueSource) valueSource ), table ) + makeDerivedValue( ( (DerivedValueSource) valueSource ), resolvedTable ) ) ); } @@ -1485,18 +1533,15 @@ private List createSimpleRelationalValues( .getNamingStrategy() .propertyToColumnName( attribute.getName() ); name = quoteIdentifier( name ); - Column column = attributeBindingContainer - .seekEntityBinding() - .getPrimaryTable() - .locateOrCreateColumn( name ); + Column column = defaultTable.locateOrCreateColumn( name ); column.setNullable( relationalValueSourceContainer.areValuesNullableByDefault() ); valueBindings.add( new RelationalValueBinding( column ) ); } return valueBindings; } - private String quoteIdentifier(String identifier) { - return currentBindingContext.isGloballyQuotedIdentifiers() ? StringHelper.quote( identifier ) : identifier; + private String quoteIdentifier(String string) { + return currentBindingContext.isGloballyQuotedIdentifiers() ? StringHelper.quote( string ) : string; } private Value makeRelationalValue( 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 fdcc4bde51..bec1afcd4e 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 @@ -40,8 +40,7 @@ public class PluralAttributeKeyBinding { // may need notion of "boolean updatable" // this knowledge can be implicitly resolved based on the typing information on the referenced owner attribute - private HibernateTypeDescriptor hibernateTypeDescriptor; - // in which case add this... + private final HibernateTypeDescriptor hibernateTypeDescriptor = new HibernateTypeDescriptor(); // SingularAttributeBinding referencedAttributeBinding; // todo : this would be nice to have but we do not always know it, especially in HBM case. @@ -89,7 +88,7 @@ public HibernateTypeDescriptor getHibernateTypeDescriptor() { return hibernateTypeDescriptor; } - public void prepareForeignKey(String foreignKeyName, String targetTableName) { + public void prepareForeignKey(String foreignKeyName, TableSpecification targetTable) { if ( foreignKey != null ) { throw new AssertionFailure( "Foreign key already initialized" ); } @@ -105,10 +104,6 @@ public void prepareForeignKey(String foreignKeyName, String targetTableName) { } } - final TableSpecification targetTable = pluralAttributeBinding.getContainer() - .seekEntityBinding() - .locateTable( targetTableName ); - foreignKey = collectionTable.createForeignKey( targetTable, foreignKeyName ); } diff --git a/hibernate-core/src/test/java/org/hibernate/metamodel/spi/binding/BasicCollectionBindingTests.java b/hibernate-core/src/test/java/org/hibernate/metamodel/spi/binding/BasicCollectionBindingTests.java index f7d1cdd6e3..f2fdf1ba45 100644 --- a/hibernate-core/src/test/java/org/hibernate/metamodel/spi/binding/BasicCollectionBindingTests.java +++ b/hibernate-core/src/test/java/org/hibernate/metamodel/spi/binding/BasicCollectionBindingTests.java @@ -23,6 +23,8 @@ */ package org.hibernate.metamodel.spi.binding; +import java.util.Iterator; + import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -30,13 +32,19 @@ import org.hibernate.metamodel.MetadataSourceProcessingOrder; import org.hibernate.metamodel.MetadataSources; import org.hibernate.metamodel.internal.MetadataImpl; +import org.hibernate.metamodel.spi.relational.Column; +import org.hibernate.metamodel.spi.relational.ForeignKey; +import org.hibernate.metamodel.spi.relational.Identifier; import org.hibernate.service.ServiceRegistryBuilder; import org.hibernate.service.internal.StandardServiceRegistryImpl; import org.hibernate.testing.junit4.BaseUnitTestCase; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; /** * @author Steve Ebersole @@ -77,14 +85,64 @@ private void doTest(MetadataSourceProcessingOrder processingOrder) { assertNotNull( bagBinding ); assertSame( bagBinding, entityBinding.locateAttributeBinding( "theBag" ) ); assertNotNull( bagBinding.getCollectionTable() ); + assertEquals( Identifier.toIdentifier( "`EntityWithBasicCollections_theBag`" ), bagBinding.getCollectionTable().getLogicalName() ); + PluralAttributeKeyBinding bagKeyBinding = bagBinding.getPluralAttributeKeyBinding(); + assertSame( bagBinding, bagKeyBinding.getPluralAttributeBinding() ); + + ForeignKey fkBag = bagKeyBinding.getForeignKey(); + assertNotNull( fkBag ); + assertSame( bagBinding.getCollectionTable(), fkBag.getSourceTable() ); + assertEquals( 1, fkBag.getColumnSpan() ); + Iterator fkBagColumnIterator = fkBag.getColumns().iterator(); + Iterator fkBagSourceColumnIterator = fkBag.getSourceColumns().iterator(); + assertNotNull( fkBagColumnIterator ); + assertNotNull( fkBagSourceColumnIterator ); + assertTrue( fkBagColumnIterator.hasNext() ); + assertTrue( fkBagSourceColumnIterator.hasNext() ); + assertEquals( Identifier.toIdentifier( "`owner_id`" ), fkBagColumnIterator.next().getColumnName() ); + assertEquals( Identifier.toIdentifier( "`owner_id`" ), fkBagSourceColumnIterator.next().getColumnName() ); + assertFalse( fkBagColumnIterator.hasNext() ); + assertFalse( fkBagSourceColumnIterator.hasNext() ); + assertSame( entityBinding.getPrimaryTable(), fkBag.getTargetTable() ); + assertEquals( entityBinding.getPrimaryTable().getPrimaryKey().getColumns(), fkBag.getTargetColumns() ); + assertSame( ForeignKey.ReferentialAction.NO_ACTION, fkBag.getDeleteRule() ); + assertSame( ForeignKey.ReferentialAction.NO_ACTION, fkBag.getUpdateRule() ); + // FK is null because no default FK name is generated until HHH-7092 is fixed + assertNull( fkBag.getName() ); + assertFalse( bagKeyBinding.isInverse() ); assertEquals( PluralAttributeElementNature.BASIC, bagBinding.getPluralAttributeElementBinding().getPluralAttributeElementNature() ); - assertEquals( String.class.getName(), ( (BasicPluralAttributeElementBinding) bagBinding.getPluralAttributeElementBinding() ).getHibernateTypeDescriptor().getJavaTypeName() ); + assertEquals( String.class.getName(), bagBinding.getPluralAttributeElementBinding().getHibernateTypeDescriptor().getJavaTypeName() ); PluralAttributeBinding setBinding = metadata.getCollection( EntityWithBasicCollections.class.getName() + ".theSet" ); assertNotNull( setBinding ); assertSame( setBinding, entityBinding.locateAttributeBinding( "theSet" ) ); assertNotNull( setBinding.getCollectionTable() ); + assertEquals( Identifier.toIdentifier( "`EntityWithBasicCollections_theSet`" ), setBinding.getCollectionTable().getLogicalName() ); + PluralAttributeKeyBinding setKeyBinding = setBinding.getPluralAttributeKeyBinding(); + assertSame( setBinding, setKeyBinding.getPluralAttributeBinding() ); + + ForeignKey fkSet = setKeyBinding.getForeignKey(); + assertNotNull( fkSet ); + assertSame( setBinding.getCollectionTable(), fkSet.getSourceTable() ); + assertEquals( 1, fkSet.getColumnSpan() ); + Iterator fkSetColumnIterator = fkSet.getColumns().iterator(); + Iterator fkSetSourceColumnIterator = fkSet.getSourceColumns().iterator(); + assertNotNull( fkSetColumnIterator ); + assertNotNull( fkSetSourceColumnIterator ); + assertTrue( fkSetColumnIterator.hasNext() ); + assertTrue( fkSetSourceColumnIterator.hasNext() ); + assertEquals( Identifier.toIdentifier( "`pid`" ), fkSetColumnIterator.next().getColumnName() ); + assertEquals( Identifier.toIdentifier( "`pid`" ), fkSetSourceColumnIterator.next().getColumnName() ); + assertFalse( fkSetColumnIterator.hasNext() ); + assertFalse( fkSetSourceColumnIterator.hasNext() ); + assertSame( entityBinding.getPrimaryTable(), fkSet.getTargetTable() ); + assertEquals( entityBinding.getPrimaryTable().getPrimaryKey().getColumns(), fkSet.getTargetColumns() ); + assertSame( ForeignKey.ReferentialAction.NO_ACTION, fkSet.getDeleteRule() ); + assertSame( ForeignKey.ReferentialAction.NO_ACTION, fkSet.getUpdateRule() ); + // FK is null because no default FK name is generated until HHH-7092 is fixed + assertNull( fkSet.getName() ); + assertFalse( setKeyBinding.isInverse() ); assertEquals( PluralAttributeElementNature.BASIC, setBinding.getPluralAttributeElementBinding().getPluralAttributeElementNature() ); - assertEquals( String.class.getName(), ( (BasicPluralAttributeElementBinding) setBinding.getPluralAttributeElementBinding() ).getHibernateTypeDescriptor().getJavaTypeName() ); + assertEquals( String.class.getName(), setBinding.getPluralAttributeElementBinding().getHibernateTypeDescriptor().getJavaTypeName() ); } }