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
This commit is contained in:
Steve Ebersole 2021-08-20 13:03:16 -05:00
parent 83ac9d5d3d
commit c0de4c7854
21 changed files with 400 additions and 139 deletions

View File

@ -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

View File

@ -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

View File

@ -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;
}
<T> DomainResult<T> createUnderlyingDomainResult(
NavigablePath navigablePath,
TableGroup tableGroup,

View File

@ -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,

View File

@ -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<T> 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<T> implements ResultBuilder {
int resultPosition,
BiFunction<String, String, DynamicFetchBuilderLegacy> 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
);
}

View File

@ -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<String, FetchMemento> explicitFetchMementoMap;
public ResultMementoEntityJpa(
EntityMappingType entityDescriptor,
LockMode lockMode,
ResultMementoBasic discriminatorMemento,
FetchMementoBasic discriminatorMemento,
Map<String, FetchMemento> explicitFetchMementoMap) {
this.navigablePath = new NavigablePath( entityDescriptor.getEntityName() );
this.entityDescriptor = entityDescriptor;
@ -56,17 +55,17 @@ public class ResultMementoEntityJpa implements ResultMementoEntity, FetchMemento
Consumer<String> 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
);
}

View File

@ -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<String, FetchMemento> fetchMementoMap;
public ResultMementoEntityStandard(
String tableAlias,
EntityMappingType entityDescriptor,
LockMode lockMode,
ResultMementoBasic discriminatorMemento,
FetchMementoBasic discriminatorMemento,
Map<String, FetchMemento> fetchMementoMap) {
this.tableAlias = tableAlias;
this.navigablePath = new NavigablePath( entityDescriptor.getEntityName() );
@ -61,8 +61,9 @@ public class ResultMementoEntityStandard implements ResultMementoEntity, FetchMe
public ResultBuilderEntityValued resolve(
Consumer<String> 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<String, FetchBuilder> fetchBuilderMap = new HashMap<>();

View File

@ -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<String, String, DynamicFetchBuilderLegacy> legacyFetchResolver,
DomainResultCreationState domainResultCreationState);
}

View File

@ -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,

View File

@ -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<String, FetchBuilder> explicitFetchBuilderMap;
public CompleteResultBuilderEntityJpa(
NavigablePath navigablePath,
EntityMappingType entityDescriptor,
LockMode lockMode,
ResultBuilderBasicValued discriminatorResultBuilder,
BasicValuedFetchBuilder discriminatorFetchBuilder,
HashMap<String, FetchBuilder> 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
);
}

View File

@ -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<String, FetchBuilder> explicitFetchBuilderMap;
public CompleteResultBuilderEntityStandard(
@ -40,13 +40,13 @@ public class CompleteResultBuilderEntityStandard implements CompleteResultBuilde
NavigablePath navigablePath,
EntityMappingType entityDescriptor,
LockMode lockMode,
ResultBuilderBasicValued discriminatorResultBuilder,
BasicValuedFetchBuilder discriminatorFetchBuilder,
HashMap<String, FetchBuilder> 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
);
}

View File

@ -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<Fetch> 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<EntityResultImpl, BasicFetch> 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

View File

@ -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;

View File

@ -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<Object> 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;
}

View File

@ -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<Object> 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() {

View File

@ -57,7 +57,7 @@ public class EntityFetchJoinedImpl extends AbstractNonLazyEntityFetch {
getNavigablePath(),
creationState.determineEffectiveLockMode( sourceAlias ),
entityResult.getIdentifierResult(),
entityResult.getDiscriminatorResult(),
entityResult.getDiscriminatorFetch(),
entityResult.getVersionResult(),
creationState
)

View File

@ -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(

View File

@ -103,7 +103,7 @@ public class EntityResultImpl extends AbstractEntityResultGraphNode implements E
getNavigablePath(),
getLockMode( creationState ),
getIdentifierResult(),
getDiscriminatorResult(),
getDiscriminatorFetch(),
getVersionResult(),
getRowIdResult(),
creationState

View File

@ -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<Object> rowIdResult,
AssemblerCreationState creationState) {

View File

@ -40,7 +40,7 @@ public class EntityResultJoinedSubclassImpl extends EntityResultImpl {
getNavigablePath(),
getLockMode( creationState ),
getIdentifierResult(),
getDiscriminatorResult(),
getDiscriminatorFetch(),
getVersionResult(),
getRowIdResult(),
creationState

View File

@ -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;
}
}
}