diff --git a/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java b/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java index fd845dcb18..47b461efac 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java @@ -83,6 +83,7 @@ import org.hibernate.context.internal.ManagedSessionContext; import org.hibernate.context.internal.ThreadLocalSessionContext; import org.hibernate.context.spi.CurrentSessionContext; import org.hibernate.dialect.Dialect; +import org.hibernate.dialect.function.SQLFunction; import org.hibernate.dialect.function.SQLFunctionRegistry; import org.hibernate.engine.ResultSetMappingDefinition; import org.hibernate.engine.jdbc.spi.JdbcServices; @@ -187,8 +188,8 @@ public final class SessionFactoryImpl private final transient Map fetchProfiles; private final transient Map imports; private final transient SessionFactoryServiceRegistry serviceRegistry; - private final transient JdbcServices jdbcServices; - private final transient Dialect dialect; + private final transient JdbcServices jdbcServices; + private final transient Dialect dialect; private final transient Settings settings; private final transient Properties properties; private transient SchemaExport schemaExport; @@ -530,9 +531,6 @@ public final class SessionFactoryImpl SessionFactoryObserver observer) throws HibernateException { LOG.debug( "Building session factory" ); - // TODO: remove initialization of final variables; just setting to null to make compiler happy - this.sqlFunctionRegistry = null; - this.sessionFactoryOptions = sessionFactoryOptions; this.properties = createPropertiesFromMap( @@ -553,6 +551,10 @@ public final class SessionFactoryImpl this.jdbcServices = this.serviceRegistry.getService( JdbcServices.class ); this.dialect = this.jdbcServices.getDialect(); + // TODO: get SQL functions from JdbcServices (HHH-6559) + //this.sqlFunctionRegistry = new SQLFunctionRegistry( this.jdbcServices.getSqlFunctions() ); + this.sqlFunctionRegistry = new SQLFunctionRegistry( this.dialect, new HashMap() ); + // TODO: get SQL functions from a new service // this.sqlFunctionRegistry = new SQLFunctionRegistry( getDialect(), cfg.getSqlFunctions() ); diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/binding/EntityBinding.java b/hibernate-core/src/main/java/org/hibernate/metamodel/binding/EntityBinding.java index 1c0552acf6..73fe3f395f 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/binding/EntityBinding.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/binding/EntityBinding.java @@ -53,6 +53,9 @@ import org.hibernate.tuple.entity.EntityTuplizer; * @author Gail Badner */ public class EntityBinding implements AttributeBindingContainer { + private static final String NULL_DISCRIMINATOR_MATCH_VALUE = "null"; + private static final String NOT_NULL_DISCRIMINATOR_MATCH_VALUE = "not null"; + private final EntityBinding superEntityBinding; private final List subEntityBindings = new ArrayList(); private final HierarchyDetails hierarchyDetails; @@ -142,28 +145,70 @@ public class EntityBinding implements AttributeBindingContainer { return subEntityBindings.size() > 0; } - public int getSubEntityBindingSpan() { + public int getSubEntityBindingClosureSpan() { int n = subEntityBindings.size(); for ( EntityBinding subEntityBinding : subEntityBindings ) { - n += subEntityBinding.getSubEntityBindingSpan(); + n += subEntityBinding.getSubEntityBindingClosureSpan(); } return n; } + + /* used for testing */ + public Iterable getDirectSubEntityBindings() { + return subEntityBindings; + } + /** - * Iterate over subclasses in a special 'order', most derived subclasses - * first. + * Returns sub-EntityBinding objects in a special 'order', most derived subclasses + * first. Specifically, the sub-entity bindings follow a depth-first, + * post-order traversal + * + * Note that the returned value excludes this entity binding. + * * @return sub-entity bindings ordered by those entity bindings that are most derived. */ - public Iterable getSubEntityBindingClosure() { - List> subclassIterables = - new ArrayList>( subEntityBindings.size() + 1 ); + public Iterable getPostOrderSubEntityBindingClosure() { + // TODO: why this order? + List> subclassIterables = new ArrayList>( subEntityBindings.size() + 1 ); for ( EntityBinding subEntityBinding : subEntityBindings ) { - subclassIterables.add( subEntityBinding.getSubEntityBindingClosure() ); + Iterable subSubEntityBindings = subEntityBinding.getPostOrderSubEntityBindingClosure(); + if ( subSubEntityBindings.iterator().hasNext() ) { + subclassIterables.add( subSubEntityBindings ); + } + } + if ( ! subEntityBindings.isEmpty() ) { + subclassIterables.add( subEntityBindings ); } - subclassIterables.add( subEntityBindings ); return new JoinedIterable( subclassIterables ); } + /** + * Returns sub-EntityBinding ordered as a depth-first, + * pre-order traversal (a subclass precedes its own subclasses). + * + * Note that the returned value specifically excludes this entity binding. + * + * @return sub-entity bindings ordered as a depth-first, + * pre-order traversal + */ + public Iterable getPreOrderSubEntityBindingClosure() { + return getPreOrderSubEntityBindingClosure( false ); + } + + private Iterable getPreOrderSubEntityBindingClosure(boolean includeThis) { + List> iterables = new ArrayList>(); + if ( includeThis ) { + iterables.add( java.util.Collections.singletonList( this ) ); + } + for ( EntityBinding subEntityBinding : subEntityBindings ) { + Iterable subSubEntityBindingClosure = subEntityBinding.getPreOrderSubEntityBindingClosure( true ); + if ( subSubEntityBindingClosure.iterator().hasNext() ) { + iterables.add( subSubEntityBindingClosure ); + } + } + return new JoinedIterable( iterables ); + } + public Entity getEntity() { return entity; } @@ -212,6 +257,14 @@ public class EntityBinding implements AttributeBindingContainer { return getHierarchyDetails().getVersioningAttributeBinding() != null; } + public boolean isDiscriminatorMatchValueNull() { + return NULL_DISCRIMINATOR_MATCH_VALUE.equals( discriminatorMatchValue ); + } + + public boolean isDiscriminatorMatchValueNotNull() { + return NOT_NULL_DISCRIMINATOR_MATCH_VALUE.equals( discriminatorMatchValue ); + } + public String getDiscriminatorMatchValue() { return discriminatorMatchValue; } @@ -521,4 +574,21 @@ public class EntityBinding implements AttributeBindingContainer { } return iterable; } + + /** + * Gets the attribute bindings for this EntityBinding and all of its + * sub-EntityBinding, starting from the root of the hierarchy; includes + * the identifier and attribute bindings defined as part of a join. + * @return + */ + public Iterable getSubEntityAttributeBindingClosure() { + List> iterables = new ArrayList>(); + iterables.add( getAttributeBindingClosure() ); + for ( EntityBinding subEntityBinding : getPreOrderSubEntityBindingClosure() ) { + // only add attribute bindings declared for the subEntityBinding + iterables.add( subEntityBinding.attributeBindings() ); + // TODO: if EntityBinding.attributeBindings() excludes joined attributes, then they need to be added here + } + return new JoinedIterable( iterables ); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java index 0fbc07c88c..81363df3a6 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java @@ -768,7 +768,6 @@ public abstract class AbstractEntityPersister final EntityBinding entityBinding, final EntityRegionAccessStrategy cacheAccessStrategy, final SessionFactoryImplementor factory) throws HibernateException { - // TODO: Implement! Initializing final fields to make compiler happy this.factory = factory; this.cacheAccessStrategy = cacheAccessStrategy; this.isLazyPropertiesCacheable = @@ -812,8 +811,6 @@ public abstract class AbstractEntityPersister rootTableKeyColumnReaders[i] = col.getReadFragment(); rootTableKeyColumnReaderTemplates[i] = getTemplateFromString( col.getReadFragment(), factory ); } - // TODO: Fix when HHH-6337 is fixed; for now assume entityBinding is the root - // identifierAliases[i] = col.getAlias( factory.getDialect(), entityBinding.getRootEntityBinding().getPrimaryTable() ); identifierAliases[i] = col.getAlias( factory.getDialect() ); i++; } @@ -915,8 +912,8 @@ public abstract class AbstractEntityPersister propertyColumnWriters[i] = colWriters; propertyColumnAliases[i] = colAliases; - propertyColumnUpdateable[i] = propertyColumnInsertability; - propertyColumnInsertable[i] = propertyColumnUpdatability; + propertyColumnUpdateable[i] = propertyColumnUpdatability; + propertyColumnInsertable[i] = propertyColumnInsertability; if ( lazyAvailable && singularAttributeBinding.isLazy() ) { lazyProperties.add( singularAttributeBinding.getAttribute().getName() ); @@ -967,9 +964,7 @@ public abstract class AbstractEntityPersister List columnSelectables = new ArrayList(); List propNullables = new ArrayList(); - // TODO: fix this when EntityBinding.getSubclassAttributeBindingClosure() is working - // for ( AttributeBinding prop : entityBinding.getSubclassAttributeBindingClosure() ) { - for ( AttributeBinding attributeBinding : entityBinding.getAttributeBindingClosure() ) { + for ( AttributeBinding attributeBinding : entityBinding.getSubEntityAttributeBindingClosure() ) { if ( attributeBinding == entityBinding.getHierarchyDetails().getEntityIdentifier().getValueBinding() ) { // entity identifier is not considered a "normal" property continue; diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/SingleTableEntityPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/SingleTableEntityPersister.java index e7a0032a10..9c0c2922a7 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/entity/SingleTableEntityPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/SingleTableEntityPersister.java @@ -466,8 +466,6 @@ public class SingleTableEntityPersister extends AbstractEntityPersister { isNullableTable = new boolean[joinSpan]; keyColumnNames = new String[joinSpan][]; - // TODO: fix when EntityBinhding.getRootEntityBinding() exists (HHH-6337) - //final Table table = entityBinding.getRootEntityBinding().getPrimaryTable(); final TableSpecification table = entityBinding.getPrimaryTable(); qualifiedTableNames[0] = table.getQualifiedName( factory.getDialect() ); isInverseTable[0] = false; @@ -538,15 +536,8 @@ public class SingleTableEntityPersister extends AbstractEntityPersister { // DISCRIMINATOR - // TODO: fix this when can get subclass info from EntityBinding (HHH-6337) - // for now set hasSubclasses to false - //hasSubclasses = entityBinding.hasSubclasses(); - boolean hasSubclasses = false; - - //polymorphic = ! entityBinding.isRoot() || entityBinding.hasSubclasses(); - boolean isPolymorphic = ! entityBinding.isRoot() || hasSubclasses; final Object discriminatorValue; - if ( isPolymorphic ) { + if ( entityBinding.isPolymorphic() ) { SimpleValue discriminatorRelationalValue = entityBinding.getHierarchyDetails().getEntityDiscriminator().getBoundValue(); if ( discriminatorRelationalValue == null ) { throw new MappingException("discriminator mapping required for single table polymorphic persistence"); @@ -569,9 +560,6 @@ public class SingleTableEntityPersister extends AbstractEntityPersister { column.getColumnName().encloseInQuotesIfQuoted( factory.getDialect() ) : column.getReadFragment(); discriminatorColumnReaderTemplate = getTemplateFromColumn( column, factory ); - // TODO: fix this when EntityBinding.getRootEntityBinding() is implemented; - // for now, assume entityBinding is the root - //discriminatorAlias = column.getAlias( factory.getDialect(), entityBinding.getRootEntityBinding().getPrimaryTable ); discriminatorAlias = column.getAlias( factory.getDialect() ); discriminatorFormula = null; discriminatorFormulaTemplate = null; @@ -648,9 +636,7 @@ public class SingleTableEntityPersister extends AbstractEntityPersister { ArrayList formulaJoinedNumbers = new ArrayList(); ArrayList propertyJoinNumbers = new ArrayList(); - // TODO: fix when subclasses are working (HHH-6337) - //for ( AttributeBinding prop : entityBinding.getSubclassAttributeBindingClosure() ) { - for ( AttributeBinding attributeBinding : entityBinding.getAttributeBindingClosure() ) { + for ( AttributeBinding attributeBinding : entityBinding.getSubEntityAttributeBindingClosure() ) { if ( ! attributeBinding.getAttribute().isSingular() ) { continue; } @@ -680,18 +666,41 @@ public class SingleTableEntityPersister extends AbstractEntityPersister { subclassFormulaTableNumberClosure = ArrayHelper.toIntArray(formulaJoinedNumbers); subclassPropertyTableNumberClosure = ArrayHelper.toIntArray(propertyJoinNumbers); - // TODO; fix when subclasses are working (HHH-6337) - //int subclassSpan = entityBinding.getSubclassSpan() + 1; - int subclassSpan = 1; + int subclassSpan = entityBinding.getSubEntityBindingClosureSpan() + 1; subclassClosure = new String[subclassSpan]; subclassClosure[0] = getEntityName(); - if ( isPolymorphic ) { + if ( entityBinding.isPolymorphic() ) { subclassesByDiscriminatorValue.put( discriminatorValue, getEntityName() ); } // SUBCLASSES - - // TODO; fix when subclasses are working (HHH-6337) + if ( entityBinding.isPolymorphic() ) { + int k=1; + for ( EntityBinding subEntityBinding : entityBinding.getPostOrderSubEntityBindingClosure() ) { + subclassClosure[k++] = subEntityBinding.getEntity().getName(); + if ( subEntityBinding.isDiscriminatorMatchValueNull() ) { + subclassesByDiscriminatorValue.put( NULL_DISCRIMINATOR, subEntityBinding.getEntity().getName() ); + } + else if ( subEntityBinding.isDiscriminatorMatchValueNotNull() ) { + subclassesByDiscriminatorValue.put( NOT_NULL_DISCRIMINATOR, subEntityBinding.getEntity().getName() ); + } + else { + try { + DiscriminatorType dtype = (DiscriminatorType) discriminatorType; + subclassesByDiscriminatorValue.put( + dtype.stringToObject( subEntityBinding.getDiscriminatorMatchValue() ), + subEntityBinding.getEntity().getName() + ); + } + catch (ClassCastException cce) { + throw new MappingException("Illegal discriminator type: " + discriminatorType.getName() ); + } + catch (Exception e) { + throw new MappingException("Error parsing discriminator value", e); + } + } + } + } initLockers(); diff --git a/hibernate-core/src/main/java/org/hibernate/tuple/DynamicMapInstantiator.java b/hibernate-core/src/main/java/org/hibernate/tuple/DynamicMapInstantiator.java index 74074e62e3..66627e064d 100755 --- a/hibernate-core/src/main/java/org/hibernate/tuple/DynamicMapInstantiator.java +++ b/hibernate-core/src/main/java/org/hibernate/tuple/DynamicMapInstantiator.java @@ -29,6 +29,7 @@ import java.util.HashSet; import java.util.Iterator; import java.util.Map; import java.util.Set; + import org.hibernate.mapping.PersistentClass; import org.hibernate.metamodel.binding.EntityBinding; @@ -58,14 +59,9 @@ public class DynamicMapInstantiator implements Instantiator { public DynamicMapInstantiator(EntityBinding mappingInfo) { this.entityName = mappingInfo.getEntity().getName(); isInstanceEntityNames.add( entityName ); - // TODO: fix this when can get subclass info from EntityBinding (HHH-6337) - //if ( mappingInfo.hasSubclasses() ) { - // Iterator itr = mappingInfo.getSubclassClosureIterator(); - // while ( itr.hasNext() ) { - // final PersistentClass subclassInfo = ( PersistentClass ) itr.next(); - // isInstanceEntityNames.add( subclassInfo.getEntityName() ); - // } - //} + for ( EntityBinding subEntityBinding : mappingInfo.getPostOrderSubEntityBindingClosure() ) { + isInstanceEntityNames.add( subEntityBinding.getEntity().getName() ); + } } public final Object instantiate(Serializable id) { diff --git a/hibernate-core/src/main/java/org/hibernate/tuple/entity/EntityMetamodel.java b/hibernate-core/src/main/java/org/hibernate/tuple/entity/EntityMetamodel.java index 890b95dc0a..e637036897 100644 --- a/hibernate-core/src/main/java/org/hibernate/tuple/entity/EntityMetamodel.java +++ b/hibernate-core/src/main/java/org/hibernate/tuple/entity/EntityMetamodel.java @@ -360,9 +360,7 @@ public class EntityMetamodel implements Serializable { name = entityBinding.getEntity().getName(); - // TODO: Fix after HHH-6337 is fixed; for now assume entityBinding is the root binding - //rootName = entityBinding.getRootEntityBinding().getName(); - rootName = name; + rootName = entityBinding.getHierarchyDetails().getRootEntityBinding().getEntity().getName(); entityType = sessionFactory.getTypeResolver().getTypeFactory().manyToOne( name ); identifierProperty = PropertyFactory.buildIdentifierProperty( @@ -386,7 +384,6 @@ public class EntityMetamodel implements Serializable { boolean hasLazy = false; // TODO: Fix after HHH-6337 is fixed; for now assume entityBinding is the root binding - //BasicAttributeBinding rootEntityIdentifier = entityBinding.getRootEntityBinding().getEntityIdentifier().getValueBinding(); BasicAttributeBinding rootEntityIdentifier = entityBinding.getHierarchyDetails().getEntityIdentifier().getValueBinding(); // entityBinding.getAttributeClosureSpan() includes the identifier binding; // "properties" here excludes the ID, so subtract 1 if the identifier binding is non-null @@ -540,13 +537,8 @@ public class EntityMetamodel implements Serializable { dynamicUpdate = entityBinding.isDynamicUpdate(); dynamicInsert = entityBinding.isDynamicInsert(); - // TODO: fix this when can get subclass info from EntityBinding (HHH-6337) - // for now set hasSubclasses to false - //hasSubclasses = entityBinding.hasSubclasses(); - hasSubclasses = false; - - //polymorphic = ! entityBinding.isRoot() || entityBinding.hasSubclasses(); - polymorphic = ! entityBinding.isRoot() || hasSubclasses; + hasSubclasses = entityBinding.hasSubEntityBindings(); + polymorphic = entityBinding.isPolymorphic(); explicitPolymorphism = entityBinding.getHierarchyDetails().isExplicitPolymorphism(); inherited = ! entityBinding.isRoot(); @@ -568,24 +560,17 @@ public class EntityMetamodel implements Serializable { hasCollections = foundCollection; hasMutableProperties = foundMutable; - // TODO: fix this when can get subclass info from EntityBinding (HHH-6337) - // TODO: uncomment when it's possible to get subclasses from an EntityBinding - //iter = entityBinding.getSubclassIterator(); - //while ( iter.hasNext() ) { - // subclassEntityNames.add( ( (PersistentClass) iter.next() ).getEntityName() ); - //} + for ( EntityBinding subEntityBinding : entityBinding.getPostOrderSubEntityBindingClosure() ) { + subclassEntityNames.add( subEntityBinding.getEntity().getName() ); + if ( subEntityBinding.getEntity().getClassReference() != null ) { + entityNameByInheritenceClassMap.put( + subEntityBinding.getEntity().getClassReference(), + subEntityBinding.getEntity().getName() ); + } + } subclassEntityNames.add( name ); - if ( mappedClass != null ) { entityNameByInheritenceClassMap.put( mappedClass, name ); - // TODO: uncomment when it's possible to get subclasses from an EntityBinding - // iter = entityBinding.getSubclassIterator(); - // while ( iter.hasNext() ) { - // final EntityBinding subclassEntityBinding = ( EntityBinding ) iter.next(); - // entityNameByInheritenceClassMap.put( - // subclassEntityBinding.getEntity().getPojoEntitySpecifics().getEntityClass(), - // subclassEntityBinding.getEntity().getName() ); - // } } entityMode = hasPojoRepresentation ? EntityMode.POJO : EntityMode.MAP; diff --git a/hibernate-core/src/main/java/org/hibernate/tuple/entity/PojoEntityTuplizer.java b/hibernate-core/src/main/java/org/hibernate/tuple/entity/PojoEntityTuplizer.java index c685de0972..0ebd8b9810 100644 --- a/hibernate-core/src/main/java/org/hibernate/tuple/entity/PojoEntityTuplizer.java +++ b/hibernate-core/src/main/java/org/hibernate/tuple/entity/PojoEntityTuplizer.java @@ -278,21 +278,18 @@ public class PojoEntityTuplizer extends AbstractEntityTuplizer { proxyInterfaces.add( mappedClass ); } - // TODO: fix when it's possible to get subclasses from an EntityBinding - //Iterator subclasses = entityBinding.getSubclassIterator(); - //while ( subclasses.hasNext() ) { - // final Subclass subclass = ( Subclass ) subclasses.next(); - // final Class subclassProxy = subclass.getProxyInterface(); - // final Class subclassClass = subclass.getMappedClass(); - // if ( subclassProxy!=null && !subclassClass.equals( subclassProxy ) ) { - // if ( !subclassProxy.isInterface() ) { - // throw new MappingException( - // "proxy must be either an interface, or the class itself: " + subclass.getEntityName() - // ); - // } - // proxyInterfaces.add( subclassProxy ); - // } - //} + for ( EntityBinding subEntityBinding : entityBinding.getPostOrderSubEntityBindingClosure() ) { + final Class subclassProxy = subEntityBinding.getProxyInterfaceType().getValue(); + final Class subclassClass = subEntityBinding.getClassReference(); + if ( subclassProxy!=null && !subclassClass.equals( subclassProxy ) ) { + if ( ! subclassProxy.isInterface() ) { + throw new MappingException( + "proxy must be either an interface, or the class itself: " + subEntityBinding.getEntity().getName() + ); + } + proxyInterfaces.add( subclassProxy ); + } + } for ( AttributeBinding property : entityBinding.attributeBindings() ) { Method method = getGetter( property ).getMethod(); diff --git a/hibernate-core/src/test/java/org/hibernate/metamodel/source/annotations/entity/InheritanceBindingTest.java b/hibernate-core/src/test/java/org/hibernate/metamodel/source/annotations/entity/InheritanceBindingTest.java index 1aae660774..05130490ce 100644 --- a/hibernate-core/src/test/java/org/hibernate/metamodel/source/annotations/entity/InheritanceBindingTest.java +++ b/hibernate-core/src/test/java/org/hibernate/metamodel/source/annotations/entity/InheritanceBindingTest.java @@ -23,8 +23,10 @@ */ package org.hibernate.metamodel.source.annotations.entity; +import java.util.ArrayList; import java.util.HashSet; import java.util.Iterator; +import java.util.List; import java.util.Set; import javax.persistence.DiscriminatorColumn; import javax.persistence.DiscriminatorType; @@ -121,14 +123,31 @@ public class InheritanceBindingTest extends BaseAnnotationBindingTestCase { assertSame( noInheritanceEntityBinding, getRootEntityBinding( SingleEntity.class ) ); assertFalse( noInheritanceEntityBinding.isPolymorphic() ); assertFalse( noInheritanceEntityBinding.hasSubEntityBindings() ); - assertEquals( 0, noInheritanceEntityBinding.getSubEntityBindingSpan() ); - assertFalse( noInheritanceEntityBinding.getSubEntityBindingClosure().iterator().hasNext() ); - assertEquals( 1, noInheritanceEntityBinding.getAttributeBindingClosureSpan() ); - for ( AttributeBinding attributeBinding : noInheritanceEntityBinding.getAttributeBindingClosure() ) { - if ( attributeBinding == noInheritanceEntityBinding.getHierarchyDetails().getEntityIdentifier().getValueBinding() ) { - continue; - } + assertEquals( 0, noInheritanceEntityBinding.getSubEntityBindingClosureSpan() ); + assertFalse( noInheritanceEntityBinding.getPostOrderSubEntityBindingClosure().iterator().hasNext() ); + assertFalse( noInheritanceEntityBinding.getPreOrderSubEntityBindingClosure().iterator().hasNext() ); + Set directAttributeBindings = new HashSet(); + for ( AttributeBinding attributeBinding : noInheritanceEntityBinding.attributeBindings() ) { + assertTrue( directAttributeBindings.add( attributeBinding ) ); } + assertEquals( 1, directAttributeBindings.size() ); + assertSame( + noInheritanceEntityBinding.getHierarchyDetails().getEntityIdentifier().getValueBinding(), + directAttributeBindings.iterator().next() + ); + assertEquals( 1, noInheritanceEntityBinding.getAttributeBindingClosureSpan() ); + Iterator iterator = noInheritanceEntityBinding.attributeBindings().iterator(); + assertTrue( iterator.hasNext() ); + assertSame( noInheritanceEntityBinding.getHierarchyDetails().getEntityIdentifier().getValueBinding(), iterator.next() ); + assertFalse( iterator.hasNext() ); + iterator = noInheritanceEntityBinding.getAttributeBindingClosure().iterator(); + assertTrue( iterator.hasNext() ); + assertSame( noInheritanceEntityBinding.getHierarchyDetails().getEntityIdentifier().getValueBinding(), iterator.next() ); + assertFalse( iterator.hasNext() ); + iterator = noInheritanceEntityBinding.getSubEntityAttributeBindingClosure().iterator(); + assertTrue( iterator.hasNext() ); + assertSame( noInheritanceEntityBinding.getHierarchyDetails().getEntityIdentifier().getValueBinding(), iterator.next() ); + assertFalse( iterator.hasNext() ); } @Test @@ -151,22 +170,110 @@ public class InheritanceBindingTest extends BaseAnnotationBindingTestCase { assertSame( rootEntityBinding, getRootEntityBinding( RootOfSingleTableInheritance.class ) ); assertTrue( rootEntityBinding.isPolymorphic() ); assertTrue( rootEntityBinding.hasSubEntityBindings() ); - assertEquals( 3, rootEntityBinding.getSubEntityBindingSpan() ); - Set subEntityBindings = new HashSet( ); - for ( EntityBinding subEntityBinding : rootEntityBinding.getSubEntityBindingClosure() ) { - subEntityBindings.add( subEntityBinding ); + Iterator directEntityBindingIterator = rootEntityBinding.getDirectSubEntityBindings().iterator(); + assertTrue( directEntityBindingIterator.hasNext() ); + EntityBinding directSubEntityBinding1 = directEntityBindingIterator.next(); + assertTrue( directEntityBindingIterator.hasNext() ); + EntityBinding directSubEntityBinding2 = directEntityBindingIterator.next(); + assertFalse( directEntityBindingIterator.hasNext() ); + boolean isSubclassEntityBindingFirst = directSubEntityBinding1 == subclassEntityBinding; + if ( isSubclassEntityBindingFirst ) { + assertSame( otherSubclassEntityBinding, directSubEntityBinding2 ); } - assertEquals( 3, subEntityBindings.size() ); - assertTrue( subEntityBindings.contains( subclassEntityBinding ) ); - assertTrue( subEntityBindings.contains( otherSubclassEntityBinding ) ); - assertTrue( subEntityBindings.contains( subclassOfSubclassEntityBinding ) ); + else { + assertSame( otherSubclassEntityBinding, directSubEntityBinding1 ); + assertSame( subclassEntityBinding, directSubEntityBinding2 ); + } + Set directAttributeBindings = new HashSet(); + for ( AttributeBinding attributeBinding : rootEntityBinding.attributeBindings() ) { + assertTrue( directAttributeBindings.add( attributeBinding ) ); + } + assertEquals( 1, directAttributeBindings.size() ); + assertTrue( directAttributeBindings.contains( rootEntityBinding.locateAttributeBinding( "id" ) ) ); assertEquals( 1, rootEntityBinding.getAttributeBindingClosureSpan() ); - Set attributeNames = new HashSet(); + Set attributeBindingClosure = new HashSet(); for ( AttributeBinding attributeBinding : rootEntityBinding.getAttributeBindingClosure() ) { - attributeNames.add( attributeBinding.getAttribute().getName() ); + assertTrue( attributeBindingClosure.add( attributeBinding ) ); } - assertEquals( 1, attributeNames.size() ); - assertTrue( attributeNames.contains( "id" ) ); + assertEquals( 1, attributeBindingClosure.size() ); + assertTrue( attributeBindingClosure.contains( rootEntityBinding.locateAttributeBinding( "id" ) ) ); + Set subAttributeBindings = new HashSet(); + for ( AttributeBinding subAttributeBinding : rootEntityBinding.getSubEntityAttributeBindingClosure() ) { + assertTrue( subAttributeBindings.add( subAttributeBinding ) ); + } + assertEquals( 4, subAttributeBindings.size() ); + assertTrue( subAttributeBindings.contains( rootEntityBinding.locateAttributeBinding( "id" ) ) ); + assertTrue( subAttributeBindings.contains( subclassEntityBinding.locateAttributeBinding( "name" ) ) ); + assertTrue( subAttributeBindings.contains( subclassOfSubclassEntityBinding.locateAttributeBinding( "otherOtherName" ) ) ); + assertTrue( subAttributeBindings.contains( otherSubclassEntityBinding.locateAttributeBinding( "otherName" ) ) ); + } + + @Test + @Resources(annotatedClasses = { + SubclassOfSingleTableInheritance.class, + SingleEntity.class, + RootOfSingleTableInheritance.class, + OtherSubclassOfSingleTableInheritance.class, + SubclassOfSubclassOfSingleTableInheritance.class + }) + public void testPreOrderRootSubEntityClosure() { + EntityBinding rootEntityBinding = getEntityBinding( RootOfSingleTableInheritance.class ); + EntityBinding subclassEntityBinding = getEntityBinding( SubclassOfSingleTableInheritance.class ); + EntityBinding otherSubclassEntityBinding = getEntityBinding( OtherSubclassOfSingleTableInheritance.class ); + EntityBinding subclassOfSubclassEntityBinding = getEntityBinding( SubclassOfSubclassOfSingleTableInheritance.class ); + // need to figure out the order of direct subclasses, since it's indeterminate + Iterator directEntityBindingIterator = rootEntityBinding.getDirectSubEntityBindings().iterator(); + boolean isSubclassEntityBindingFirst = subclassEntityBinding == directEntityBindingIterator.next(); + assertEquals( 3, rootEntityBinding.getSubEntityBindingClosureSpan() ); + Iterator subEntityBindingIterator = rootEntityBinding.getPreOrderSubEntityBindingClosure().iterator(); + assertTrue( subEntityBindingIterator.hasNext() ); + if ( isSubclassEntityBindingFirst ) { + assertSame( subclassEntityBinding, subEntityBindingIterator.next() ); + assertTrue( subEntityBindingIterator.hasNext() ); + assertSame( subclassOfSubclassEntityBinding, subEntityBindingIterator.next() ); + assertTrue( subEntityBindingIterator.hasNext() ); + assertSame( otherSubclassEntityBinding, subEntityBindingIterator.next() ); + } + else { + assertSame( otherSubclassEntityBinding, subEntityBindingIterator.next() ); + assertTrue( subEntityBindingIterator.hasNext() ); + assertSame( subclassEntityBinding, subEntityBindingIterator.next() ); + assertTrue( subEntityBindingIterator.hasNext() ); + assertSame( subclassOfSubclassEntityBinding, subEntityBindingIterator.next() ); + } + assertFalse( subEntityBindingIterator.hasNext() ); + } + + @Test + @Resources(annotatedClasses = { + SubclassOfSingleTableInheritance.class, + SingleEntity.class, + RootOfSingleTableInheritance.class, + OtherSubclassOfSingleTableInheritance.class, + SubclassOfSubclassOfSingleTableInheritance.class + }) + public void testPostOrderRootSubEntityClosure() { + EntityBinding rootEntityBinding = getEntityBinding( RootOfSingleTableInheritance.class ); + EntityBinding subclassEntityBinding = getEntityBinding( SubclassOfSingleTableInheritance.class ); + EntityBinding otherSubclassEntityBinding = getEntityBinding( OtherSubclassOfSingleTableInheritance.class ); + EntityBinding subclassOfSubclassEntityBinding = getEntityBinding( SubclassOfSubclassOfSingleTableInheritance.class ); + // need to figure out the order of direct subclasses, since it's indeterminate + Iterator directEntityBindingIterator = rootEntityBinding.getDirectSubEntityBindings().iterator(); + boolean isSubclassEntityBindingFirst = subclassEntityBinding == directEntityBindingIterator.next(); + assertEquals( 3, rootEntityBinding.getSubEntityBindingClosureSpan() ); + Iterator subEntityBindingIterator = rootEntityBinding.getPostOrderSubEntityBindingClosure().iterator(); + assertTrue( subEntityBindingIterator.hasNext() ); + if ( isSubclassEntityBindingFirst ) { + assertSame( subclassOfSubclassEntityBinding, subEntityBindingIterator.next() ); + assertSame( subclassEntityBinding, subEntityBindingIterator.next() ); + assertSame( otherSubclassEntityBinding, subEntityBindingIterator.next() ); + } + else { + assertSame( subclassOfSubclassEntityBinding, subEntityBindingIterator.next() ); + assertSame( otherSubclassEntityBinding, subEntityBindingIterator.next() ); + assertSame( subclassEntityBinding, subEntityBindingIterator.next() ); + } + assertFalse( subEntityBindingIterator.hasNext() ); } @Test @@ -189,16 +296,30 @@ public class InheritanceBindingTest extends BaseAnnotationBindingTestCase { assertSame( rootEntityBinding, getRootEntityBinding( OtherSubclassOfSingleTableInheritance.class) ); assertTrue( otherSubclassEntityBinding.isPolymorphic() ); assertFalse( otherSubclassEntityBinding.hasSubEntityBindings() ); - assertEquals( 0, otherSubclassEntityBinding.getSubEntityBindingSpan() ); - assertFalse( otherSubclassEntityBinding.getSubEntityBindingClosure().iterator().hasNext() ); - assertEquals( 2, otherSubclassEntityBinding.getAttributeBindingClosureSpan() ); - Set attributeNames = new HashSet(); - for ( AttributeBinding attributeBinding : otherSubclassEntityBinding.getAttributeBindingClosure() ) { - attributeNames.add( attributeBinding.getAttribute().getName() ); + assertEquals( 0, otherSubclassEntityBinding.getSubEntityBindingClosureSpan() ); + assertFalse( otherSubclassEntityBinding.getPostOrderSubEntityBindingClosure().iterator().hasNext() ); + assertFalse( otherSubclassEntityBinding.getPreOrderSubEntityBindingClosure().iterator().hasNext() ); + Set directAttributeBindings = new HashSet(); + for ( AttributeBinding attributeBinding : otherSubclassEntityBinding.attributeBindings() ) { + assertTrue( directAttributeBindings.add( attributeBinding ) ); } - assertEquals( 2, attributeNames.size() ); - assertTrue( attributeNames.contains( "id" ) ); - assertTrue( attributeNames.contains( "otherName" ) ); + assertEquals( 1, directAttributeBindings.size() ); + assertTrue( directAttributeBindings.contains( otherSubclassEntityBinding.locateAttributeBinding( "otherName" ) ) ); + assertEquals( 2, otherSubclassEntityBinding.getAttributeBindingClosureSpan() ); + Set attributeBindingClosure = new HashSet(); + for ( AttributeBinding attributeBinding : otherSubclassEntityBinding.getAttributeBindingClosure() ) { + assertTrue( attributeBindingClosure.add( attributeBinding ) ); + } + assertEquals(2, attributeBindingClosure.size() ); + assertTrue( attributeBindingClosure.contains( rootEntityBinding.locateAttributeBinding( "id" ) ) ); + assertTrue( attributeBindingClosure.contains( otherSubclassEntityBinding.locateAttributeBinding( "otherName" ) ) ); + Set subAttributeBindings = new HashSet(); + for ( AttributeBinding subAttributeBinding : otherSubclassEntityBinding.getSubEntityAttributeBindingClosure() ) { + assertTrue( subAttributeBindings.add( subAttributeBinding ) ); + } + assertEquals( 2, subAttributeBindings.size() ); + assertTrue( subAttributeBindings.contains( rootEntityBinding.locateAttributeBinding( "id" ) ) ); + assertTrue( subAttributeBindings.contains( otherSubclassEntityBinding.locateAttributeBinding( "otherName" ) ) ); } @Test @@ -221,19 +342,37 @@ public class InheritanceBindingTest extends BaseAnnotationBindingTestCase { assertSame( rootEntityBinding, getRootEntityBinding( SubclassOfSingleTableInheritance.class ) ); assertTrue( subclassEntityBinding.isPolymorphic() ); assertTrue( subclassEntityBinding.hasSubEntityBindings() ); - assertEquals( 1, subclassEntityBinding.getSubEntityBindingSpan() ); - Iterator itSubEntityBindings = subclassEntityBinding.getSubEntityBindingClosure().iterator(); + assertEquals( 1, subclassEntityBinding.getSubEntityBindingClosureSpan() ); + Iterator itSubEntityBindings = subclassEntityBinding.getPostOrderSubEntityBindingClosure().iterator(); assertTrue( itSubEntityBindings.hasNext() ); assertSame( subclassOfSubclassEntityBinding, itSubEntityBindings.next() ); assertFalse( itSubEntityBindings.hasNext() ); - assertEquals( 2, subclassEntityBinding.getAttributeBindingClosureSpan() ); - Set attributeNames = new HashSet(); - for ( AttributeBinding attributeBinding : subclassEntityBinding.getAttributeBindingClosure() ) { - attributeNames.add( attributeBinding.getAttribute().getName() ); + itSubEntityBindings = subclassEntityBinding.getPreOrderSubEntityBindingClosure().iterator(); + assertTrue( itSubEntityBindings.hasNext() ); + assertSame( subclassOfSubclassEntityBinding, itSubEntityBindings.next() ); + assertFalse( itSubEntityBindings.hasNext() ); + Set directAttributeBindings = new HashSet(); + for ( AttributeBinding attributeBinding : subclassEntityBinding.attributeBindings() ) { + assertTrue( directAttributeBindings.add( attributeBinding ) ); } - assertEquals( 2, attributeNames.size() ); - assertTrue( attributeNames.contains( "id" ) ); - assertTrue( attributeNames.contains( "name" ) ); + assertEquals( 1, directAttributeBindings.size() ); + assertTrue( directAttributeBindings.contains( subclassEntityBinding.locateAttributeBinding( "name" ) ) ); + assertEquals( 2, subclassEntityBinding.getAttributeBindingClosureSpan() ); + Set attributeBindingClosure = new HashSet(); + for ( AttributeBinding attributeBinding : subclassEntityBinding.getAttributeBindingClosure() ) { + assertTrue( attributeBindingClosure.add( attributeBinding ) ); + } + assertEquals( 2, attributeBindingClosure.size() ); + assertTrue( attributeBindingClosure.contains( rootEntityBinding.locateAttributeBinding( "id" ) ) ); + assertTrue( attributeBindingClosure.contains( subclassEntityBinding.locateAttributeBinding( "name" ) ) ); + Set subAttributeBindings = new HashSet(); + for ( AttributeBinding subAttributeBinding : subclassEntityBinding.getSubEntityAttributeBindingClosure() ) { + assertTrue( subAttributeBindings.add( subAttributeBinding ) ); + } + assertEquals( 3, subAttributeBindings.size() ); + assertTrue( subAttributeBindings.contains( rootEntityBinding.locateAttributeBinding( "id" ) ) ); + assertTrue( subAttributeBindings.contains( subclassEntityBinding.locateAttributeBinding( "name" ) ) ); + assertTrue( subAttributeBindings.contains( subclassOfSubclassEntityBinding.locateAttributeBinding( "otherOtherName" ) ) ); } @Test @@ -256,17 +395,32 @@ public class InheritanceBindingTest extends BaseAnnotationBindingTestCase { assertSame( rootEntityBinding, getRootEntityBinding( SubclassOfSubclassOfSingleTableInheritance.class ) ); assertTrue( subclassOfSubclassEntityBinding.isPolymorphic() ); assertFalse( subclassOfSubclassEntityBinding.hasSubEntityBindings() ); - assertEquals( 0, subclassOfSubclassEntityBinding.getSubEntityBindingSpan() ); - assertFalse( subclassOfSubclassEntityBinding.getSubEntityBindingClosure().iterator().hasNext() ); - assertEquals( 3, subclassOfSubclassEntityBinding.getAttributeBindingClosureSpan() ); - Set attributeNames = new HashSet(); - for ( AttributeBinding attributeBinding : subclassOfSubclassEntityBinding.getAttributeBindingClosure() ) { - attributeNames.add( attributeBinding.getAttribute().getName() ); + assertEquals( 0, subclassOfSubclassEntityBinding.getSubEntityBindingClosureSpan() ); + assertFalse( subclassOfSubclassEntityBinding.getPostOrderSubEntityBindingClosure().iterator().hasNext() ); + assertFalse( subclassOfSubclassEntityBinding.getPreOrderSubEntityBindingClosure().iterator().hasNext() ); + Set directAttributeBindings = new HashSet(); + for ( AttributeBinding attributeBinding : subclassOfSubclassEntityBinding.attributeBindings() ) { + assertTrue( directAttributeBindings.add( attributeBinding ) ); } - assertEquals( 3, attributeNames.size() ); - assertTrue( attributeNames.contains( "id" ) ); - assertTrue( attributeNames.contains( "name" ) ); - assertTrue( attributeNames.contains( "otherOtherName" ) ); + assertEquals( 1, directAttributeBindings.size() ); + assertTrue( directAttributeBindings.contains( subclassOfSubclassEntityBinding.locateAttributeBinding( "otherOtherName" ) ) ); + assertEquals( 3, subclassOfSubclassEntityBinding.getAttributeBindingClosureSpan() ); + Set attributeBindingClosure = new HashSet(); + for ( AttributeBinding attributeBinding : subclassOfSubclassEntityBinding.getAttributeBindingClosure() ) { + assertTrue( attributeBindingClosure.add( attributeBinding ) ); + } + assertEquals( 3, attributeBindingClosure.size() ); + assertTrue( attributeBindingClosure.contains( rootEntityBinding.locateAttributeBinding( "id" ) ) ); + assertTrue( attributeBindingClosure.contains( subclassEntityBinding.locateAttributeBinding( "name" ) ) ); + assertTrue( attributeBindingClosure.contains( subclassOfSubclassEntityBinding.locateAttributeBinding( "otherOtherName" ) ) ); + Set subAttributeBindings = new HashSet(); + for ( AttributeBinding subAttributeBinding : subclassOfSubclassEntityBinding.getSubEntityAttributeBindingClosure() ) { + assertTrue( subAttributeBindings.add( subAttributeBinding ) ); + } + assertEquals( 3, subAttributeBindings.size() ); + assertTrue( subAttributeBindings.contains( rootEntityBinding.locateAttributeBinding( "id" ) ) ); + assertTrue( subAttributeBindings.contains( subclassEntityBinding.locateAttributeBinding( "name" ) ) ); + assertTrue( subAttributeBindings.contains( subclassOfSubclassEntityBinding.locateAttributeBinding( "otherOtherName" ) ) ); } @Test diff --git a/hibernate-core/src/test/java/org/hibernate/test/discriminator/PartTimeEmployee.java b/hibernate-core/src/test/java/org/hibernate/test/discriminator/PartTimeEmployee.java new file mode 100755 index 0000000000..c14a831600 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/discriminator/PartTimeEmployee.java @@ -0,0 +1,21 @@ +//$Id: Employee.java 4373 2004-08-18 09:18:34Z oneovthafew $ +package org.hibernate.test.discriminator; +import java.math.BigDecimal; + +/** + * @author Gail Badner + */ +public class PartTimeEmployee extends Employee { + private String title; + private BigDecimal salary; + private Employee manager; + private int percent; + + public int getPercent() { + return percent; + } + + public void setPercent(int percent) { + this.percent = percent; + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/discriminator/SimpleInheritance.hbm.xml b/hibernate-core/src/test/java/org/hibernate/test/discriminator/SimpleInheritance.hbm.xml new file mode 100644 index 0000000000..8fbd1e6afc --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/discriminator/SimpleInheritance.hbm.xml @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/hibernate-core/src/test/java/org/hibernate/test/discriminator/SimpleInheritanceTest.java b/hibernate-core/src/test/java/org/hibernate/test/discriminator/SimpleInheritanceTest.java new file mode 100644 index 0000000000..fd9960657b --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/discriminator/SimpleInheritanceTest.java @@ -0,0 +1,271 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * Copyright (c) 2006-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.discriminator; + +import java.math.BigDecimal; +import java.util.List; + +import org.junit.Test; + +import org.hibernate.Session; +import org.hibernate.Transaction; +import org.hibernate.cfg.Configuration; +import org.hibernate.criterion.Property; +import org.hibernate.criterion.Restrictions; +import org.hibernate.proxy.HibernateProxy; +import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; + +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 Gavin King + */ +public class SimpleInheritanceTest extends BaseCoreFunctionalTestCase { + public void configure(Configuration cfg) { + super.configure( cfg ); + cfg.setProperty( USE_NEW_METADATA_MAPPINGS, "true"); + } + + @Override + public String[] getMappings() { + return new String[] { "discriminator/SimpleInheritance.hbm.xml" }; + } + + @Test + public void testDiscriminatorSubclass() { + Session s = openSession(); + Transaction t = s.beginTransaction(); + + Employee mark = new Employee(); + mark.setId( 1 ); + mark.setName( "Mark" ); + mark.setTitle( "internal sales" ); + mark.setSex( 'M' ); + + Customer joe = new Customer(); + joe.setId( 2 ); + joe.setName( "Joe" ); + joe.setComments( "Very demanding" ); + joe.setSex( 'M' ); + + Person yomomma = new Person(); + yomomma.setId( 3 ); + yomomma.setName("mum"); + yomomma.setSex('F'); + + s.save(yomomma); + s.save(mark); + s.save(joe); + + assertEquals( s.createQuery("from java.io.Serializable").list().size(), 0 ); + + assertEquals( s.createQuery("from org.hibernate.test.discriminator.Person").list().size(), 3 ); + assertEquals( s.createQuery("from org.hibernate.test.discriminator.Person p where p.class = org.hibernate.test.discriminator.Person").list().size(), 1 ); + assertEquals( s.createQuery("from org.hibernate.test.discriminator.Person p where p.class = org.hibernate.test.discriminator.Customer").list().size(), 1 ); + s.clear(); + + List customers = s.createQuery("from org.hibernate.test.discriminator.Customer").list(); + for ( Object customer : customers ) { + Customer c = (Customer) customer; + assertEquals( "Very demanding", c.getComments() ); + } + assertEquals( customers.size(), 1 ); + s.clear(); + + mark = (Employee) s.get( Employee.class, mark.getId() ); + joe = (Customer) s.get( Customer.class, joe.getId() ); + + s.delete(mark); + s.delete(joe); + s.delete(yomomma); + assertTrue( s.createQuery("from org.hibernate.test.discriminator.Person").list().isEmpty() ); + t.commit(); + s.close(); + } + + @Test + public void testAccessAsIncorrectSubclass() { + Session s = openSession(); + s.beginTransaction(); + Employee e = new Employee(); + e.setId( 4 ); + e.setName( "Steve" ); + e.setSex( 'M' ); + e.setTitle( "grand poobah" ); + s.save( e ); + s.getTransaction().commit(); + s.close(); + + s = openSession(); + s.beginTransaction(); + Customer c = ( Customer ) s.get( Customer.class, e.getId() ); + s.getTransaction().commit(); + s.close(); + assertNull( c ); + + s = openSession(); + s.beginTransaction(); + e = ( Employee ) s.get( Employee.class, e.getId() ); + c = ( Customer ) s.get( Customer.class, e.getId() ); + s.getTransaction().commit(); + s.close(); + assertNotNull( e ); + assertNull( c ); + + s = openSession(); + s.beginTransaction(); + s.delete( e ); + s.getTransaction().commit(); + s.close(); + } + + @Test + public void testQuerySubclassAttribute() { + Session s = openSession(); + Transaction t = s.beginTransaction(); + Person p = new Person(); + p.setId( 5 ); + p.setName("Emmanuel"); + p.setSex('M'); + s.save( p ); + Employee q = new Employee(); + q.setId( 6 ); + q.setName("Steve"); + q.setSex('M'); + q.setTitle("Mr"); + q.setSalary( new BigDecimal(1000) ); + s.save( q ); + + List result = s.createQuery("from org.hibernate.test.discriminator.Person where salary > 100").list(); + assertEquals( result.size(), 1 ); + assertSame( result.get(0), q ); + + result = s.createQuery("from org.hibernate.test.discriminator.Person where salary > 100 or name like 'E%'").list(); + assertEquals( result.size(), 2 ); + + result = s.createCriteria(Person.class) + .add( Property.forName("salary").gt( new BigDecimal(100) ) ) + .list(); + assertEquals( result.size(), 1 ); + assertSame( result.get(0), q ); + + //TODO: make this work: + /*result = s.createQuery("select salary from Person where salary > 100").list(); + assertEquals( result.size(), 1 ); + assertEquals( result.get(0), new BigDecimal(1000) );*/ + + s.delete(p); + s.delete(q); + t.commit(); + s.close(); + } + + @Test + public void testLoadSuperclassProxyPolymorphicAccess() { + Session s = openSession(); + s.beginTransaction(); + Employee e = new Employee(); + e.setId( 7 ); + e.setName( "Steve" ); + e.setSex( 'M' ); + e.setTitle( "grand poobah" ); + s.save( e ); + s.getTransaction().commit(); + s.close(); + + s = openSession(); + s.beginTransaction(); + // load the superclass proxy. + Person pLoad = ( Person ) s.load( Person.class, new Long( e.getId() ) ); + assertTrue( pLoad instanceof HibernateProxy); + Person pGet = ( Person ) s.get( Person.class, e.getId()); + Person pQuery = ( Person ) s.createQuery( "from org.hibernate.test.discriminator.Person where id = :id" ) + .setLong( "id", e.getId() ) + .uniqueResult(); + Person pCriteria = ( Person ) s.createCriteria( Person.class ) + .add( Restrictions.idEq( e.getId() ) ) + .uniqueResult(); + // assert that executing the queries polymorphically returns the same proxy + assertSame( pLoad, pGet ); + assertSame( pLoad, pQuery ); + assertSame( pLoad, pCriteria ); + + // assert that the proxy is not an instance of Employee + assertFalse( pLoad instanceof Employee ); + + s.getTransaction().commit(); + s.close(); + + s = openSession(); + s.beginTransaction(); + s.delete( e ); + s.getTransaction().commit(); + s.close(); + } + + @Test + public void testLoadSuperclassProxyEvictPolymorphicAccess() { + Session s = openSession(); + s.beginTransaction(); + Employee e = new Employee(); + e.setId( 8 ); + e.setName( "Steve" ); + e.setSex( 'M' ); + e.setTitle( "grand poobah" ); + s.save( e ); + s.getTransaction().commit(); + s.close(); + + s = openSession(); + s.beginTransaction(); + // load the superclass proxy. + Person pLoad = ( Person ) s.load( Person.class, new Long( e.getId() ) ); + assertTrue( pLoad instanceof HibernateProxy); + // evict the proxy + s.evict( pLoad ); + Employee pGet = ( Employee ) s.get( Person.class, e.getId() ); + Employee pQuery = ( Employee ) s.createQuery( "from org.hibernate.test.discriminator.Person where id = :id" ) + .setLong( "id", e.getId() ) + .uniqueResult(); + Employee pCriteria = ( Employee ) s.createCriteria( Person.class ) + .add( Restrictions.idEq( e.getId() ) ) + .uniqueResult(); + // assert that executing the queries polymorphically returns the same Employee instance + assertSame( pGet, pQuery ); + assertSame( pGet, pCriteria ); + s.getTransaction().commit(); + s.close(); + + s = openSession(); + s.beginTransaction(); + s.delete( e ); + s.getTransaction().commit(); + s.close(); + } +}