HHH-15883 - Expose MappingMetamodel via unwrap from SessionFactory

HHH-15884 - Clean-up EntityDiscriminatorMapping for API uses
This commit is contained in:
Steve Ebersole 2022-12-15 12:29:17 -06:00
parent 49c096f146
commit 2e0b4b3558
19 changed files with 370 additions and 129 deletions

View File

@ -83,13 +83,22 @@ public class LoadQueryInfluencers implements Serializable {
}
}
/**
* Fetch-profile to apply, if one, when building the result-graph
* for cascade fetching - for example, the result-graph used when
* handling a {@linkplain org.hibernate.Session#merge merge} to
* immediately load additional based on {@linkplain jakarta.persistence.CascadeType#MERGE}
*/
public CascadingFetchProfile getEnabledCascadingFetchProfile() {
return enabledCascadingFetchProfile;
}
/**
* Set the effective {@linkplain #getEnabledCascadingFetchProfile() cascading fetch-profile}
*/
public void setEnabledCascadingFetchProfile(CascadingFetchProfile enabledCascadingFetchProfile) {
if ( sessionFactory == null ) {
// thats the signal that this is the immutable, context-less
// that's the signal that this is the immutable, context-less
// variety
throw new IllegalStateException( "Cannot modify context-less LoadQueryInfluencers" );
}

View File

@ -25,14 +25,6 @@ import java.util.function.Supplier;
import javax.naming.Reference;
import javax.naming.StringRefAddr;
import jakarta.persistence.Cache;
import jakarta.persistence.EntityGraph;
import jakarta.persistence.EntityManagerFactory;
import jakarta.persistence.PersistenceException;
import jakarta.persistence.PersistenceUnitUtil;
import jakarta.persistence.Query;
import jakarta.persistence.SynchronizationType;
import org.hibernate.CustomEntityDirtinessStrategy;
import org.hibernate.EntityNameResolver;
import org.hibernate.FlushMode;
@ -64,7 +56,6 @@ import org.hibernate.context.internal.ManagedSessionContext;
import org.hibernate.context.internal.ThreadLocalSessionContext;
import org.hibernate.context.spi.CurrentSessionContext;
import org.hibernate.context.spi.CurrentTenantIdentifierResolver;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.config.spi.ConfigurationService;
import org.hibernate.engine.jdbc.connections.spi.JdbcConnectionAccess;
import org.hibernate.engine.jdbc.spi.JdbcServices;
@ -78,6 +69,7 @@ import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.engine.transaction.jta.platform.spi.JtaPlatform;
import org.hibernate.event.spi.EventEngine;
import org.hibernate.generator.Generator;
import org.hibernate.graph.spi.RootGraphImplementor;
import org.hibernate.id.IdentifierGenerator;
import org.hibernate.id.factory.IdentifierGeneratorFactory;
@ -91,11 +83,10 @@ import org.hibernate.mapping.PersistentClass;
import org.hibernate.mapping.RootClass;
import org.hibernate.metadata.CollectionMetadata;
import org.hibernate.metamodel.internal.RuntimeMetamodelsImpl;
import org.hibernate.metamodel.model.domain.spi.JpaMetamodelImplementor;
import org.hibernate.metamodel.spi.RuntimeMetamodelsImplementor;
import org.hibernate.query.BindableType;
import org.hibernate.metamodel.model.domain.internal.MappingMetamodelImpl;
import org.hibernate.metamodel.model.domain.spi.JpaMetamodelImplementor;
import org.hibernate.metamodel.spi.MetamodelImplementor;
import org.hibernate.metamodel.spi.RuntimeMetamodelsImplementor;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.persister.entity.Loadable;
import org.hibernate.persister.entity.SessionFactoryBasedWrapperOptions;
@ -103,6 +94,7 @@ import org.hibernate.procedure.spi.ProcedureCallImplementor;
import org.hibernate.proxy.EntityNotFoundDelegate;
import org.hibernate.proxy.HibernateProxy;
import org.hibernate.proxy.LazyInitializer;
import org.hibernate.query.BindableType;
import org.hibernate.query.QueryLogging;
import org.hibernate.query.hql.spi.SqmQueryImplementor;
import org.hibernate.query.named.NamedObjectRepository;
@ -124,13 +116,18 @@ import org.hibernate.service.spi.SessionFactoryServiceRegistryFactory;
import org.hibernate.stat.spi.StatisticsImplementor;
import org.hibernate.tool.schema.spi.DelayedDropAction;
import org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator;
import org.hibernate.generator.Generator;
import org.hibernate.type.Type;
import org.hibernate.type.descriptor.WrapperOptions;
import org.hibernate.type.spi.TypeConfiguration;
import org.jboss.logging.Logger;
import jakarta.persistence.EntityGraph;
import jakarta.persistence.PersistenceException;
import jakarta.persistence.PersistenceUnitUtil;
import jakarta.persistence.Query;
import jakarta.persistence.SynchronizationType;
import static java.util.Collections.unmodifiableSet;
/**
@ -901,31 +898,19 @@ public class SessionFactoryImpl implements SessionFactoryImplementor {
@Override
public <T> T unwrap(Class<T> type) {
if ( type.isAssignableFrom( SessionFactory.class ) ) {
if ( type.isInstance( this ) ) {
return type.cast( this );
}
if ( type.isAssignableFrom( SessionFactoryImplementor.class ) ) {
return type.cast( this );
}
if ( type.isAssignableFrom( SessionFactoryImpl.class ) ) {
return type.cast( this );
}
if ( type.isAssignableFrom( EntityManagerFactory.class ) ) {
return type.cast( this );
}
if ( type.isAssignableFrom( SessionFactoryServiceRegistry.class ) ) {
if ( type.isInstance( serviceRegistry ) ) {
return type.cast( serviceRegistry );
}
if ( type.isAssignableFrom( JdbcServices.class ) ) {
if ( type.isInstance( jdbcServices ) ) {
return type.cast( jdbcServices );
}
if ( type.isAssignableFrom( Cache.class ) || type.isAssignableFrom( org.hibernate.Cache.class ) ) {
if ( type.isInstance( cacheAccess ) ) {
return type.cast( cacheAccess );
}
@ -937,11 +922,11 @@ public class SessionFactoryImpl implements SessionFactoryImplementor {
return type.cast( runtimeMetamodels.getJpaMetamodel() );
}
if ( type.isAssignableFrom( MetamodelImplementor.class ) || type.isAssignableFrom( MetadataImplementor.class ) ) {
if ( type.isInstance( runtimeMetamodels.getMappingMetamodel() ) ) {
return type.cast( runtimeMetamodels.getMappingMetamodel() );
}
if ( type.isAssignableFrom( QueryEngine.class ) ) {
if ( type.isInstance( queryEngine ) ) {
return type.cast( queryEngine );
}

View File

@ -11,19 +11,37 @@ import org.hibernate.metamodel.mapping.ModelPart;
import org.hibernate.sql.ast.tree.from.RootTableGroupProducer;
/**
* Contract for things that can be loaded by a Loader.
*
* Generally speaking this is limited to entities and collections
* Common details for things that can be loaded by a {@linkplain Loader loader} - generally
* {@linkplain org.hibernate.metamodel.mapping.EntityMappingType entities} and
* {@linkplain org.hibernate.metamodel.mapping.PluralAttributeMapping plural attributes} (collections).
*
* @see Loader
* @see org.hibernate.metamodel.mapping.EntityMappingType
* @see org.hibernate.metamodel.mapping.PluralAttributeMapping
*
* @author Steve Ebersole
*/
public interface Loadable extends ModelPart, RootTableGroupProducer {
boolean isAffectedByEnabledFilters(LoadQueryInfluencers influencers);
boolean isAffectedByEntityGraph(LoadQueryInfluencers influencers);
boolean isAffectedByEnabledFetchProfiles(LoadQueryInfluencers influencers);
/**
* The name for this loadable, for use as the root when generating
* {@linkplain org.hibernate.spi.NavigablePath relative paths}
*/
String getRootPathName();
/**
* Whether any of the "influencers" affect this loadable.
*/
boolean isAffectedByEnabledFilters(LoadQueryInfluencers influencers);
/**
* Whether the {@linkplain LoadQueryInfluencers#getEffectiveEntityGraph() effective entity-graph}
* applies to this loadable
*/
boolean isAffectedByEntityGraph(LoadQueryInfluencers influencers);
/**
* Whether any of the {@linkplain LoadQueryInfluencers#getEnabledFetchProfileNames()}
* apply to this loadable
*/
boolean isAffectedByEnabledFetchProfiles(LoadQueryInfluencers influencers);
}

View File

@ -8,7 +8,6 @@ package org.hibernate.metamodel.mapping;
import org.hibernate.engine.FetchStyle;
import org.hibernate.engine.FetchTiming;
import org.hibernate.persister.entity.DiscriminatorType;
import org.hibernate.spi.NavigablePath;
import org.hibernate.sql.ast.spi.SqlAstCreationState;
import org.hibernate.sql.ast.tree.expression.Expression;
@ -19,6 +18,11 @@ import org.hibernate.sql.results.graph.FetchParent;
import org.hibernate.sql.results.graph.basic.BasicFetch;
/**
* Details about the discriminator for an entity hierarchy.
*
* @implNote All {@linkplain EntityMappingType entity-mappings} within the
* hierarchy share the same EntityDiscriminatorMapping instance.
*
* @see jakarta.persistence.DiscriminatorColumn
* @see jakarta.persistence.DiscriminatorValue
*
@ -42,16 +46,51 @@ public interface EntityDiscriminatorMapping extends VirtualModelPart, BasicValue
return getPartName();
}
/**
* Is the discriminator defined by a physical column?
*/
boolean isPhysical();
@Override
default int getFetchableKey() {
return -2;
}
DiscriminatorType getDiscriminatorType();
/**
* Retrieve the details for a particular discriminator value.
*
* Returns {@code null} if there is no match.
*/
DiscriminatorValueDetails resolveDiscriminatorValue(Object value);
String getConcreteEntityNameForDiscriminatorValue(Object value);
/**
* Details for a particular discriminator value.
*
* @apiNote For {@linkplain jakarta.persistence.InheritanceType#JOINED joined}
* {@linkplain jakarta.persistence.InheritanceType#TABLE_PER_CLASS union} inheritance,
* the discriminator also effectively indicates a specific table. That table can be
* found via {@linkplain EntityMappingType#getMappedTableDetails()} for the
* {@linkplain #getIndicatedEntity() indicated entity}
*
* @see jakarta.persistence.DiscriminatorValue
*/
interface DiscriminatorValueDetails {
/**
* The discriminator value
*/
Object getValue();
boolean isPhysical();
/**
* The SQL literal representation of the discriminator value. E.g.
* for Strings, this would be the fully SQL-quoted form.
*/
Object getSqlLiteralValue();
/**
* The concrete entity-type mapped to this discriminator value
*/
EntityMappingType getIndicatedEntity();
}
/**
* Create the appropriate SQL expression for this discriminator
@ -66,7 +105,7 @@ public interface EntityDiscriminatorMapping extends VirtualModelPart, BasicValue
SqlAstCreationState creationState);
@Override
BasicFetch generateFetch(
BasicFetch<?> generateFetch(
FetchParent fetchParent,
NavigablePath fetchablePath,
FetchTiming fetchTiming,

View File

@ -6,10 +6,10 @@
*/
package org.hibernate.metamodel.mapping.internal;
import java.util.Map;
import java.util.function.BiConsumer;
import org.hibernate.engine.FetchTiming;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.mapping.IndexedConsumer;
import org.hibernate.metamodel.mapping.EntityDiscriminatorMapping;
@ -19,7 +19,6 @@ import org.hibernate.metamodel.mapping.MappingType;
import org.hibernate.metamodel.mapping.SelectableConsumer;
import org.hibernate.metamodel.model.domain.NavigableRole;
import org.hibernate.persister.entity.DiscriminatorType;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.spi.NavigablePath;
import org.hibernate.sql.ast.spi.SqlAstCreationState;
import org.hibernate.sql.ast.spi.SqlExpressionResolver;
@ -33,6 +32,9 @@ import org.hibernate.sql.results.graph.basic.BasicResult;
import org.hibernate.type.BasicType;
import org.hibernate.type.descriptor.java.JavaType;
import static org.hibernate.persister.entity.DiscriminatorHelper.NOT_NULL_DISCRIMINATOR;
import static org.hibernate.persister.entity.DiscriminatorHelper.NULL_DISCRIMINATOR;
/**
* @implNote `discriminatorType` represents the mapping to Class, whereas `discriminatorType.getUnderlyingType()`
* represents the "raw" JDBC mapping (String, Integer, etc)
@ -42,38 +44,36 @@ import org.hibernate.type.descriptor.java.JavaType;
public abstract class AbstractDiscriminatorMapping implements EntityDiscriminatorMapping {
private final NavigableRole role;
private final EntityPersister entityDescriptor;
private final DiscriminatorType<?> discriminatorType;
private final SessionFactoryImplementor sessionFactory;
private final JdbcMapping jdbcMapping;
private final EntityMappingType entityDescriptor;
private final Map<Object, DiscriminatorValueDetails> valueMappings;
private final DiscriminatorType<Object> discriminatorType;
public AbstractDiscriminatorMapping(
EntityPersister entityDescriptor,
EntityMappingType entityDescriptor,
DiscriminatorType<?> discriminatorType,
Map<Object, DiscriminatorValueDetails> valueMappings,
MappingModelCreationProcess creationProcess) {
this.jdbcMapping = discriminatorType.getUnderlyingType().getJdbcMapping();
this.entityDescriptor = entityDescriptor;
this.discriminatorType = discriminatorType;
this.valueMappings = valueMappings;
role = entityDescriptor.getNavigableRole().append( EntityDiscriminatorMapping.ROLE_NAME );
sessionFactory = creationProcess.getCreationContext().getSessionFactory();
this.role = entityDescriptor.getNavigableRole().append( EntityDiscriminatorMapping.ROLE_NAME );
//noinspection unchecked
this.discriminatorType = (DiscriminatorType<Object>) discriminatorType;
}
public EntityPersister getEntityDescriptor() {
public EntityMappingType getEntityDescriptor() {
return entityDescriptor;
}
@Override
public DiscriminatorType getDiscriminatorType() {
return discriminatorType;
}
public BasicType<?> getUnderlyingJdbcMappingType() {
return discriminatorType.getUnderlyingType();
}
public SessionFactoryImplementor getSessionFactory() {
return sessionFactory;
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// EntityDiscriminatorMapping
@ -89,8 +89,17 @@ public abstract class AbstractDiscriminatorMapping implements EntityDiscriminato
}
@Override
public String getConcreteEntityNameForDiscriminatorValue(Object value) {
return getEntityDescriptor().getSubclassForDiscriminatorValue( value );
public DiscriminatorValueDetails resolveDiscriminatorValue(Object value) {
if ( value == null ) {
return valueMappings.get( NULL_DISCRIMINATOR );
}
final DiscriminatorValueDetails matchedType = valueMappings.get( value );
if ( matchedType != null ) {
return matchedType;
}
return valueMappings.get( NOT_NULL_DISCRIMINATOR );
}
@Override
@ -108,24 +117,28 @@ public abstract class AbstractDiscriminatorMapping implements EntityDiscriminato
return getJdbcMapping().getJavaTypeDescriptor();
}
@SuppressWarnings({ "rawtypes", "unchecked" })
@Override
public <T> DomainResult<T> createDomainResult(
public DomainResult createDomainResult(
NavigablePath navigablePath,
TableGroup tableGroup,
String resultVariable,
DomainResultCreationState creationState) {
// create a SqlSelection based on the underlying JdbcMapping
final SqlSelection sqlSelection = resolveSqlSelection(
navigablePath,
getUnderlyingJdbcMappingType(),
jdbcMapping,
tableGroup,
null,
creationState.getSqlAstCreationState()
);
return new BasicResult<>(
// return a BasicResult with conversion the entity class or entity-name
return new BasicResult(
sqlSelection.getValuesArrayPosition(),
resultVariable,
discriminatorType,
discriminatorType.getJavaTypeDescriptor(),
discriminatorType.getValueConverter(),
navigablePath
);
}
@ -160,19 +173,22 @@ public abstract class AbstractDiscriminatorMapping implements EntityDiscriminato
assert tableGroup != null;
// create a SqlSelection based on the underlying JdbcMapping
final SqlSelection sqlSelection = resolveSqlSelection(
fetchablePath,
getUnderlyingJdbcMappingType(),
jdbcMapping,
tableGroup,
fetchParent,
creationState.getSqlAstCreationState()
);
// return a BasicFetch with conversion the entity class or entity-name
return new BasicFetch<>(
sqlSelection.getValuesArrayPosition(),
fetchParent,
fetchablePath,
this,
discriminatorType.getValueConverter(),
fetchTiming,
creationState
);
@ -183,7 +199,13 @@ public abstract class AbstractDiscriminatorMapping implements EntityDiscriminato
NavigablePath navigablePath,
TableGroup tableGroup,
DomainResultCreationState creationState) {
resolveSqlSelection( navigablePath, getUnderlyingJdbcMappingType(), tableGroup, null, creationState.getSqlAstCreationState() );
resolveSqlSelection(
navigablePath,
jdbcMapping,
tableGroup,
null,
creationState.getSqlAstCreationState()
);
}
@Override
@ -193,7 +215,7 @@ public abstract class AbstractDiscriminatorMapping implements EntityDiscriminato
DomainResultCreationState creationState,
BiConsumer<SqlSelection, JdbcMapping> selectionConsumer) {
selectionConsumer.accept(
resolveSqlSelection( navigablePath, getUnderlyingJdbcMappingType(), tableGroup, null, creationState.getSqlAstCreationState() ),
resolveSqlSelection( navigablePath, jdbcMapping, tableGroup, null, creationState.getSqlAstCreationState() ),
getJdbcMapping()
);
}
@ -204,13 +226,13 @@ public abstract class AbstractDiscriminatorMapping implements EntityDiscriminato
int offset,
JdbcValuesConsumer valuesConsumer,
SharedSessionContractImplementor session) {
valuesConsumer.consume( offset, value, getJdbcMapping() );
valuesConsumer.consume( offset, value, jdbcMapping );
return getJdbcTypeCount();
}
@Override
public int forEachJdbcType(int offset, IndexedConsumer<JdbcMapping> action) {
action.accept( offset, getJdbcMapping() );
action.accept( offset, jdbcMapping );
return getJdbcTypeCount();
}

View File

@ -50,8 +50,9 @@ public class CaseStatementDiscriminatorMappingImpl extends AbstractDiscriminator
String[] discriminatorValues,
Map<String,String> subEntityNameByTableName,
DiscriminatorType<?> incomingDiscriminatorType,
Map<Object, DiscriminatorValueDetails> valueMappings,
MappingModelCreationProcess creationProcess) {
super( entityDescriptor, incomingDiscriminatorType, creationProcess );
super( entityDescriptor, incomingDiscriminatorType, valueMappings, creationProcess );
for ( int i = 0; i < discriminatorValues.length; i++ ) {
final String tableName = tableNames[notNullColumnTableNumbers[i]];

View File

@ -6,9 +6,11 @@
*/
package org.hibernate.metamodel.mapping.internal;
import java.util.Map;
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.persister.entity.DiscriminatorType;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.spi.NavigablePath;
import org.hibernate.sql.ast.spi.SqlAstCreationState;
import org.hibernate.sql.ast.spi.SqlExpressionResolver;
@ -30,8 +32,7 @@ public class ExplicitColumnDiscriminatorMappingImpl extends AbstractDiscriminato
private final Integer scale;
public ExplicitColumnDiscriminatorMappingImpl(
EntityPersister entityDescriptor,
DiscriminatorType<?> discriminatorType,
EntityMappingType entityDescriptor,
String tableExpression,
String columnExpression,
boolean isFormula,
@ -40,8 +41,10 @@ public class ExplicitColumnDiscriminatorMappingImpl extends AbstractDiscriminato
Long length,
Integer precision,
Integer scale,
DiscriminatorType<?> discriminatorType,
Map<Object, DiscriminatorValueDetails> valueMappings,
MappingModelCreationProcess creationProcess) {
super( entityDescriptor, discriminatorType, creationProcess );
super( entityDescriptor, discriminatorType, valueMappings, creationProcess );
this.tableExpression = tableExpression;
this.isPhysical = isPhysical;
this.columnDefinition = columnDefinition;

View File

@ -161,6 +161,7 @@ import org.hibernate.metamodel.mapping.BasicValuedModelPart;
import org.hibernate.metamodel.mapping.DiscriminatedAssociationModelPart;
import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart;
import org.hibernate.metamodel.mapping.EntityDiscriminatorMapping;
import org.hibernate.metamodel.mapping.EntityDiscriminatorMapping.DiscriminatorValueDetails;
import org.hibernate.metamodel.mapping.EntityIdentifierMapping;
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.mapping.EntityRowIdMapping;
@ -4992,16 +4993,23 @@ public abstract class AbstractEntityPersister
}
return new ExplicitColumnDiscriminatorMappingImpl (
this,
(DiscriminatorType<?>) getTypeDiscriminatorMetadata().getResolutionType(),
getTableName(),
discriminatorColumnExpression,
getDiscriminatorFormulaTemplate() != null,
isPhysicalDiscriminator(),
columnDefinition, length, precision, scale, modelCreationProcess
columnDefinition, length, precision, scale,
(DiscriminatorType<?>) getTypeDiscriminatorMetadata().getResolutionType(),
buildDiscriminatorValueMappings( bootEntityDescriptor, modelCreationProcess ),
modelCreationProcess
);
}
}
protected abstract Map<Object, DiscriminatorValueDetails> buildDiscriminatorValueMappings(
PersistentClass bootEntityDescriptor,
MappingModelCreationProcess modelCreationProcess);
protected EntityVersionMapping generateVersionMapping(
Supplier<?> templateInstanceCreator,
PersistentClass bootEntityDescriptor,

View File

@ -6,6 +6,7 @@
*/
package org.hibernate.persister.entity;
import org.hibernate.Internal;
import org.hibernate.MappingException;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.spi.SessionFactoryImplementor;
@ -14,18 +15,18 @@ import org.hibernate.mapping.PersistentClass;
import org.hibernate.sql.InFragment;
import org.hibernate.type.BasicType;
import org.hibernate.type.Type;
import org.hibernate.type.descriptor.WrapperOptions;
import org.hibernate.type.descriptor.java.JavaType;
import org.hibernate.type.descriptor.jdbc.JdbcLiteralFormatter;
/**
* Operations needed by persisters for working with discriminators.
*
* @author Gavin King
*/
class DiscriminatorHelper {
@Internal
public class DiscriminatorHelper {
static final Object NULL_DISCRIMINATOR = new MarkerObject( "<null discriminator>" );
static final Object NOT_NULL_DISCRIMINATOR = new MarkerObject( "<not null discriminator>" );
public static final Object NULL_DISCRIMINATOR = new MarkerObject( "<null discriminator>" );
public static final Object NOT_NULL_DISCRIMINATOR = new MarkerObject( "<not null discriminator>" );
static BasicType<?> getDiscriminatorType(PersistentClass persistentClass) {
Type discriminatorType = persistentClass.getDiscriminator().getType();
@ -51,8 +52,7 @@ class DiscriminatorHelper {
return discriminatorSqlLiteral(
getDiscriminatorType( persistentClass ),
persistentClass,
dialect,
factory.getWrapperOptions()
dialect
);
}
}
@ -82,16 +82,20 @@ class DiscriminatorHelper {
private static <T> String discriminatorSqlLiteral(
BasicType<T> discriminatorType,
PersistentClass persistentClass,
Dialect dialect,
WrapperOptions wrapperOptions) {
final JavaType<T> javaType = discriminatorType.getJavaTypeDescriptor();
Dialect dialect) {
return jdbcLiteral(
discriminatorType.getJavaTypeDescriptor().fromString( persistentClass.getDiscriminatorValue() ),
discriminatorType.getJdbcLiteralFormatter(),
dialect
);
}
public static <T> String jdbcLiteral(
T value,
JdbcLiteralFormatter<T> formatter,
Dialect dialect) {
try {
return discriminatorType.getJdbcLiteralFormatter()
.toJdbcLiteral(
javaType.fromString( persistentClass.getDiscriminatorValue() ),
dialect,
wrapperOptions
);
return formatter.toJdbcLiteral( value, dialect, null );
}
catch (Exception e) {
throw new MappingException( "Could not format discriminator value to SQL string", e );

View File

@ -19,6 +19,8 @@ import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.internal.util.collections.ArrayHelper;
import org.hibernate.metamodel.RepresentationMode;
import org.hibernate.metamodel.mapping.EntityDiscriminatorMapping.DiscriminatorValueDetails;
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.model.convert.spi.BasicValueConverter;
import org.hibernate.metamodel.spi.MappingMetamodelImplementor;
import org.hibernate.type.AbstractType;
@ -64,18 +66,16 @@ public class DiscriminatorType<T> extends AbstractType implements BasicType<T>,
if ( discriminatorValue == null ) {
return null;
}
final String entityName = persister.getSubclassForDiscriminatorValue( discriminatorValue );
if ( entityName == null ) {
final DiscriminatorValueDetails valueDetails = persister.getDiscriminatorMapping().resolveDiscriminatorValue( discriminatorValue );
if ( valueDetails == null ) {
throw new HibernateException( "Unable to resolve discriminator value [" + discriminatorValue + "] to entity name" );
}
final EntityPersister entityPersister = persister.getFactory()
.getRuntimeMetamodels()
.getMappingMetamodel()
.getEntityDescriptor( entityName );
final EntityMappingType indicatedEntity = valueDetails.getIndicatedEntity();
//noinspection unchecked
return entityPersister.getRepresentationStrategy().getMode() == RepresentationMode.POJO
? (T) entityPersister.getJavaType().getJavaTypeClass()
: (T) entityName;
return indicatedEntity.getRepresentationStrategy().getMode() == RepresentationMode.POJO
? (T) indicatedEntity.getJavaType().getJavaTypeClass()
: (T) indicatedEntity.getEntityName();
}
@Override

View File

@ -0,0 +1,40 @@
/*
* 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.persister.entity;
import org.hibernate.metamodel.mapping.EntityDiscriminatorMapping;
import org.hibernate.metamodel.mapping.EntityMappingType;
/**
* @author Steve Ebersole
*/
public class DiscriminatorValueDetailsImpl implements EntityDiscriminatorMapping.DiscriminatorValueDetails {
private final Object value;
private final String jdbcLiteral;
private final EntityMappingType matchedEntityDescriptor;
public DiscriminatorValueDetailsImpl(Object value, String jdbcLiteral, EntityMappingType matchedEntityDescriptor) {
this.value = value;
this.jdbcLiteral = jdbcLiteral;
this.matchedEntityDescriptor = matchedEntityDescriptor;
}
@Override
public Object getValue() {
return value;
}
@Override
public Object getSqlLiteralValue() {
return jdbcLiteral;
}
@Override
public EntityMappingType getIndicatedEntity() {
return matchedEntityDescriptor;
}
}

View File

@ -34,7 +34,6 @@ import org.hibernate.id.IdentifierGenerator;
import org.hibernate.id.insert.InsertGeneratedIdentifierDelegate;
import org.hibernate.internal.FilterAliasGenerator;
import org.hibernate.internal.TableGroupFilterAliasGenerator;
import org.hibernate.loader.ast.spi.Loadable;
import org.hibernate.loader.ast.spi.MultiIdLoadOptions;
import org.hibernate.loader.ast.spi.MultiNaturalIdLoader;
import org.hibernate.loader.ast.spi.NaturalIdLoader;
@ -103,8 +102,7 @@ import org.hibernate.type.descriptor.java.VersionJavaType;
* @see org.hibernate.persister.spi.PersisterFactory
* @see org.hibernate.persister.spi.PersisterClassResolver
*/
public interface EntityPersister
extends EntityMappingType, Loadable, RootTableGroupProducer, AttributeSource {
public interface EntityPersister extends EntityMappingType, RootTableGroupProducer, AttributeSource {
/**
* Finish the initialization of this object.

View File

@ -14,6 +14,7 @@ import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Supplier;
import org.hibernate.AssertionFailure;
@ -70,6 +71,7 @@ import org.hibernate.type.BasicType;
import org.hibernate.type.CompositeType;
import org.hibernate.type.StandardBasicTypes;
import org.hibernate.type.Type;
import org.hibernate.type.descriptor.jdbc.JdbcLiteralFormatter;
import org.jboss.logging.Logger;
@ -861,6 +863,32 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
}
}
@Override
protected Map<Object, EntityDiscriminatorMapping.DiscriminatorValueDetails> buildDiscriminatorValueMappings(PersistentClass bootEntityDescriptor, MappingModelCreationProcess modelCreationProcess) {
final MappingMetamodelImplementor mappingModel = modelCreationProcess.getCreationContext()
.getSessionFactory()
.getMappingMetamodel();
//noinspection unchecked
final JdbcLiteralFormatter<Object> jdbcLiteralFormatter = (JdbcLiteralFormatter<Object>) discriminatorType.getJdbcLiteralFormatter();
final Dialect dialect = modelCreationProcess.getCreationContext().getSessionFactory().getJdbcServices().getDialect();
final Map<Object, EntityDiscriminatorMapping.DiscriminatorValueDetails> valueMappings = new ConcurrentHashMap<>();
subclassesByDiscriminatorValue.forEach( (value, entityName) -> {
final String jdbcLiteral = value == NULL_DISCRIMINATOR || value == NOT_NULL_DISCRIMINATOR
? null
: jdbcLiteralFormatter.toJdbcLiteral( value, dialect, null );
final DiscriminatorValueDetailsImpl valueMapping = new DiscriminatorValueDetailsImpl(
value,
jdbcLiteral,
mappingModel.findEntityDescriptor( entityName )
);
valueMappings.put( value, valueMapping );
} );
return valueMappings;
}
@Override
public void addDiscriminatorToInsertGroup(MutationGroupBuilder insertGroupBuilder) {
if ( explicitDiscriminatorColumnName != null ) {
@ -1256,6 +1284,7 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister {
discriminatorValues,
subclassNameByTableName,
discriminatorMetadataType,
buildDiscriminatorValueMappings( bootEntityDescriptor, modelCreationProcess ),
modelCreationProcess
);
}

View File

@ -6,6 +6,8 @@
*/
package org.hibernate.persister.entity;
import org.hibernate.metamodel.mapping.EntityDiscriminatorMapping;
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.type.Type;
/**
@ -13,14 +15,20 @@ import org.hibernate.type.Type;
* using a {@link org.hibernate.loader.ast.spi.Loader}.
*
* @author Gavin King
*
* @deprecated Use {@link EntityMappingType}
*/
@Deprecated(since = "6", forRemoval = true)
public interface Loadable extends EntityPersister {
String ROWID_ALIAS = "rowid_";
/**
* Does this persistent class have subclasses?
*
* @deprecated See {@link EntityMappingType#hasSubclasses()}
*/
@Deprecated
boolean hasSubclasses();
/**
@ -30,13 +38,19 @@ public interface Loadable extends EntityPersister {
/**
* Get the discriminator value
*
* @deprecated Use {@link EntityMappingType#getDiscriminatorValue()} instead
*/
@Deprecated
Object getDiscriminatorValue();
/**
* Get the concrete subclass corresponding to the given discriminator
* value
*
* @deprecated Use {@link EntityDiscriminatorMapping#resolveDiscriminatorValue} instead
*/
@Deprecated
String getSubclassForDiscriminatorValue(Object value);
/**
@ -65,7 +79,10 @@ public interface Loadable extends EntityPersister {
/**
* @return the column name for the discriminator as specified in the mapping.
*
* @deprecated Use {@link EntityDiscriminatorMapping#getSelectionExpression()} instead
*/
@Deprecated
String getDiscriminatorColumnName();
/**

View File

@ -6,6 +6,8 @@
*/
package org.hibernate.persister.entity;
import org.hibernate.metamodel.mapping.EntityMappingType;
/**
* Extends the generic {@link EntityPersister} contract to add
* operations required by the Hibernate Query Language
@ -20,20 +22,30 @@ public interface Queryable extends Loadable, PropertyMapping, Joinable {
/**
* Is this an abstract class?
*
* @see EntityMappingType#isAbstract()
*/
boolean isAbstract();
/**
* Is this class explicit polymorphism only?
*
* @see EntityMappingType#isExplicitPolymorphism()
*/
boolean isExplicitPolymorphism();
/**
* Get the class that this class is mapped as a subclass of -
* not necessarily the direct superclass
*
* @see EntityMappingType#getSuperMappingType()
*/
String getMappedSuperclass();
/**
* Get the discriminator value for this particular concrete subclass,
* as a string that may be embedded in a select statement
*
* @see EntityMappingType#getDiscriminatorSQLValue()
*/
String getDiscriminatorSQLValue();

View File

@ -12,6 +12,7 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Consumer;
import java.util.function.Supplier;
@ -39,8 +40,10 @@ import org.hibernate.mapping.Selectable;
import org.hibernate.mapping.Subclass;
import org.hibernate.mapping.Table;
import org.hibernate.mapping.Value;
import org.hibernate.metamodel.mapping.EntityDiscriminatorMapping.DiscriminatorValueDetails;
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.mapping.TableDetails;
import org.hibernate.metamodel.mapping.internal.MappingModelCreationProcess;
import org.hibernate.metamodel.spi.MappingMetamodelImplementor;
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
import org.hibernate.persister.spi.PersisterCreationContext;
@ -66,10 +69,11 @@ import org.hibernate.sql.ast.tree.predicate.NullnessPredicate;
import org.hibernate.sql.ast.tree.predicate.Predicate;
import org.hibernate.sql.model.ast.builder.MutationGroupBuilder;
import org.hibernate.sql.model.ast.builder.TableInsertBuilder;
import org.hibernate.sql.model.ast.builder.TableMutationBuilder;
import org.hibernate.type.BasicType;
import org.hibernate.type.Type;
import org.hibernate.type.descriptor.jdbc.JdbcLiteralFormatter;
import static org.hibernate.persister.entity.DiscriminatorHelper.NOT_NULL_DISCRIMINATOR;
import static org.hibernate.persister.entity.DiscriminatorHelper.NULL_DISCRIMINATOR;
import static org.hibernate.sql.model.ast.builder.TableMutationBuilder.NULL;
@ -703,6 +707,35 @@ public class SingleTableEntityPersister extends AbstractEntityPersister {
return getTableSpan() > 1;
}
@Override
protected Map<Object, DiscriminatorValueDetails> buildDiscriminatorValueMappings(
PersistentClass bootEntityDescriptor,
MappingModelCreationProcess modelCreationProcess) {
final MappingMetamodelImplementor mappingModel = modelCreationProcess.getCreationContext()
.getSessionFactory()
.getMappingMetamodel();
//noinspection unchecked
final JdbcLiteralFormatter<Object> jdbcLiteralFormatter = (JdbcLiteralFormatter<Object>) discriminatorType.getJdbcLiteralFormatter();
final Dialect dialect = modelCreationProcess.getCreationContext().getSessionFactory().getJdbcServices().getDialect();
final Map<Object, DiscriminatorValueDetails> valueMappings = new ConcurrentHashMap<>();
subclassesByDiscriminatorValue.forEach( (value, entityName) -> {
final String jdbcLiteral = value == NULL_DISCRIMINATOR || value == NOT_NULL_DISCRIMINATOR
? null
: jdbcLiteralFormatter.toJdbcLiteral( value, dialect, null );
final DiscriminatorValueDetailsImpl valueMapping = new DiscriminatorValueDetailsImpl(
value,
jdbcLiteral,
mappingModel.findEntityDescriptor( entityName )
);
valueMappings.put( value, valueMapping );
} );
return valueMappings;
}
@Override
public String[] getConstraintOrderedTableNameClosure() {
return constraintOrderedTableNames;

View File

@ -17,6 +17,7 @@ import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Consumer;
import java.util.function.Supplier;
@ -64,6 +65,7 @@ import org.hibernate.sql.ast.tree.predicate.Predicate;
import org.hibernate.type.BasicType;
import org.hibernate.type.StandardBasicTypes;
import org.hibernate.type.Type;
import org.hibernate.type.descriptor.jdbc.JdbcLiteralFormatter;
/**
* An {@link EntityPersister} implementing the
@ -328,6 +330,29 @@ public class UnionSubclassEntityPersister extends AbstractEntityPersister {
return subclassByDiscriminatorValue.get( value );
}
@Override
protected Map<Object, EntityDiscriminatorMapping.DiscriminatorValueDetails> buildDiscriminatorValueMappings(PersistentClass bootEntityDescriptor, MappingModelCreationProcess modelCreationProcess) {
final MappingMetamodelImplementor mappingModel = modelCreationProcess.getCreationContext()
.getSessionFactory()
.getMappingMetamodel();
//noinspection unchecked
final JdbcLiteralFormatter<Object> jdbcLiteralFormatter = (JdbcLiteralFormatter<Object>) discriminatorType.getJdbcLiteralFormatter();
final Dialect dialect = modelCreationProcess.getCreationContext().getSessionFactory().getJdbcServices().getDialect();
final Map<Object, EntityDiscriminatorMapping.DiscriminatorValueDetails> valueMappings = new ConcurrentHashMap<>();
subclassByDiscriminatorValue.forEach( (value, entityName) -> {
final DiscriminatorValueDetailsImpl valueMapping = new DiscriminatorValueDetailsImpl(
value,
jdbcLiteralFormatter.toJdbcLiteral( value, dialect, null ),
mappingModel.findEntityDescriptor( entityName )
);
valueMappings.put( value, valueMapping );
} );
return valueMappings;
}
@Override
public Serializable[] getPropertySpaces() {
return spaces;

View File

@ -12,6 +12,7 @@ import org.hibernate.mapping.IndexedConsumer;
import org.hibernate.metamodel.mapping.AttributeMapping;
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.mapping.ModelPart;
import org.hibernate.metamodel.model.domain.NavigableRole;
import org.hibernate.spi.NavigablePath;
/**
@ -22,7 +23,10 @@ import org.hibernate.spi.NavigablePath;
@Incubating
public interface Fetchable extends ModelPart {
/**
* The name of the fetchable
* The name of the fetchable. This is the part's "local name".
*
* @see #getNavigableRole()
* @see NavigableRole#getLocalName()
*/
String getFetchableName();

View File

@ -27,7 +27,6 @@ import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.engine.spi.Status;
import org.hibernate.event.service.spi.EventListenerGroup;
import org.hibernate.event.spi.EventSource;
import org.hibernate.event.spi.PreLoadEvent;
import org.hibernate.event.spi.PreLoadEventListener;
import org.hibernate.internal.util.NullnessHelper;
@ -35,6 +34,8 @@ import org.hibernate.internal.util.StringHelper;
import org.hibernate.loader.entity.CacheEntityLoaderHelper;
import org.hibernate.metamodel.mapping.AttributeMapping;
import org.hibernate.metamodel.mapping.AttributeMetadata;
import org.hibernate.metamodel.mapping.EntityDiscriminatorMapping;
import org.hibernate.metamodel.mapping.EntityDiscriminatorMapping.DiscriminatorValueDetails;
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.mapping.EntityValuedModelPart;
import org.hibernate.metamodel.mapping.EntityVersionMapping;
@ -53,7 +54,6 @@ import org.hibernate.sql.results.graph.DomainResultAssembler;
import org.hibernate.sql.results.graph.Fetch;
import org.hibernate.sql.results.graph.Fetchable;
import org.hibernate.sql.results.graph.basic.BasicResultAssembler;
import org.hibernate.sql.results.graph.entity.internal.EntityResultInitializer;
import org.hibernate.sql.results.internal.NullValueAssembler;
import org.hibernate.sql.results.jdbc.spi.JdbcValuesSourceProcessingState;
import org.hibernate.sql.results.jdbc.spi.RowProcessingState;
@ -342,32 +342,26 @@ public abstract class AbstractEntityInitializer extends AbstractFetchParentAcces
return entityDescriptor;
}
final Object discriminatorDomainValue = discriminatorAssembler.extractRawValue( rowProcessingState );
final String concreteEntityName = entityDescriptor.getDiscriminatorMapping()
.getConcreteEntityNameForDiscriminatorValue( discriminatorDomainValue );
final EntityDiscriminatorMapping discriminatorMapping = entityDescriptor.getDiscriminatorMapping();
assert discriminatorMapping != null;
if ( concreteEntityName == null ) {
final Object discriminator = discriminatorAssembler.extractRawValue( rowProcessingState );
final DiscriminatorValueDetails discriminatorDetails = discriminatorMapping.resolveDiscriminatorValue( discriminator );
if ( discriminatorDetails == null ) {
return entityDescriptor;
}
final EntityPersister concreteType = session.getFactory()
.getRuntimeMetamodels()
.getMappingMetamodel()
.findEntityDescriptor( concreteEntityName );
if ( concreteType == null || !concreteType.isTypeOrSuperType( entityDescriptor ) ) {
if ( !discriminatorDetails.getIndicatedEntity().isTypeOrSuperType( entityDescriptor ) ) {
throw new WrongClassException(
concreteEntityName,
discriminatorDetails.getIndicatedEntity().getEntityName(),
null,
entityDescriptor.getEntityName(),
discriminatorDomainValue
discriminator
);
}
// verify that the `entityDescriptor` is either == concreteType or its super-type
assert concreteType.isTypeOrSuperType( entityDescriptor );
return concreteType;
return discriminatorDetails.getIndicatedEntity().getEntityPersister();
}
protected void resolveEntityKey(RowProcessingState rowProcessingState) {