From 943acc78bccdbae903060e390d99aa1dd1d4e136 Mon Sep 17 00:00:00 2001 From: Matt Drees Date: Wed, 21 May 2014 17:31:30 -0600 Subject: [PATCH] HHH-5764 - Support for multi-level derived ids (cherry picked from commit a32372d7519616036b777e2d457189e77c1ddf6e) --- .../InFlightMetadataCollectorImpl.java | 45 ++++- .../CopyIdentifierComponentSecondPass.java | 182 ++++++++++++------ .../derivedidentities/e3/b2/Dependent.java | 17 ++ .../derivedidentities/e3/b2/DependentId.java | 10 + ...mbeddedIdGrandparentEmbeddedIdDepTest.java | 87 +++++++++ .../derivedidentities/e3/b2/Employee.java | 11 ++ .../derivedidentities/e3/b2/EmployeeId.java | 10 + .../derivedidentities/e3/b2/Policy.java | 18 ++ .../derivedidentities/e3/b2/PolicyId.java | 10 + .../derivedidentities/e3/b3/Dependent.java | 18 ++ .../derivedidentities/e3/b3/DependentId.java | 10 + ...arentEmbeddedIdColumnOverridesDepTest.java | 81 ++++++++ .../derivedidentities/e3/b3/Employee.java | 11 ++ .../derivedidentities/e3/b3/EmployeeId.java | 10 + .../derivedidentities/e3/b3/Policy.java | 19 ++ .../derivedidentities/e3/b3/PolicyId.java | 10 + 16 files changed, 486 insertions(+), 63 deletions(-) create mode 100644 hibernate-core/src/test/java/org/hibernate/test/annotations/derivedidentities/e3/b2/Dependent.java create mode 100644 hibernate-core/src/test/java/org/hibernate/test/annotations/derivedidentities/e3/b2/DependentId.java create mode 100644 hibernate-core/src/test/java/org/hibernate/test/annotations/derivedidentities/e3/b2/DerivedIdentityEmbeddedIdParentEmbeddedIdGrandparentEmbeddedIdDepTest.java create mode 100644 hibernate-core/src/test/java/org/hibernate/test/annotations/derivedidentities/e3/b2/Employee.java create mode 100644 hibernate-core/src/test/java/org/hibernate/test/annotations/derivedidentities/e3/b2/EmployeeId.java create mode 100644 hibernate-core/src/test/java/org/hibernate/test/annotations/derivedidentities/e3/b2/Policy.java create mode 100644 hibernate-core/src/test/java/org/hibernate/test/annotations/derivedidentities/e3/b2/PolicyId.java create mode 100644 hibernate-core/src/test/java/org/hibernate/test/annotations/derivedidentities/e3/b3/Dependent.java create mode 100644 hibernate-core/src/test/java/org/hibernate/test/annotations/derivedidentities/e3/b3/DependentId.java create mode 100644 hibernate-core/src/test/java/org/hibernate/test/annotations/derivedidentities/e3/b3/DerivedIdentityEmbeddedIdParentEmbeddedIdGrandparentEmbeddedIdColumnOverridesDepTest.java create mode 100644 hibernate-core/src/test/java/org/hibernate/test/annotations/derivedidentities/e3/b3/Employee.java create mode 100644 hibernate-core/src/test/java/org/hibernate/test/annotations/derivedidentities/e3/b3/EmployeeId.java create mode 100644 hibernate-core/src/test/java/org/hibernate/test/annotations/derivedidentities/e3/b3/Policy.java create mode 100644 hibernate-core/src/test/java/org/hibernate/test/annotations/derivedidentities/e3/b3/PolicyId.java diff --git a/hibernate-core/src/main/java/org/hibernate/boot/internal/InFlightMetadataCollectorImpl.java b/hibernate-core/src/main/java/org/hibernate/boot/internal/InFlightMetadataCollectorImpl.java index 726c353ec4..bb094bd729 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/internal/InFlightMetadataCollectorImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/internal/InFlightMetadataCollectorImpl.java @@ -1611,7 +1611,8 @@ public class InFlightMetadataCollectorImpl implements InFlightMetadataCollector processSecondPasses( pkDrivenByDefaultMapsIdSecondPassList ); processSecondPasses( setSimpleValueTypeSecondPassList ); - processSecondPasses( copyIdentifierComponentSecondPasList ); + + processCopyIdentifierSecondPassesInOrder(); processFkSecondPassesInOrder(); @@ -1637,6 +1638,14 @@ public class InFlightMetadataCollectorImpl implements InFlightMetadataCollector } } + private void processCopyIdentifierSecondPassesInOrder() { + if ( copyIdentifierComponentSecondPasList == null ) { + return; + } + sortCopyIdentifierComponentSecondPasses(); + processSecondPasses( copyIdentifierComponentSecondPasList ); + } + private void processSecondPasses(ArrayList secondPasses) { if ( secondPasses == null ) { return; @@ -1649,6 +1658,40 @@ public class InFlightMetadataCollectorImpl implements InFlightMetadataCollector secondPasses.clear(); } + private void sortCopyIdentifierComponentSecondPasses() { + + ArrayList sorted = + new ArrayList( copyIdentifierComponentSecondPasList.size() ); + Set toSort = new HashSet(); + toSort.addAll( copyIdentifierComponentSecondPasList ); + topologicalSort( sorted, toSort ); + copyIdentifierComponentSecondPasList = sorted; + } + + /* naive O(n^3) topological sort */ + private void topologicalSort( List sorted, Set toSort ) { + while (!toSort.isEmpty()) { + CopyIdentifierComponentSecondPass independent = null; + + searchForIndependent: + for ( CopyIdentifierComponentSecondPass secondPass : toSort ) { + for ( CopyIdentifierComponentSecondPass other : toSort ) { + if (secondPass.dependentUpon( other )) { + continue searchForIndependent; + } + } + independent = secondPass; + break; + } + if (independent == null) { + throw new MappingException( "cyclic dependency in derived identities" ); + } + toSort.remove( independent ); + sorted.add( independent ); + } + } + + private void processFkSecondPassesInOrder() { if ( fkSecondPassList == null || fkSecondPassList.isEmpty() ) { return; diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/CopyIdentifierComponentSecondPass.java b/hibernate-core/src/main/java/org/hibernate/cfg/CopyIdentifierComponentSecondPass.java index 8bf3e8cad8..11f305650f 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/CopyIdentifierComponentSecondPass.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/CopyIdentifierComponentSecondPass.java @@ -10,6 +10,7 @@ import java.util.HashMap; import java.util.Iterator; import java.util.Locale; import java.util.Map; +import java.util.concurrent.atomic.AtomicInteger; import org.hibernate.AnnotationException; import org.hibernate.AssertionFailure; @@ -75,81 +76,138 @@ public class CopyIdentifierComponentSecondPass implements SecondPass { columnByReferencedName.put( referencedColumnName.toLowerCase(Locale.ROOT), joinColumn ); } //try default column orientation - int index = 0; + AtomicInteger index = new AtomicInteger( 0 ); if ( columnByReferencedName.isEmpty() ) { isExplicitReference = false; for (Ejb3JoinColumn joinColumn : joinColumns) { - columnByReferencedName.put( "" + index, joinColumn ); - index++; + columnByReferencedName.put( "" + index.get(), joinColumn ); + index.getAndIncrement(); } - index = 0; + index.set( 0 ); } while ( properties.hasNext() ) { Property referencedProperty = properties.next(); if ( referencedProperty.isComposite() ) { - throw new AssertionFailure( "Unexpected nested component on the referenced entity when mapping a @MapsId: " - + referencedEntityName); + Property property = createComponentProperty( referencedPersistentClass, isExplicitReference, columnByReferencedName, index, referencedProperty ); + component.addProperty( property ); } else { - Property property = new Property(); - property.setName( referencedProperty.getName() ); - //FIXME set optional? - //property.setOptional( property.isOptional() ); - property.setPersistentClass( component.getOwner() ); - property.setPropertyAccessorName( referencedProperty.getPropertyAccessorName() ); - SimpleValue value = new SimpleValue( buildingContext.getMetadataCollector(), component.getTable() ); - property.setValue( value ); - final SimpleValue referencedValue = (SimpleValue) referencedProperty.getValue(); - value.setTypeName( referencedValue.getTypeName() ); - value.setTypeParameters( referencedValue.getTypeParameters() ); - final Iterator columns = referencedValue.getColumnIterator(); - - if ( joinColumns[0].isNameDeferred() ) { - joinColumns[0].copyReferencedStructureAndCreateDefaultJoinColumns( - referencedPersistentClass, - columns, - value); - } - else { - //FIXME take care of Formula - while ( columns.hasNext() ) { - final Selectable selectable = columns.next(); - if ( ! Column.class.isInstance( selectable ) ) { - log.debug( "Encountered formula definition; skipping" ); - continue; - } - final Column column = (Column) selectable; - final Ejb3JoinColumn joinColumn; - String logicalColumnName = null; - if ( isExplicitReference ) { - final String columnName = column.getName(); - logicalColumnName = buildingContext.getMetadataCollector().getLogicalColumnName( - referencedPersistentClass.getTable(), - columnName - ); - //JPA 2 requires referencedColumnNames to be case insensitive - joinColumn = columnByReferencedName.get( logicalColumnName.toLowerCase(Locale.ROOT ) ); - } - else { - joinColumn = columnByReferencedName.get( "" + index ); - index++; - } - if ( joinColumn == null && ! joinColumns[0].isNameDeferred() ) { - throw new AnnotationException( - isExplicitReference ? - "Unable to find column reference in the @MapsId mapping: " + logicalColumnName : - "Implicit column reference in the @MapsId mapping fails, try to use explicit referenceColumnNames: " + referencedEntityName - ); - } - final String columnName = joinColumn == null || joinColumn.isNameDeferred() ? "tata_" + column.getName() : joinColumn - .getName(); - value.addColumn( new Column( columnName ) ); - column.setValue( value ); - } - } + Property property = createSimpleProperty( referencedPersistentClass, isExplicitReference, columnByReferencedName, index, referencedProperty ); component.addProperty( property ); } } } + + private Property createComponentProperty( + PersistentClass referencedPersistentClass, + boolean isExplicitReference, + Map columnByReferencedName, + AtomicInteger index, + Property referencedProperty ) { + Property property = new Property(); + property.setName( referencedProperty.getName() ); + //FIXME set optional? + //property.setOptional( property.isOptional() ); + property.setPersistentClass( component.getOwner() ); + property.setPropertyAccessorName( referencedProperty.getPropertyAccessorName() ); + Component value = new Component( buildingContext.getMetadataCollector(), component.getOwner() ); + + property.setValue( value ); + final Component referencedValue = (Component) referencedProperty.getValue(); + value.setTypeName( referencedValue.getTypeName() ); + value.setTypeParameters( referencedValue.getTypeParameters() ); + value.setComponentClassName( referencedValue.getComponentClassName() ); + + + Iterator propertyIterator = referencedValue.getPropertyIterator(); + while(propertyIterator.hasNext()) + { + Property referencedComponentProperty = propertyIterator.next(); + + if ( referencedComponentProperty.isComposite() ) { + Property componentProperty = createComponentProperty( referencedValue.getOwner(), isExplicitReference, columnByReferencedName, index, referencedComponentProperty ); + value.addProperty( componentProperty ); + } + else { + Property componentProperty = createSimpleProperty( referencedValue.getOwner(), isExplicitReference, columnByReferencedName, index, referencedComponentProperty ); + value.addProperty( componentProperty ); + } + } + + return property; + } + + + private Property createSimpleProperty( + PersistentClass referencedPersistentClass, + boolean isExplicitReference, + Map columnByReferencedName, + AtomicInteger index, + Property referencedProperty ) { + Property property = new Property(); + property.setName( referencedProperty.getName() ); + //FIXME set optional? + //property.setOptional( property.isOptional() ); + property.setPersistentClass( component.getOwner() ); + property.setPropertyAccessorName( referencedProperty.getPropertyAccessorName() ); + SimpleValue value = new SimpleValue( buildingContext.getMetadataCollector(), component.getTable() ); + property.setValue( value ); + final SimpleValue referencedValue = (SimpleValue) referencedProperty.getValue(); + value.setTypeName( referencedValue.getTypeName() ); + value.setTypeParameters( referencedValue.getTypeParameters() ); + final Iterator columns = referencedValue.getColumnIterator(); + + if ( joinColumns[0].isNameDeferred() ) { + joinColumns[0].copyReferencedStructureAndCreateDefaultJoinColumns( + referencedPersistentClass, + columns, + value); + } + else { + //FIXME take care of Formula + while ( columns.hasNext() ) { + final Selectable selectable = columns.next(); + if ( ! Column.class.isInstance( selectable ) ) { + log.debug( "Encountered formula definition; skipping" ); + continue; + } + final Column column = (Column) selectable; + final Ejb3JoinColumn joinColumn; + String logicalColumnName = null; + if ( isExplicitReference ) { + final String columnName = column.getName(); + logicalColumnName = buildingContext.getMetadataCollector().getLogicalColumnName( + referencedPersistentClass.getTable(), + columnName + ); + //JPA 2 requires referencedColumnNames to be case insensitive + joinColumn = columnByReferencedName.get( logicalColumnName.toLowerCase(Locale.ROOT ) ); + } + else { + joinColumn = columnByReferencedName.get( "" + index.get() ); + index.getAndIncrement(); + } + if ( joinColumn == null && ! joinColumns[0].isNameDeferred() ) { + throw new AnnotationException( + isExplicitReference ? + "Unable to find column reference in the @MapsId mapping: " + logicalColumnName : + "Implicit column reference in the @MapsId mapping fails, try to use explicit referenceColumnNames: " + referencedEntityName + ); + } + final String columnName = joinColumn == null || joinColumn.isNameDeferred() ? "tata_" + column.getName() : joinColumn + .getName(); + value.addColumn( new Column( columnName ) ); + if ( joinColumn != null ) { + joinColumn.linkWithValue( value ); + } + column.setValue( value ); + } + } + return property; + } + + public boolean dependentUpon( CopyIdentifierComponentSecondPass other ) { + return this.referencedEntityName.equals( other.component.getOwner().getEntityName() ); + } } diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/derivedidentities/e3/b2/Dependent.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/derivedidentities/e3/b2/Dependent.java new file mode 100644 index 0000000000..40b82422d0 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/derivedidentities/e3/b2/Dependent.java @@ -0,0 +1,17 @@ +package org.hibernate.test.annotations.derivedidentities.e3.b2; + +import javax.persistence.EmbeddedId; +import javax.persistence.Entity; +import javax.persistence.ManyToOne; +import javax.persistence.MapsId; + +@Entity +public class Dependent { + + @EmbeddedId + DependentId id; + + @MapsId("empPK") + @ManyToOne + Employee emp; +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/derivedidentities/e3/b2/DependentId.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/derivedidentities/e3/b2/DependentId.java new file mode 100644 index 0000000000..aa15aeaa23 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/derivedidentities/e3/b2/DependentId.java @@ -0,0 +1,10 @@ +package org.hibernate.test.annotations.derivedidentities.e3.b2; + +import javax.persistence.Embeddable; +import java.io.Serializable; + +@Embeddable +public class DependentId implements Serializable { + String name; + EmployeeId empPK; +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/derivedidentities/e3/b2/DerivedIdentityEmbeddedIdParentEmbeddedIdGrandparentEmbeddedIdDepTest.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/derivedidentities/e3/b2/DerivedIdentityEmbeddedIdParentEmbeddedIdGrandparentEmbeddedIdDepTest.java new file mode 100644 index 0000000000..2bcd77fbcd --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/derivedidentities/e3/b2/DerivedIdentityEmbeddedIdParentEmbeddedIdGrandparentEmbeddedIdDepTest.java @@ -0,0 +1,87 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2011, 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.test.annotations.derivedidentities.e3.b2; + +import org.hibernate.Session; +import org.hibernate.test.util.SchemaUtil; +import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +/** + * @author Emmanuel Bernard + * @author Matt Drees + */ +public class DerivedIdentityEmbeddedIdParentEmbeddedIdGrandparentEmbeddedIdDepTest extends BaseNonConfigCoreFunctionalTestCase { + @Test + public void testManyToOne() throws Exception { + assertTrue( SchemaUtil.isColumnPresent( "Dependent", "emp_firstName", metadata() ) ); + assertTrue( SchemaUtil.isColumnPresent( "Dependent", "emp_lastName", metadata() ) ); + assertTrue( SchemaUtil.isColumnPresent( "Dependent", "name", metadata() ) ); + assertTrue( !SchemaUtil.isColumnPresent( "Dependent", "firstName", metadata() ) ); + assertTrue( !SchemaUtil.isColumnPresent( "Dependent", "lastName", metadata() ) ); + + assertTrue( SchemaUtil.isColumnPresent( "Policy", "dep_emp_firstName", metadata() ) ); + assertTrue( SchemaUtil.isColumnPresent( "Policy", "dep_emp_lastName", metadata() ) ); + assertTrue( SchemaUtil.isColumnPresent( "Policy", "type", metadata() ) ); + assertTrue( !SchemaUtil.isColumnPresent( "Policy", "firstName", metadata() ) ); + assertTrue( !SchemaUtil.isColumnPresent( "Policy", "lastName", metadata() ) ); + assertTrue( !SchemaUtil.isColumnPresent( "Policy", "name", metadata() ) ); + + + final Employee e = new Employee(); + e.empId = new EmployeeId(); + e.empId.firstName = "Emmanuel"; + e.empId.lastName = "Bernard"; + final Session s = openSession(); + s.getTransaction().begin(); + s.persist( e ); + final Dependent d = new Dependent(); + d.emp = e; + d.id = new DependentId(); + d.id.name = "Doggy"; + s.persist( d ); + Policy p = new Policy(); + p.dep = d; + p.id = new PolicyId(); + p.id.type = "Vet Insurance"; + s.persist( p ); + + s.flush(); + s.clear(); + p = (Policy) s.get( Policy.class, p.id ); + assertNotNull( p.dep ); + assertEquals( e.empId.firstName, p.dep.emp.empId.firstName ); + s.getTransaction().rollback(); + s.close(); + } + + @Override + protected Class[] getAnnotatedClasses() { + return new Class[]{Policy.class, Dependent.class, Employee.class}; + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/derivedidentities/e3/b2/Employee.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/derivedidentities/e3/b2/Employee.java new file mode 100644 index 0000000000..381114776f --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/derivedidentities/e3/b2/Employee.java @@ -0,0 +1,11 @@ +package org.hibernate.test.annotations.derivedidentities.e3.b2; + +import javax.persistence.EmbeddedId; +import javax.persistence.Entity; + + +@Entity +public class Employee { + @EmbeddedId + EmployeeId empId; +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/derivedidentities/e3/b2/EmployeeId.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/derivedidentities/e3/b2/EmployeeId.java new file mode 100644 index 0000000000..a844ddbaf2 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/derivedidentities/e3/b2/EmployeeId.java @@ -0,0 +1,10 @@ +package org.hibernate.test.annotations.derivedidentities.e3.b2; + +import javax.persistence.Embeddable; +import java.io.Serializable; + +@Embeddable +public class EmployeeId implements Serializable { + String firstName; + String lastName; +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/derivedidentities/e3/b2/Policy.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/derivedidentities/e3/b2/Policy.java new file mode 100644 index 0000000000..deb3cdb335 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/derivedidentities/e3/b2/Policy.java @@ -0,0 +1,18 @@ +package org.hibernate.test.annotations.derivedidentities.e3.b2; + +import javax.persistence.EmbeddedId; +import javax.persistence.Entity; +import javax.persistence.ManyToOne; +import javax.persistence.MapsId; + +@Entity +public class Policy { + @EmbeddedId + PolicyId id; + + + @MapsId("depPK") + @ManyToOne + Dependent dep; + +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/derivedidentities/e3/b2/PolicyId.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/derivedidentities/e3/b2/PolicyId.java new file mode 100644 index 0000000000..26d568f6e3 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/derivedidentities/e3/b2/PolicyId.java @@ -0,0 +1,10 @@ +package org.hibernate.test.annotations.derivedidentities.e3.b2; + +import javax.persistence.Embeddable; +import java.io.Serializable; + +@Embeddable +public class PolicyId implements Serializable { + String type; + DependentId depPK; +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/derivedidentities/e3/b3/Dependent.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/derivedidentities/e3/b3/Dependent.java new file mode 100644 index 0000000000..7435c4b54e --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/derivedidentities/e3/b3/Dependent.java @@ -0,0 +1,18 @@ +package org.hibernate.test.annotations.derivedidentities.e3.b3; + +import javax.persistence.*; + +@Entity +public class Dependent { + + @EmbeddedId + DependentId id; + + @JoinColumns({ + @JoinColumn(name = "FIRSTNAME", referencedColumnName = "FIRSTNAME"), + @JoinColumn(name = "LASTNAME", referencedColumnName = "lastName") + }) + @MapsId("empPK") + @ManyToOne + Employee emp; +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/derivedidentities/e3/b3/DependentId.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/derivedidentities/e3/b3/DependentId.java new file mode 100644 index 0000000000..987ca79b5d --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/derivedidentities/e3/b3/DependentId.java @@ -0,0 +1,10 @@ +package org.hibernate.test.annotations.derivedidentities.e3.b3; + +import javax.persistence.Embeddable; +import java.io.Serializable; + +@Embeddable +public class DependentId implements Serializable { + String name; + EmployeeId empPK; +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/derivedidentities/e3/b3/DerivedIdentityEmbeddedIdParentEmbeddedIdGrandparentEmbeddedIdColumnOverridesDepTest.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/derivedidentities/e3/b3/DerivedIdentityEmbeddedIdParentEmbeddedIdGrandparentEmbeddedIdColumnOverridesDepTest.java new file mode 100644 index 0000000000..300d3772eb --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/derivedidentities/e3/b3/DerivedIdentityEmbeddedIdParentEmbeddedIdGrandparentEmbeddedIdColumnOverridesDepTest.java @@ -0,0 +1,81 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2011, 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.test.annotations.derivedidentities.e3.b3; + +import org.hibernate.Session; +import org.hibernate.test.util.SchemaUtil; +import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase; +import org.junit.Test; + +import static org.junit.Assert.*; + +/** + * @author Emmanuel Bernard + * @author Matt Drees + */ +public class DerivedIdentityEmbeddedIdParentEmbeddedIdGrandparentEmbeddedIdColumnOverridesDepTest extends BaseNonConfigCoreFunctionalTestCase { + @Test + public void testManyToOne() throws Exception { + assertTrue( SchemaUtil.isColumnPresent( "Dependent", "FIRSTNAME", metadata() ) ); + assertTrue( SchemaUtil.isColumnPresent( "Dependent", "LASTNAME", metadata() ) ); + assertTrue( SchemaUtil.isColumnPresent( "Dependent", "name", metadata() ) ); + + assertTrue( SchemaUtil.isColumnPresent( "Policy", "FIRSTNAME", metadata() ) ); + assertTrue( SchemaUtil.isColumnPresent( "Policy", "LASTNAME", metadata() ) ); + assertTrue( SchemaUtil.isColumnPresent( "Policy", "NAME", metadata() ) ); + assertTrue( SchemaUtil.isColumnPresent( "Policy", "type", metadata() ) ); + + + final Employee e = new Employee(); + e.empId = new EmployeeId(); + e.empId.firstName = "Emmanuel"; + e.empId.lastName = "Bernard"; + final Session s = openSession(); + s.getTransaction().begin(); + s.persist( e ); + final Dependent d = new Dependent(); + d.emp = e; + d.id = new DependentId(); + d.id.name = "Doggy"; + s.persist( d ); + Policy p = new Policy(); + p.dep = d; + p.id = new PolicyId(); + p.id.type = "Vet Insurance"; + s.persist( p ); + + s.flush(); + s.clear(); + p = (Policy) s.get( Policy.class, p.id ); + assertNotNull( p.dep ); + assertEquals( e.empId.firstName, p.dep.emp.empId.firstName ); + s.getTransaction().rollback(); + s.close(); + } + + @Override + protected Class[] getAnnotatedClasses() { + return new Class[]{Policy.class, Dependent.class, Employee.class}; + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/derivedidentities/e3/b3/Employee.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/derivedidentities/e3/b3/Employee.java new file mode 100644 index 0000000000..00492d1172 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/derivedidentities/e3/b3/Employee.java @@ -0,0 +1,11 @@ +package org.hibernate.test.annotations.derivedidentities.e3.b3; + +import javax.persistence.EmbeddedId; +import javax.persistence.Entity; + + +@Entity +public class Employee { + @EmbeddedId + EmployeeId empId; +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/derivedidentities/e3/b3/EmployeeId.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/derivedidentities/e3/b3/EmployeeId.java new file mode 100644 index 0000000000..270e2106d4 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/derivedidentities/e3/b3/EmployeeId.java @@ -0,0 +1,10 @@ +package org.hibernate.test.annotations.derivedidentities.e3.b3; + +import javax.persistence.Embeddable; +import java.io.Serializable; + +@Embeddable +public class EmployeeId implements Serializable { + String firstName; + String lastName; +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/derivedidentities/e3/b3/Policy.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/derivedidentities/e3/b3/Policy.java new file mode 100644 index 0000000000..565c0ba144 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/derivedidentities/e3/b3/Policy.java @@ -0,0 +1,19 @@ +package org.hibernate.test.annotations.derivedidentities.e3.b3; + +import javax.persistence.*; + +@Entity +public class Policy { + @EmbeddedId + PolicyId id; + + @JoinColumns({ + @JoinColumn(name = "FIRSTNAME", referencedColumnName = "FIRSTNAME"), + @JoinColumn(name = "LASTNAME", referencedColumnName = "lastName"), + @JoinColumn(name = "NAME", referencedColumnName = "Name") + }) + @MapsId("depPK") + @ManyToOne + Dependent dep; + +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/derivedidentities/e3/b3/PolicyId.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/derivedidentities/e3/b3/PolicyId.java new file mode 100644 index 0000000000..90e4b242c5 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/derivedidentities/e3/b3/PolicyId.java @@ -0,0 +1,10 @@ +package org.hibernate.test.annotations.derivedidentities.e3.b3; + +import javax.persistence.Embeddable; +import java.io.Serializable; + +@Embeddable +public class PolicyId implements Serializable { + String type; + DependentId depPK; +}