From c7825481724ed479bf4f8e3b1b7ca6b3a784cdc0 Mon Sep 17 00:00:00 2001 From: Steve Ebersole Date: Thu, 9 Aug 2012 13:34:58 -0500 Subject: [PATCH] HHH-7517 - Make sure new metamodel bindings create FK for joined inheritance --- .../hibernate/metamodel/internal/Binder.java | 16 +++- .../annotations/SubclassEntitySourceImpl.java | 10 +-- .../source/hbm/SubclassEntitySourceImpl.java | 9 +++ .../spi/source/SubclassEntitySource.java | 9 ++- .../binding/JoinedSubclassBindingTests.java | 79 +++++++++++++++++++ 5 files changed, 116 insertions(+), 7 deletions(-) create mode 100644 hibernate-core/src/test/java/org/hibernate/metamodel/spi/binding/JoinedSubclassBindingTests.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 1598acf952..eb0cfcd91c 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 @@ -47,6 +47,7 @@ import org.hibernate.id.IdentifierGenerator; import org.hibernate.id.IdentityGenerator; import org.hibernate.id.PersistentIdentifierGenerator; import org.hibernate.id.factory.IdentifierGeneratorFactory; +import org.hibernate.internal.jaxb.mapping.hbm.JaxbJoinedSubclassElement; import org.hibernate.internal.util.ReflectHelper; import org.hibernate.internal.util.StringHelper; import org.hibernate.internal.util.ValueHolder; @@ -1703,9 +1704,22 @@ public class Binder { if ( discriminatorValue != null ) { entityBinding.setDiscriminatorMatchValue( discriminatorValue ); } - } else { + } + else { bindPrimaryTable( entityBinding, entitySource ); } + + if ( inheritanceType == InheritanceType.JOINED && superEntityBinding != null ) { + ForeignKey fk = entityBinding.getPrimaryTable().createForeignKey( + superEntityBinding.getPrimaryTable(), + ( (SubclassEntitySource) entitySource ).getJoinedForeignKeyName() + ); + // explicitly maps to target table pk + for ( Column column : entityBinding.getPrimaryTable().getPrimaryKey().getColumns() ) { + fk.addColumn( column ); + } + } + // todo: deal with joined and unioned subclass bindings // todo: bind fetch profiles // Configure rest of binding diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/annotations/SubclassEntitySourceImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/annotations/SubclassEntitySourceImpl.java index 6fe81b2487..4323e2c033 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/annotations/SubclassEntitySourceImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/annotations/SubclassEntitySourceImpl.java @@ -40,15 +40,15 @@ public class SubclassEntitySourceImpl extends EntitySourceImpl implements Subcla this.container = container; } - /** - * {@inheritDoc} - * - * @see org.hibernate.metamodel.spi.source.SubclassEntitySource#superclassEntitySource() - */ @Override public EntitySource superclassEntitySource() { return container; } + + @Override + public String getJoinedForeignKeyName() { + return null; + } } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/hbm/SubclassEntitySourceImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/hbm/SubclassEntitySourceImpl.java index 93881dd0ec..577f2c7cfc 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/hbm/SubclassEntitySourceImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/source/hbm/SubclassEntitySourceImpl.java @@ -24,6 +24,7 @@ package org.hibernate.metamodel.internal.source.hbm; import org.hibernate.internal.jaxb.mapping.hbm.EntityElement; +import org.hibernate.internal.jaxb.mapping.hbm.JaxbJoinedSubclassElement; import org.hibernate.internal.jaxb.mapping.hbm.JaxbSubclassElement; import org.hibernate.internal.jaxb.mapping.hbm.TableInformationSource; import org.hibernate.metamodel.spi.source.EntitySource; @@ -66,4 +67,12 @@ public class SubclassEntitySourceImpl extends AbstractEntitySourceImpl implement public EntitySource superclassEntitySource() { return container; } + + @Override + public String getJoinedForeignKeyName() { + if ( JaxbJoinedSubclassElement.class.isInstance( entityElement() ) ) { + return ( (JaxbJoinedSubclassElement) entityElement() ).getKey().getForeignKey(); + } + return null; + } } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/source/SubclassEntitySource.java b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/source/SubclassEntitySource.java index d2a3914439..bcff378116 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/spi/source/SubclassEntitySource.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/spi/source/SubclassEntitySource.java @@ -27,9 +27,16 @@ package org.hibernate.metamodel.spi.source; * @author Steve Ebersole */ public interface SubclassEntitySource extends EntitySource { - /** * @return the entity source for the entity that is a superclass of the entity for which this is a source */ EntitySource superclassEntitySource(); + + /** + * Not sure the best way to model this. We need access to the underlying mapping for the joined-subclass + * mapping. Not sure what capabilities jpa/annotations exposes for this. + * + * @return The configured FK name. + */ + public String getJoinedForeignKeyName(); } diff --git a/hibernate-core/src/test/java/org/hibernate/metamodel/spi/binding/JoinedSubclassBindingTests.java b/hibernate-core/src/test/java/org/hibernate/metamodel/spi/binding/JoinedSubclassBindingTests.java new file mode 100644 index 0000000000..a33eaae0cd --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/metamodel/spi/binding/JoinedSubclassBindingTests.java @@ -0,0 +1,79 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2012, 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.spi.binding; + +import javax.persistence.*; +import javax.persistence.InheritanceType; + +import org.hibernate.metamodel.MetadataSources; +import org.hibernate.metamodel.internal.MetadataImpl; +import org.hibernate.service.ServiceRegistryBuilder; +import org.hibernate.service.internal.StandardServiceRegistryImpl; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import org.hibernate.testing.junit4.BaseUnitTestCase; + +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +/** + * @author Steve Ebersole + */ +public class JoinedSubclassBindingTests extends BaseUnitTestCase { + private StandardServiceRegistryImpl serviceRegistry; + + @Before + public void setUp() { + serviceRegistry = (StandardServiceRegistryImpl) new ServiceRegistryBuilder().buildServiceRegistry(); + } + + @After + public void tearDown() { + serviceRegistry.destroy(); + } + + @Test + public void testJoinedSubclassBindingGeneratesForeignKey() { + MetadataSources sources = new MetadataSources( serviceRegistry ); + sources.addAnnotatedClass( Sub.class ); + MetadataImpl metadata = (MetadataImpl) sources.buildMetadata(); + + EntityBinding entityBinding = metadata.getEntityBinding( Sub.class.getName() ); + assertTrue( entityBinding.getPrimaryTable().getForeignKeys().iterator().hasNext() ); + } + + @Entity + @Inheritance( strategy = InheritanceType.JOINED ) + public static class Base { + @Id + private Long id; + } + + @Entity + public static class Sub extends Base { + } +}