From c0de4c7854e45574855c42f295be931d62951b52 Mon Sep 17 00:00:00 2001 From: Steve Ebersole Date: Fri, 20 Aug 2021 13:03:16 -0500 Subject: [PATCH] discriminator work - Handle discriminator as Fetch for entity ResultGraphNodes. This allows us to make the distinction about whether to handle the discriminator as `Class` or as its "underlying" type when selecting it. Fetches return the underlying type. DomainResults return `Class`, or String for entity-named entity mappings --- .../query/HbmResultSetMappingDescriptor.java | 7 +- .../query/SqlResultSetMappingDescriptor.java | 11 +- .../mapping/EntityDiscriminatorMapping.java | 49 ++++- .../AbstractEntityDiscriminatorMapping.java | 27 +-- .../internal/EntityDomainResultBuilder.java | 38 ++-- .../internal/ResultMementoEntityJpa.java | 21 +-- .../internal/ResultMementoEntityStandard.java | 13 +- .../results/BasicValuedFetchBuilder.java | 29 +++ .../CompleteFetchBuilderBasicPart.java | 9 +- .../CompleteResultBuilderEntityJpa.java | 48 ++--- .../CompleteResultBuilderEntityStandard.java | 37 ++-- .../results/complete/EntityResultImpl.java | 29 ++- .../implicit/ImplicitFetchBuilderBasic.java | 3 +- .../entity/AbstractEntityInitializer.java | 10 +- .../entity/AbstractEntityResultGraphNode.java | 17 +- .../internal/EntityFetchJoinedImpl.java | 2 +- .../EntityJoinedFetchInitializer.java | 4 +- .../entity/internal/EntityResultImpl.java | 2 +- .../internal/EntityResultInitializer.java | 3 +- .../EntityResultJoinedSubclassImpl.java | 2 +- .../orm/test/legacy/AbcTransitionTests.java | 178 ++++++++++++++++++ 21 files changed, 400 insertions(+), 139 deletions(-) create mode 100644 hibernate-core/src/main/java/org/hibernate/query/results/BasicValuedFetchBuilder.java create mode 100644 hibernate-core/src/test/java/org/hibernate/orm/test/legacy/AbcTransitionTests.java diff --git a/hibernate-core/src/main/java/org/hibernate/boot/query/HbmResultSetMappingDescriptor.java b/hibernate-core/src/main/java/org/hibernate/boot/query/HbmResultSetMappingDescriptor.java index 60cc7cf93e..0d21c45aed 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/query/HbmResultSetMappingDescriptor.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/query/HbmResultSetMappingDescriptor.java @@ -36,16 +36,15 @@ import org.hibernate.query.NavigablePath; import org.hibernate.query.internal.FetchMementoBasicStandard; import org.hibernate.query.internal.FetchMementoHbmStandard; import org.hibernate.query.internal.FetchMementoHbmStandard.FetchParentMemento; -import org.hibernate.query.internal.ModelPartResultMementoBasicImpl; import org.hibernate.query.internal.NamedResultSetMappingMementoImpl; import org.hibernate.query.internal.ResultMementoBasicStandard; import org.hibernate.query.internal.ResultMementoCollectionStandard; import org.hibernate.query.internal.ResultMementoEntityStandard; import org.hibernate.query.internal.ResultSetMappingResolutionContext; import org.hibernate.query.named.FetchMemento; +import org.hibernate.query.named.FetchMementoBasic; import org.hibernate.query.named.NamedResultSetMappingMemento; import org.hibernate.query.named.ResultMemento; -import org.hibernate.query.named.ResultMementoBasic; import org.hibernate.sql.results.graph.Fetchable; import org.hibernate.sql.results.graph.FetchableContainer; import org.hibernate.type.BasicType; @@ -375,7 +374,7 @@ public class HbmResultSetMappingDescriptor implements NamedResultSetMappingDescr final NavigablePath entityPath = new NavigablePath( entityName ); - final ResultMementoBasic discriminatorMemento; + final FetchMementoBasic discriminatorMemento; if ( discriminatorColumnAlias == null ) { discriminatorMemento = null; } @@ -387,7 +386,7 @@ public class HbmResultSetMappingDescriptor implements NamedResultSetMappingDescr ); } - discriminatorMemento = new ModelPartResultMementoBasicImpl( + discriminatorMemento = new FetchMementoBasicStandard( entityPath.append( EntityDiscriminatorMapping.ROLE_NAME ), entityDescriptor.getDiscriminatorMapping(), discriminatorColumnAlias diff --git a/hibernate-core/src/main/java/org/hibernate/boot/query/SqlResultSetMappingDescriptor.java b/hibernate-core/src/main/java/org/hibernate/boot/query/SqlResultSetMappingDescriptor.java index 393d5d62bc..b0dca7267c 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/query/SqlResultSetMappingDescriptor.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/query/SqlResultSetMappingDescriptor.java @@ -41,13 +41,10 @@ import org.hibernate.query.internal.ResultMementoEntityJpa; import org.hibernate.query.internal.ResultMementoInstantiationStandard; import org.hibernate.query.internal.ResultSetMappingResolutionContext; import org.hibernate.query.named.FetchMemento; -import org.hibernate.query.named.ModelPartResultMementoBasic; +import org.hibernate.query.named.FetchMementoBasic; import org.hibernate.query.named.NamedResultSetMappingMemento; import org.hibernate.query.named.ResultMemento; -import org.hibernate.query.named.ResultMementoBasic; import org.hibernate.query.named.ResultMementoInstantiation.ArgumentMemento; -import org.hibernate.sql.results.graph.Fetchable; -import org.hibernate.sql.results.graph.FetchableContainer; import org.hibernate.type.descriptor.java.JavaTypeDescriptor; /** @@ -275,7 +272,7 @@ public class SqlResultSetMappingDescriptor implements NamedResultSetMappingDescr final RuntimeMetamodels runtimeMetamodels = resolutionContext.getSessionFactory().getRuntimeMetamodels(); final EntityMappingType entityDescriptor = runtimeMetamodels.getEntityMappingType( entityName ); - final ResultMementoBasic discriminatorMemento = resolveDiscriminatorMemento( + final FetchMementoBasic discriminatorMemento = resolveDiscriminatorMemento( entityDescriptor, discriminatorColumn, navigablePath @@ -297,7 +294,7 @@ public class SqlResultSetMappingDescriptor implements NamedResultSetMappingDescr ); } - private static ModelPartResultMementoBasic resolveDiscriminatorMemento( + private static FetchMementoBasic resolveDiscriminatorMemento( EntityMappingType entityMapping, String discriminatorColumn, NavigablePath entityPath) { @@ -310,7 +307,7 @@ public class SqlResultSetMappingDescriptor implements NamedResultSetMappingDescr return null; } - return new ModelPartResultMementoBasicImpl( + return new FetchMementoBasicStandard( entityPath.append( EntityDiscriminatorMapping.ROLE_NAME ), discriminatorMapping, discriminatorColumn diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/EntityDiscriminatorMapping.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/EntityDiscriminatorMapping.java index c765eabd75..42ab9349bc 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/EntityDiscriminatorMapping.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/EntityDiscriminatorMapping.java @@ -6,15 +6,21 @@ */ package org.hibernate.metamodel.mapping; +import org.hibernate.engine.FetchStyle; +import org.hibernate.engine.FetchTiming; import org.hibernate.query.NavigablePath; import org.hibernate.sql.ast.tree.from.TableGroup; import org.hibernate.sql.results.graph.DomainResult; import org.hibernate.sql.results.graph.DomainResultCreationState; +import org.hibernate.sql.results.graph.Fetch; +import org.hibernate.sql.results.graph.FetchOptions; +import org.hibernate.sql.results.graph.FetchParent; +import org.hibernate.sql.results.graph.basic.BasicFetch; /** * @author Steve Ebersole */ -public interface EntityDiscriminatorMapping extends VirtualModelPart, BasicValuedModelPart { +public interface EntityDiscriminatorMapping extends VirtualModelPart, BasicValuedModelPart, FetchOptions { String ROLE_NAME = "{discriminator}"; String LEGACY_HQL_ROLE_NAME = "class"; @@ -27,6 +33,47 @@ public interface EntityDiscriminatorMapping extends VirtualModelPart, BasicValue return ROLE_NAME; } + @Override + default String getFetchableName() { + return getPartName(); + } + + String getConcreteEntityNameForDiscriminatorValue(Object value); + + @Override + BasicFetch generateFetch( + FetchParent fetchParent, + NavigablePath fetchablePath, + FetchTiming fetchTiming, + boolean selected, + String resultVariable, + DomainResultCreationState creationState); + + @Override + default FetchOptions getMappedFetchOptions() { + return this; + } + + @Override + default FetchStyle getStyle() { + return FetchStyle.JOIN; + } + + @Override + default FetchTiming getTiming() { + return FetchTiming.IMMEDIATE; + } + + @Override + default Fetch resolveCircularFetch( + NavigablePath fetchablePath, + FetchParent fetchParent, + FetchTiming fetchTiming, + DomainResultCreationState creationState) { + // can never be circular + return null; + } + DomainResult createUnderlyingDomainResult( NavigablePath navigablePath, TableGroup tableGroup, diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/AbstractEntityDiscriminatorMapping.java b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/AbstractEntityDiscriminatorMapping.java index ee41fdcd0b..355bde89f7 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/AbstractEntityDiscriminatorMapping.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/mapping/internal/AbstractEntityDiscriminatorMapping.java @@ -6,20 +6,18 @@ */ package org.hibernate.metamodel.mapping.internal; -import org.hibernate.engine.FetchStyle; import org.hibernate.engine.FetchTiming; import org.hibernate.metamodel.mapping.EntityDiscriminatorMapping; import org.hibernate.metamodel.mapping.JdbcMapping; import org.hibernate.persister.entity.DiscriminatorType; import org.hibernate.persister.entity.EntityPersister; +import org.hibernate.persister.entity.Loadable; import org.hibernate.query.NavigablePath; import org.hibernate.sql.ast.spi.SqlAstCreationState; import org.hibernate.sql.ast.spi.SqlSelection; import org.hibernate.sql.ast.tree.from.TableGroup; import org.hibernate.sql.results.graph.DomainResult; import org.hibernate.sql.results.graph.DomainResultCreationState; -import org.hibernate.sql.results.graph.Fetch; -import org.hibernate.sql.results.graph.FetchOptions; import org.hibernate.sql.results.graph.FetchParent; import org.hibernate.sql.results.graph.basic.BasicFetch; import org.hibernate.sql.results.graph.basic.BasicResult; @@ -28,7 +26,7 @@ import org.hibernate.type.descriptor.java.JavaTypeDescriptor; /** * @author Andrea Boriero */ -public abstract class AbstractEntityDiscriminatorMapping implements EntityDiscriminatorMapping, FetchOptions { +public abstract class AbstractEntityDiscriminatorMapping implements EntityDiscriminatorMapping { private final EntityPersister entityDescriptor; private final String tableExpression; private final String mappedColumnExpression; @@ -69,23 +67,8 @@ public abstract class AbstractEntityDiscriminatorMapping implements EntityDiscri } @Override - public String getFetchableName() { - return ROLE_NAME; - } - - @Override - public FetchOptions getMappedFetchOptions() { - return this; - } - - @Override - public FetchStyle getStyle() { - return FetchStyle.JOIN; - } - - @Override - public FetchTiming getTiming() { - return FetchTiming.IMMEDIATE; + public String getConcreteEntityNameForDiscriminatorValue(Object value) { + return ( (Loadable) getEntityDescriptor() ).getSubclassForDiscriminatorValue( value ); } @Override @@ -131,7 +114,7 @@ public abstract class AbstractEntityDiscriminatorMapping implements EntityDiscri } @Override - public Fetch generateFetch( + public BasicFetch generateFetch( FetchParent fetchParent, NavigablePath fetchablePath, FetchTiming fetchTiming, diff --git a/hibernate-core/src/main/java/org/hibernate/procedure/internal/EntityDomainResultBuilder.java b/hibernate-core/src/main/java/org/hibernate/procedure/internal/EntityDomainResultBuilder.java index 2ded566602..006de05b10 100644 --- a/hibernate-core/src/main/java/org/hibernate/procedure/internal/EntityDomainResultBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/procedure/internal/EntityDomainResultBuilder.java @@ -12,34 +12,33 @@ import org.hibernate.LockMode; import org.hibernate.metamodel.mapping.EntityDiscriminatorMapping; import org.hibernate.metamodel.mapping.EntityMappingType; import org.hibernate.query.NavigablePath; +import org.hibernate.query.results.BasicValuedFetchBuilder; import org.hibernate.query.results.ResultBuilder; -import org.hibernate.query.results.ResultBuilderBasicValued; import org.hibernate.query.results.complete.EntityResultImpl; import org.hibernate.query.results.dynamic.DynamicFetchBuilderLegacy; -import org.hibernate.query.results.implicit.ImplicitModelPartResultBuilderBasic; +import org.hibernate.query.results.implicit.ImplicitFetchBuilderBasic; import org.hibernate.sql.results.graph.DomainResultCreationState; -import org.hibernate.sql.results.graph.basic.BasicResult; import org.hibernate.sql.results.graph.entity.EntityResult; import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata; /** * @author Christian Beikov */ -public class EntityDomainResultBuilder implements ResultBuilder { +public class EntityDomainResultBuilder implements ResultBuilder { private final NavigablePath navigablePath; private final EntityMappingType entityDescriptor; - private final ResultBuilderBasicValued discriminatorResultBuilder; + private final BasicValuedFetchBuilder discriminatorFetchBuilder; public EntityDomainResultBuilder(EntityMappingType entityDescriptor) { this.entityDescriptor = entityDescriptor; this.navigablePath = new NavigablePath( entityDescriptor.getEntityName() ); final EntityDiscriminatorMapping discriminatorMapping = entityDescriptor.getDiscriminatorMapping(); if ( discriminatorMapping == null ) { - this.discriminatorResultBuilder = null; + this.discriminatorFetchBuilder = null; } else { - this.discriminatorResultBuilder = new ImplicitModelPartResultBuilderBasic( + this.discriminatorFetchBuilder = new ImplicitFetchBuilderBasic( navigablePath, discriminatorMapping ); @@ -52,25 +51,24 @@ public class EntityDomainResultBuilder implements ResultBuilder { int resultPosition, BiFunction legacyFetchResolver, DomainResultCreationState domainResultCreationState) { - final BasicResult discriminatorResult; - if ( discriminatorResultBuilder == null ) { - discriminatorResult = null; - } - else { - discriminatorResult = discriminatorResultBuilder.buildResult( - jdbcResultsMetadata, - resultPosition, - legacyFetchResolver, - domainResultCreationState - ); - } return new EntityResultImpl( navigablePath, entityDescriptor, null, LockMode.NONE, - discriminatorResult, + entityResult -> { + if ( discriminatorFetchBuilder == null ) { + return null; + } + return discriminatorFetchBuilder.buildFetch( + entityResult, + navigablePath.append( EntityDiscriminatorMapping.ROLE_NAME ), + jdbcResultsMetadata, + legacyFetchResolver, + domainResultCreationState + ); + }, domainResultCreationState ); } diff --git a/hibernate-core/src/main/java/org/hibernate/query/internal/ResultMementoEntityJpa.java b/hibernate-core/src/main/java/org/hibernate/query/internal/ResultMementoEntityJpa.java index 065110e8e0..193b5b1671 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/internal/ResultMementoEntityJpa.java +++ b/hibernate-core/src/main/java/org/hibernate/query/internal/ResultMementoEntityJpa.java @@ -15,13 +15,13 @@ import org.hibernate.metamodel.mapping.EntityDiscriminatorMapping; import org.hibernate.metamodel.mapping.EntityMappingType; import org.hibernate.query.NavigablePath; import org.hibernate.query.named.FetchMemento; -import org.hibernate.query.named.ResultMementoBasic; +import org.hibernate.query.named.FetchMementoBasic; import org.hibernate.query.named.ResultMementoEntity; +import org.hibernate.query.results.BasicValuedFetchBuilder; import org.hibernate.query.results.FetchBuilder; -import org.hibernate.query.results.ResultBuilderBasicValued; import org.hibernate.query.results.ResultBuilderEntityValued; import org.hibernate.query.results.complete.CompleteResultBuilderEntityJpa; -import org.hibernate.query.results.implicit.ImplicitModelPartResultBuilderBasic; +import org.hibernate.query.results.implicit.ImplicitFetchBuilderBasic; /** * @author Steve Ebersole @@ -30,14 +30,13 @@ public class ResultMementoEntityJpa implements ResultMementoEntity, FetchMemento private final NavigablePath navigablePath; private final EntityMappingType entityDescriptor; private final LockMode lockMode; -// private final ResultMemento identifierMemento; - private final ResultMementoBasic discriminatorMemento; + private final FetchMementoBasic discriminatorMemento; private final Map explicitFetchMementoMap; public ResultMementoEntityJpa( EntityMappingType entityDescriptor, LockMode lockMode, - ResultMementoBasic discriminatorMemento, + FetchMementoBasic discriminatorMemento, Map explicitFetchMementoMap) { this.navigablePath = new NavigablePath( entityDescriptor.getEntityName() ); this.entityDescriptor = entityDescriptor; @@ -56,17 +55,17 @@ public class ResultMementoEntityJpa implements ResultMementoEntity, FetchMemento Consumer querySpaceConsumer, ResultSetMappingResolutionContext context) { final EntityDiscriminatorMapping discriminatorMapping = entityDescriptor.getDiscriminatorMapping(); - final ResultBuilderBasicValued discriminatorResultBuilder; + final BasicValuedFetchBuilder discriminatorFetchBuilder; if ( discriminatorMapping == null ) { assert discriminatorMemento == null; - discriminatorResultBuilder = null; + discriminatorFetchBuilder = null; } else { if ( discriminatorMemento != null ) { - discriminatorResultBuilder = discriminatorMemento.resolve( querySpaceConsumer, context ); + discriminatorFetchBuilder = (BasicValuedFetchBuilder) discriminatorMemento.resolve( this, querySpaceConsumer, context ); } else { - discriminatorResultBuilder = new ImplicitModelPartResultBuilderBasic( navigablePath, discriminatorMapping ); + discriminatorFetchBuilder = new ImplicitFetchBuilderBasic( navigablePath, discriminatorMapping ); } } @@ -83,7 +82,7 @@ public class ResultMementoEntityJpa implements ResultMementoEntity, FetchMemento navigablePath, entityDescriptor, lockMode, - discriminatorResultBuilder, + discriminatorFetchBuilder, explicitFetchBuilderMap ); } diff --git a/hibernate-core/src/main/java/org/hibernate/query/internal/ResultMementoEntityStandard.java b/hibernate-core/src/main/java/org/hibernate/query/internal/ResultMementoEntityStandard.java index 6552b69859..6d316e90b0 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/internal/ResultMementoEntityStandard.java +++ b/hibernate-core/src/main/java/org/hibernate/query/internal/ResultMementoEntityStandard.java @@ -15,10 +15,10 @@ import org.hibernate.metamodel.mapping.EntityMappingType; import org.hibernate.query.NavigablePath; import org.hibernate.query.QueryLogging; import org.hibernate.query.named.FetchMemento; -import org.hibernate.query.named.ResultMementoBasic; +import org.hibernate.query.named.FetchMementoBasic; import org.hibernate.query.named.ResultMementoEntity; +import org.hibernate.query.results.BasicValuedFetchBuilder; import org.hibernate.query.results.FetchBuilder; -import org.hibernate.query.results.ResultBuilderBasicValued; import org.hibernate.query.results.ResultBuilderEntityValued; import org.hibernate.query.results.complete.CompleteResultBuilderEntityStandard; @@ -30,14 +30,14 @@ public class ResultMementoEntityStandard implements ResultMementoEntity, FetchMe private final NavigablePath navigablePath; private final EntityMappingType entityDescriptor; private final LockMode lockMode; - private final ResultMementoBasic discriminatorMemento; + private final FetchMementoBasic discriminatorMemento; private final Map fetchMementoMap; public ResultMementoEntityStandard( String tableAlias, EntityMappingType entityDescriptor, LockMode lockMode, - ResultMementoBasic discriminatorMemento, + FetchMementoBasic discriminatorMemento, Map fetchMementoMap) { this.tableAlias = tableAlias; this.navigablePath = new NavigablePath( entityDescriptor.getEntityName() ); @@ -61,8 +61,9 @@ public class ResultMementoEntityStandard implements ResultMementoEntity, FetchMe public ResultBuilderEntityValued resolve( Consumer querySpaceConsumer, ResultSetMappingResolutionContext context) { - final ResultBuilderBasicValued discriminatorResultBuilder = discriminatorMemento != null - ? discriminatorMemento.resolve( querySpaceConsumer, context ) + + final BasicValuedFetchBuilder discriminatorResultBuilder = discriminatorMemento != null + ? (BasicValuedFetchBuilder) discriminatorMemento.resolve( this, querySpaceConsumer, context ) : null; final HashMap fetchBuilderMap = new HashMap<>(); diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/BasicValuedFetchBuilder.java b/hibernate-core/src/main/java/org/hibernate/query/results/BasicValuedFetchBuilder.java new file mode 100644 index 0000000000..a77eb43ebd --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/query/results/BasicValuedFetchBuilder.java @@ -0,0 +1,29 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.query.results; + +import java.util.function.BiFunction; + +import org.hibernate.query.NavigablePath; +import org.hibernate.query.results.dynamic.DynamicFetchBuilderLegacy; +import org.hibernate.sql.results.graph.DomainResultCreationState; +import org.hibernate.sql.results.graph.FetchParent; +import org.hibernate.sql.results.graph.basic.BasicFetch; +import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata; + +/** + * @author Steve Ebersole + */ +public interface BasicValuedFetchBuilder extends FetchBuilder { + @Override + BasicFetch buildFetch( + FetchParent parent, + NavigablePath fetchPath, + JdbcValuesMetadata jdbcResultsMetadata, + BiFunction legacyFetchResolver, + DomainResultCreationState domainResultCreationState); +} diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/complete/CompleteFetchBuilderBasicPart.java b/hibernate-core/src/main/java/org/hibernate/query/results/complete/CompleteFetchBuilderBasicPart.java index a9a5848769..b0b6b762bb 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/complete/CompleteFetchBuilderBasicPart.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/complete/CompleteFetchBuilderBasicPart.java @@ -11,6 +11,7 @@ import java.util.function.BiFunction; import org.hibernate.engine.FetchTiming; import org.hibernate.metamodel.mapping.BasicValuedModelPart; import org.hibernate.query.NavigablePath; +import org.hibernate.query.results.BasicValuedFetchBuilder; import org.hibernate.query.results.DomainResultCreationStateImpl; import org.hibernate.query.results.MissingSqlSelectionException; import org.hibernate.query.results.PositionalSelectionsNotAllowedException; @@ -19,8 +20,8 @@ import org.hibernate.query.results.dynamic.DynamicFetchBuilderLegacy; import org.hibernate.sql.ast.tree.from.TableGroup; import org.hibernate.sql.ast.tree.from.TableReference; import org.hibernate.sql.results.graph.DomainResultCreationState; -import org.hibernate.sql.results.graph.Fetch; import org.hibernate.sql.results.graph.FetchParent; +import org.hibernate.sql.results.graph.basic.BasicFetch; import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata; import static org.hibernate.query.results.ResultsHelper.impl; @@ -30,7 +31,7 @@ import static org.hibernate.sql.ast.spi.SqlExpressionResolver.createColumnRefere /** * @author Steve Ebersole */ -public class CompleteFetchBuilderBasicPart implements CompleteFetchBuilder, ModelPartReferenceBasic { +public class CompleteFetchBuilderBasicPart implements CompleteFetchBuilder, BasicValuedFetchBuilder, ModelPartReferenceBasic { private final NavigablePath navigablePath; private final BasicValuedModelPart referencedModelPart; private final String selectionAlias; @@ -55,7 +56,7 @@ public class CompleteFetchBuilderBasicPart implements CompleteFetchBuilder, Mode } @Override - public Fetch buildFetch( + public BasicFetch buildFetch( FetchParent parent, NavigablePath fetchPath, JdbcValuesMetadata jdbcResultsMetadata, @@ -103,7 +104,7 @@ public class CompleteFetchBuilderBasicPart implements CompleteFetchBuilder, Mode processingState -> new SqlSelectionImpl( valuesArrayPosition, referencedModelPart ) ); - return parent.generateFetchableFetch( + return (BasicFetch) parent.generateFetchableFetch( referencedModelPart, fetchPath, FetchTiming.IMMEDIATE, diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/complete/CompleteResultBuilderEntityJpa.java b/hibernate-core/src/main/java/org/hibernate/query/results/complete/CompleteResultBuilderEntityJpa.java index 2eb8b4f50c..cb955904b6 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/complete/CompleteResultBuilderEntityJpa.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/complete/CompleteResultBuilderEntityJpa.java @@ -14,13 +14,12 @@ import org.hibernate.LockMode; import org.hibernate.metamodel.mapping.EntityDiscriminatorMapping; import org.hibernate.metamodel.mapping.EntityMappingType; import org.hibernate.query.NavigablePath; +import org.hibernate.query.results.BasicValuedFetchBuilder; import org.hibernate.query.results.DomainResultCreationStateImpl; import org.hibernate.query.results.FetchBuilder; -import org.hibernate.query.results.ResultBuilderBasicValued; import org.hibernate.query.results.ResultsHelper; import org.hibernate.query.results.dynamic.DynamicFetchBuilderLegacy; import org.hibernate.sql.results.graph.DomainResultCreationState; -import org.hibernate.sql.results.graph.basic.BasicResult; import org.hibernate.sql.results.graph.entity.EntityResult; import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata; @@ -38,20 +37,29 @@ public class CompleteResultBuilderEntityJpa implements CompleteResultBuilderEnti private final NavigablePath navigablePath; private final EntityMappingType entityDescriptor; private final LockMode lockMode; - private final ResultBuilderBasicValued discriminatorResultBuilder; + private final BasicValuedFetchBuilder discriminatorFetchBuilder; private final HashMap explicitFetchBuilderMap; public CompleteResultBuilderEntityJpa( NavigablePath navigablePath, EntityMappingType entityDescriptor, LockMode lockMode, - ResultBuilderBasicValued discriminatorResultBuilder, + BasicValuedFetchBuilder discriminatorFetchBuilder, HashMap explicitFetchBuilderMap) { this.navigablePath = navigablePath; this.entityDescriptor = entityDescriptor; this.lockMode = lockMode; - this.discriminatorResultBuilder = discriminatorResultBuilder; + this.discriminatorFetchBuilder = discriminatorFetchBuilder; this.explicitFetchBuilderMap = explicitFetchBuilderMap; + + if ( entityDescriptor.getDiscriminatorMapping() == null ) { + // not discriminated + assert discriminatorFetchBuilder == null; + } + else { + // discriminated + assert discriminatorFetchBuilder != null; + } } @Override @@ -90,28 +98,24 @@ public class CompleteResultBuilderEntityJpa implements CompleteResultBuilderEnti ) ); - final EntityDiscriminatorMapping discriminatorMapping = entityDescriptor.getDiscriminatorMapping(); - final BasicResult discriminatorResult; - if ( discriminatorMapping == null ) { - assert discriminatorResultBuilder == null; - discriminatorResult = null; - } - else { - assert discriminatorResultBuilder != null; - discriminatorResult = discriminatorResultBuilder.buildResult( - jdbcResultsMetadata, - resultPosition, - legacyFetchResolver, - domainResultCreationState - ); - } - return new EntityResultImpl( navigablePath, entityDescriptor, null, lockMode, - discriminatorResult, + (entityResult) -> { + if ( discriminatorFetchBuilder == null ) { + return null; + } + + return discriminatorFetchBuilder.buildFetch( + entityResult, + navigablePath.append( EntityDiscriminatorMapping.ROLE_NAME ), + jdbcResultsMetadata, + legacyFetchResolver, + domainResultCreationState + ); + }, domainResultCreationState ); } diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/complete/CompleteResultBuilderEntityStandard.java b/hibernate-core/src/main/java/org/hibernate/query/results/complete/CompleteResultBuilderEntityStandard.java index 341872b742..5afdf99fce 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/complete/CompleteResultBuilderEntityStandard.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/complete/CompleteResultBuilderEntityStandard.java @@ -11,16 +11,16 @@ import java.util.function.BiConsumer; import java.util.function.BiFunction; import org.hibernate.LockMode; +import org.hibernate.metamodel.mapping.EntityDiscriminatorMapping; import org.hibernate.metamodel.mapping.EntityMappingType; import org.hibernate.query.NativeQuery; import org.hibernate.query.NavigablePath; +import org.hibernate.query.results.BasicValuedFetchBuilder; import org.hibernate.query.results.DomainResultCreationStateImpl; import org.hibernate.query.results.FetchBuilder; -import org.hibernate.query.results.ResultBuilderBasicValued; import org.hibernate.query.results.ResultsHelper; import org.hibernate.query.results.dynamic.DynamicFetchBuilderLegacy; import org.hibernate.sql.results.graph.DomainResultCreationState; -import org.hibernate.sql.results.graph.basic.BasicResult; import org.hibernate.sql.results.graph.entity.EntityResult; import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata; @@ -32,7 +32,7 @@ public class CompleteResultBuilderEntityStandard implements CompleteResultBuilde private final NavigablePath navigablePath; private final EntityMappingType entityDescriptor; private final LockMode lockMode; - private final ResultBuilderBasicValued discriminatorResultBuilder; + private final BasicValuedFetchBuilder discriminatorFetchBuilder; private final HashMap explicitFetchBuilderMap; public CompleteResultBuilderEntityStandard( @@ -40,13 +40,13 @@ public class CompleteResultBuilderEntityStandard implements CompleteResultBuilde NavigablePath navigablePath, EntityMappingType entityDescriptor, LockMode lockMode, - ResultBuilderBasicValued discriminatorResultBuilder, + BasicValuedFetchBuilder discriminatorFetchBuilder, HashMap explicitFetchBuilderMap) { this.tableAlias = tableAlias; this.navigablePath = navigablePath; this.entityDescriptor = entityDescriptor; this.lockMode = lockMode; - this.discriminatorResultBuilder = discriminatorResultBuilder; + this.discriminatorFetchBuilder = discriminatorFetchBuilder; this.explicitFetchBuilderMap = explicitFetchBuilderMap; } @@ -126,25 +126,24 @@ public class CompleteResultBuilderEntityStandard implements CompleteResultBuilde ) ); - final BasicResult discriminatorResult; - if ( discriminatorResultBuilder != null ) { - discriminatorResult = discriminatorResultBuilder.buildResult( - jdbcResultsMetadata, - resultPosition, - legacyFetchResolver, - domainResultCreationState - ); - } - else { - discriminatorResult = null; - } - return new EntityResultImpl( navigablePath, entityDescriptor, null, lockMode, - discriminatorResult, + (entityResult) -> { + if ( discriminatorFetchBuilder == null ) { + return null; + } + + return discriminatorFetchBuilder.buildFetch( + entityResult, + navigablePath.append( EntityDiscriminatorMapping.ROLE_NAME ), + jdbcResultsMetadata, + legacyFetchResolver, + domainResultCreationState + ); + }, domainResultCreationState ); } diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/complete/EntityResultImpl.java b/hibernate-core/src/main/java/org/hibernate/query/results/complete/EntityResultImpl.java index cc5f39fdfc..050e2eb9fb 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/complete/EntityResultImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/complete/EntityResultImpl.java @@ -7,6 +7,7 @@ package org.hibernate.query.results.complete; import java.util.List; +import java.util.function.Function; import org.hibernate.LockMode; import org.hibernate.internal.util.MutableObject; @@ -22,7 +23,7 @@ import org.hibernate.sql.results.graph.DomainResultAssembler; import org.hibernate.sql.results.graph.DomainResultCreationState; import org.hibernate.sql.results.graph.Fetch; import org.hibernate.sql.results.graph.Fetchable; -import org.hibernate.sql.results.graph.basic.BasicResult; +import org.hibernate.sql.results.graph.basic.BasicFetch; import org.hibernate.sql.results.graph.entity.EntityInitializer; import org.hibernate.sql.results.graph.entity.EntityResult; import org.hibernate.sql.results.graph.entity.internal.EntityAssembler; @@ -36,25 +37,43 @@ public class EntityResultImpl implements EntityResult { private final EntityValuedModelPart entityValuedModelPart; private final DomainResult identifierResult; - private final BasicResult discriminatorResult; + private final Fetch discriminatorFetch; private final List fetches; private final String resultAlias; private final LockMode lockMode; + public EntityResultImpl( + NavigablePath navigablePath, + EntityValuedModelPart entityValuedModelPart, + String resultAlias, + LockMode lockMode, + BasicFetch discriminatorFetch, + DomainResultCreationState creationState) { + this( + navigablePath, + entityValuedModelPart, + resultAlias, + lockMode, + entityResult -> discriminatorFetch, + creationState + ); + } + @SuppressWarnings( { "PointlessNullCheck" } ) public EntityResultImpl( NavigablePath navigablePath, EntityValuedModelPart entityValuedModelPart, String resultAlias, LockMode lockMode, - BasicResult discriminatorResult, + Function discriminatorFetchBuilder, DomainResultCreationState creationState) { this.navigablePath = navigablePath; this.entityValuedModelPart = entityValuedModelPart; this.resultAlias = resultAlias; this.lockMode = lockMode; - this.discriminatorResult = discriminatorResult; + + this.discriminatorFetch = discriminatorFetchBuilder.apply( this ); this.fetches = creationState.visitFetches( this ); @@ -141,7 +160,7 @@ public class EntityResultImpl implements EntityResult { getNavigablePath(), lockMode, identifierResult, - discriminatorResult, + discriminatorFetch, null, null, creationState diff --git a/hibernate-core/src/main/java/org/hibernate/query/results/implicit/ImplicitFetchBuilderBasic.java b/hibernate-core/src/main/java/org/hibernate/query/results/implicit/ImplicitFetchBuilderBasic.java index fba0740fd3..5832a710f8 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/results/implicit/ImplicitFetchBuilderBasic.java +++ b/hibernate-core/src/main/java/org/hibernate/query/results/implicit/ImplicitFetchBuilderBasic.java @@ -13,6 +13,7 @@ import org.hibernate.metamodel.mapping.BasicValuedModelPart; import org.hibernate.metamodel.mapping.ConvertibleModelPart; import org.hibernate.metamodel.model.convert.spi.BasicValueConverter; import org.hibernate.query.NavigablePath; +import org.hibernate.query.results.BasicValuedFetchBuilder; import org.hibernate.query.results.DomainResultCreationStateImpl; import org.hibernate.query.results.ResultsHelper; import org.hibernate.query.results.SqlSelectionImpl; @@ -31,7 +32,7 @@ import static org.hibernate.sql.ast.spi.SqlExpressionResolver.createColumnRefere /** * @author Steve Ebersole */ -public class ImplicitFetchBuilderBasic implements ImplicitFetchBuilder { +public class ImplicitFetchBuilderBasic implements ImplicitFetchBuilder, BasicValuedFetchBuilder { private final NavigablePath fetchPath; private final BasicValuedModelPart fetchable; diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/AbstractEntityInitializer.java b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/AbstractEntityInitializer.java index a147cb5891..9267d0500c 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/AbstractEntityInitializer.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/AbstractEntityInitializer.java @@ -35,7 +35,6 @@ import org.hibernate.metamodel.mapping.AttributeMapping; import org.hibernate.metamodel.mapping.EntityValuedModelPart; import org.hibernate.metamodel.mapping.ModelPart; import org.hibernate.persister.entity.EntityPersister; -import org.hibernate.persister.entity.Loadable; import org.hibernate.proxy.HibernateProxy; import org.hibernate.proxy.LazyInitializer; import org.hibernate.proxy.map.MapProxy; @@ -99,7 +98,7 @@ public abstract class AbstractEntityInitializer extends AbstractFetchParentAcces NavigablePath navigablePath, LockMode lockMode, DomainResult identifierResult, - DomainResult discriminatorResult, + Fetch discriminatorFetch, DomainResult versionResult, DomainResult rowIdResult, AssemblerCreationState creationState) { @@ -170,8 +169,8 @@ public abstract class AbstractEntityInitializer extends AbstractFetchParentAcces this.identifierAssembler = null; } - if ( discriminatorResult != null ) { - discriminatorAssembler = discriminatorResult.createResultAssembler( creationState ); + if ( discriminatorFetch != null ) { + discriminatorAssembler = discriminatorFetch.createAssembler( this, creationState ); } else { discriminatorAssembler = null; @@ -337,7 +336,8 @@ public abstract class AbstractEntityInitializer extends AbstractFetchParentAcces rowProcessingState.getJdbcValuesSourceProcessingState().getProcessingOptions() ); - final String concreteEntityName = ( (Loadable) entityDescriptor.getRootEntityDescriptor() ).getSubclassForDiscriminatorValue( discriminatorValue ); + final String concreteEntityName = entityDescriptor.getDiscriminatorMapping().getConcreteEntityNameForDiscriminatorValue( discriminatorValue ); + if ( concreteEntityName == null ) { return entityDescriptor; } diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/AbstractEntityResultGraphNode.java b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/AbstractEntityResultGraphNode.java index e74f947705..70197b0a80 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/AbstractEntityResultGraphNode.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/AbstractEntityResultGraphNode.java @@ -6,7 +6,7 @@ */ package org.hibernate.sql.results.graph.entity; -import org.hibernate.LockMode; +import org.hibernate.engine.FetchTiming; import org.hibernate.metamodel.mapping.EntityDiscriminatorMapping; import org.hibernate.metamodel.mapping.EntityIdentifierMapping; import org.hibernate.metamodel.mapping.EntityMappingType; @@ -24,6 +24,7 @@ import org.hibernate.sql.ast.tree.from.TableGroup; import org.hibernate.sql.results.graph.AbstractFetchParent; import org.hibernate.sql.results.graph.DomainResult; import org.hibernate.sql.results.graph.DomainResultCreationState; +import org.hibernate.sql.results.graph.Fetch; import org.hibernate.type.descriptor.java.JavaTypeDescriptor; import static org.hibernate.query.results.ResultsHelper.attributeName; @@ -36,7 +37,7 @@ import static org.hibernate.query.results.ResultsHelper.attributeName; public abstract class AbstractEntityResultGraphNode extends AbstractFetchParent implements EntityResultGraphNode { private final EntityValuedModelPart referencedModelPart; private final DomainResult identifierResult; - private final DomainResult discriminatorResult; + private final Fetch discriminatorFetch; private final DomainResult versionResult; private final DomainResult rowIdResult; @@ -104,15 +105,17 @@ public abstract class AbstractEntityResultGraphNode extends AbstractFetchParent final EntityDiscriminatorMapping discriminatorMapping = getDiscriminatorMapping( entityDescriptor, entityTableGroup ); // No need to fetch the discriminator if this type does not have subclasses if ( discriminatorMapping != null && entityDescriptor.getEntityPersister().getEntityMetamodel().hasSubclasses() ) { - discriminatorResult = discriminatorMapping.createUnderlyingDomainResult( + discriminatorFetch = discriminatorMapping.generateFetch( + this, navigablePath.append( EntityDiscriminatorMapping.ROLE_NAME ), - entityTableGroup, + FetchTiming.IMMEDIATE, + true, null, creationState ); } else { - discriminatorResult = null; + discriminatorFetch = null; } final EntityVersionMapping versionDescriptor = entityDescriptor.getVersionMapping(); @@ -205,8 +208,8 @@ public abstract class AbstractEntityResultGraphNode extends AbstractFetchParent return identifierResult; } - public DomainResult getDiscriminatorResult() { - return discriminatorResult; + public Fetch getDiscriminatorFetch() { + return discriminatorFetch; } public DomainResult getVersionResult() { diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/EntityFetchJoinedImpl.java b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/EntityFetchJoinedImpl.java index 891316887b..2cbb856c34 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/EntityFetchJoinedImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/EntityFetchJoinedImpl.java @@ -57,7 +57,7 @@ public class EntityFetchJoinedImpl extends AbstractNonLazyEntityFetch { getNavigablePath(), creationState.determineEffectiveLockMode( sourceAlias ), entityResult.getIdentifierResult(), - entityResult.getDiscriminatorResult(), + entityResult.getDiscriminatorFetch(), entityResult.getVersionResult(), creationState ) diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/EntityJoinedFetchInitializer.java b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/EntityJoinedFetchInitializer.java index 6fa64e6a5c..e2a76212ca 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/EntityJoinedFetchInitializer.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/EntityJoinedFetchInitializer.java @@ -19,6 +19,8 @@ import org.hibernate.metamodel.mapping.internal.ToOneAttributeMapping; import org.hibernate.query.NavigablePath; import org.hibernate.sql.results.graph.AssemblerCreationState; import org.hibernate.sql.results.graph.DomainResult; +import org.hibernate.sql.results.graph.Fetch; +import org.hibernate.sql.results.graph.basic.BasicFetch; import org.hibernate.sql.results.graph.entity.AbstractEntityInitializer; import org.hibernate.sql.results.graph.entity.EntityResultGraphNode; import org.hibernate.sql.results.jdbc.spi.RowProcessingState; @@ -38,7 +40,7 @@ public class EntityJoinedFetchInitializer extends AbstractEntityInitializer { NavigablePath navigablePath, LockMode lockMode, DomainResult identifierResult, - DomainResult discriminatorResult, + Fetch discriminatorResult, DomainResult versionResult, AssemblerCreationState creationState) { super( diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/EntityResultImpl.java b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/EntityResultImpl.java index e86e266c3f..2052db5778 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/EntityResultImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/EntityResultImpl.java @@ -103,7 +103,7 @@ public class EntityResultImpl extends AbstractEntityResultGraphNode implements E getNavigablePath(), getLockMode( creationState ), getIdentifierResult(), - getDiscriminatorResult(), + getDiscriminatorFetch(), getVersionResult(), getRowIdResult(), creationState diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/EntityResultInitializer.java b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/EntityResultInitializer.java index cb2807182d..a529d47460 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/EntityResultInitializer.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/EntityResultInitializer.java @@ -10,6 +10,7 @@ import org.hibernate.LockMode; import org.hibernate.query.NavigablePath; import org.hibernate.sql.results.graph.AssemblerCreationState; import org.hibernate.sql.results.graph.DomainResult; +import org.hibernate.sql.results.graph.Fetch; import org.hibernate.sql.results.graph.entity.AbstractEntityInitializer; import org.hibernate.sql.results.graph.entity.EntityResultGraphNode; @@ -26,7 +27,7 @@ public class EntityResultInitializer extends AbstractEntityInitializer { NavigablePath navigablePath, LockMode lockMode, DomainResult identifierResult, - DomainResult discriminatorResult, + Fetch discriminatorResult, DomainResult versionResult, DomainResult rowIdResult, AssemblerCreationState creationState) { diff --git a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/EntityResultJoinedSubclassImpl.java b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/EntityResultJoinedSubclassImpl.java index 86509f3d03..dd4bfa3306 100644 --- a/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/EntityResultJoinedSubclassImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/sql/results/graph/entity/internal/EntityResultJoinedSubclassImpl.java @@ -40,7 +40,7 @@ public class EntityResultJoinedSubclassImpl extends EntityResultImpl { getNavigablePath(), getLockMode( creationState ), getIdentifierResult(), - getDiscriminatorResult(), + getDiscriminatorFetch(), getVersionResult(), getRowIdResult(), creationState diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/legacy/AbcTransitionTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/legacy/AbcTransitionTests.java new file mode 100644 index 0000000000..cb5ae68b0b --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/legacy/AbcTransitionTests.java @@ -0,0 +1,178 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.orm.test.legacy; + +import javax.persistence.DiscriminatorColumn; +import javax.persistence.DiscriminatorValue; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.Id; +import javax.persistence.Inheritance; +import javax.persistence.InheritanceType; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.Table; + +import org.hibernate.query.criteria.HibernateCriteriaBuilder; +import org.hibernate.query.criteria.JpaCriteriaDelete; + +import org.hibernate.testing.orm.junit.DomainModel; +import org.hibernate.testing.orm.junit.SessionFactory; +import org.hibernate.testing.orm.junit.SessionFactoryScope; +import org.junit.jupiter.api.AfterAll; +import org.junit.jupiter.api.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * @author Steve Ebersole + */ +@DomainModel( + annotatedClasses = { + AbcTransitionTests.EntityA.class, + AbcTransitionTests.EntityB.class, + AbcTransitionTests.EntityC1.class, + AbcTransitionTests.EntityC2.class, + AbcTransitionTests.EntityD.class + + } +) +@SessionFactory +public class AbcTransitionTests { + + /** + * @see ABCTest#testSubclassing + */ + @Test + public void testSubclassing(SessionFactoryScope scope) { + final EntityC1 created = scope.fromTransaction( (session) -> { + final EntityC1 entityC1 = new EntityC1( 1, "some text", "a b name", 1, "a c1 name", "a c1 address" ); + session.save( entityC1 ); + return entityC1; + } ); + + scope.inTransaction( (session) -> { + assertThat( session.createQuery( "from EntityC2 c where 1=1 or 1=1" ).list() ).hasSize( 0 ); + + final Object queried = session.createQuery( "from EntityA e where e.id = :id" ) + .setParameter( "id", created.id ) + .uniqueResult(); + assertThat( queried ).isNotNull(); + assertThat( queried ).isInstanceOf( EntityC1.class ); + + final EntityA loaded = session.get( EntityA.class, created.id ); + assertThat( loaded ).isNotNull(); + assertThat( loaded ).isInstanceOf( EntityC1.class ); + } ); + } + + @AfterAll + public void dropTestData(SessionFactoryScope scope) { + scope.inTransaction( (session) -> { + final HibernateCriteriaBuilder criteriaBuilder = scope.getSessionFactory().getCriteriaBuilder(); + session.createQuery( criteriaBuilder.createCriteriaDelete( EntityA.class ) ).executeUpdate(); + session.createQuery( criteriaBuilder.createCriteriaDelete( EntityD.class ) ).executeUpdate(); + } ); + } + + @Entity( name = "EntityA" ) + @Table( name = "tbl_a" ) + @Inheritance( strategy = InheritanceType.SINGLE_TABLE ) + @DiscriminatorColumn( name = "clazz_discriminata" ) + @DiscriminatorValue( "entity-a" ) + public static class EntityA { + @Id + Integer id; + String text; + + public EntityA() { + } + + public EntityA(Integer id, String text) { + this.id = id; + this.text = text; + } + } + + @Entity( name = "EntityB" ) + @Table( name = "tbl_b" ) + @DiscriminatorValue( "entity-b" ) + public static class EntityB extends EntityA { + String bName; + int count; + + public EntityB() { + } + + public EntityB(int id, String text, String bName, int count) { + super( id, text ); + this.count = count; + } + } + + @Entity( name = "EntityC1" ) + @Table( name = "tbl_c1" ) + @DiscriminatorValue( "entity-c1" ) + public static class EntityC1 extends EntityB { + String cName; + String cAddress; + + public EntityC1() { + } + + public EntityC1(int id, String text, String bName, int count, String name, String address) { + super( id, text, bName, count ); + this.cName = name; + this.cAddress = address; + } + } + + + + + @Entity( name = "EntityC2" ) + @Table( name = "tbl_c2" ) + @DiscriminatorValue( "entity-c2" ) + public static class EntityC2 extends EntityB { + String c2Name; + String c2Address; + + public EntityC2() { + } + + public EntityC2(Integer id, String text, String bName, int count, String name, String address) { + super( id, text, bName, count ); + this.c2Name = name; + this.c2Address = address; + } + } + + @Entity( name = "EntityD" ) + @Table( name = "tbl_d" ) + public static class EntityD { + @Id + Integer id; + String text; + + @ManyToOne( fetch = FetchType.LAZY ) + @JoinColumn( name = "rev_fk" ) + EntityA reverse; + + @ManyToOne( fetch = FetchType.LAZY ) + @JoinColumn( name = "inv_fk" ) + EntityA inverse; + + public EntityD() { + } + + public EntityD(Integer id, String text) { + this.id = id; + this.text = text; + } + } + +}