HHH-18125 Support for `type()` and `treat()` operators for Embeddables

This commit is contained in:
Marco Belladelli 2024-05-13 12:46:24 +02:00
parent 11384ab917
commit 2e9acf1ded
83 changed files with 1786 additions and 520 deletions

View File

@ -543,8 +543,8 @@ The following special functions make it possible to discover or narrow expressio
|=== |===
| Special function | Purpose | Signature | JPA standard | Special function | Purpose | Signature | JPA standard
| `type()` | The (concrete) entity type | `type(e)` | ✔ | `type()` | The (concrete) entity or embeddable type | `type(e)` | ✔
| `treat()` | Narrow an entity type | `treat(e as Entity)` | ✔ | `treat()` | Narrow an entity or embeddable type | `treat(e as Entity)` | ✔
| `cast()` | Narrow a basic type | `cast(x as Type)` | ✖ | `cast()` | Narrow a basic type | `cast(x as Type)` | ✖
| `str()` | Cast to a string | `str(x)` | ✖ | `str()` | Cast to a string | `str(x)` | ✖
|=== |===
@ -555,7 +555,7 @@ Let's see what these functions do.
[discrete] [discrete]
===== Evaluating an entity type ===== Evaluating an entity type
The function `type()`, applied to an identification variable or entity-valued path expression, evaluates to the concrete type, that is, the Java `Class`, of the referenced entity. The function `type()`, applied to an identification variable or to an entity-valued or embeddable-valued path expression, evaluates to the concrete type, that is, the Java `Class`, of the referenced entity or embeddable.
This is mainly useful when dealing with entity inheritance hierarchies. This is mainly useful when dealing with entity inheritance hierarchies.
[[entity-type-exp-example]] [[entity-type-exp-example]]
@ -571,7 +571,7 @@ where type(payment) = CreditCardPayment
===== Narrowing an entity type ===== Narrowing an entity type
The function `treat()` may be used to narrow the type of an identification variable. The function `treat()` may be used to narrow the type of an identification variable.
This is useful when dealing with entity inheritance hierarchies. This is useful when dealing with entity or embeddable inheritance hierarchies.
[[treat-example]] [[treat-example]]
[source, hql] [source, hql]

View File

@ -395,7 +395,7 @@ It's possible to customize the discriminator column mapping:
* For the whole `@Embeddable` type, by using `@DiscriminatorColumn` or `@DiscriminatorFormula` on the *root* class of the inheritance hierarchy * For the whole `@Embeddable` type, by using `@DiscriminatorColumn` or `@DiscriminatorFormula` on the *root* class of the inheritance hierarchy
(NOTE: if using the same inheritance-enabled embeddable type for two different properties in the same entity mapping, (NOTE: if using the same inheritance-enabled embeddable type for two different properties in the same entity mapping,
this will cause a column name conflict); this will cause a column name conflict);
* For a specific `@Embedded` property, by using the `@AttributeOverride` annotation with the special name `{discriminator}`. * For a specific `@Embedded` property, by using the `@AttributeOverride` annotation with the special name `+{discriminator}+`.
Finally, to specify custom discriminator values for each subtype one can annotate the inheritance hierarchy's Finally, to specify custom discriminator values for each subtype one can annotate the inheritance hierarchy's
classes with `@DiscriminatorValue`. classes with `@DiscriminatorValue`.
@ -407,6 +407,8 @@ Embeddable inheritance is *NOT* supported for `@EmbeddedId`, embeddable types us
and embedded properties using a custom `@CompositeType`. and embedded properties using a custom `@CompositeType`.
==== ====
Note that the `type()` and `treat()` functions are also supported for embeddable inheritance, see <<chapters/jndi/QueryLanguage.adoc#hql-functions-typecasts,types and typecasts>>.
[[embeddable-inheritance-example]] [[embeddable-inheritance-example]]
.Example mapping of an embeddable inheritance hierarchy .Example mapping of an embeddable inheritance hierarchy
[source,java] [source,java]

View File

@ -750,8 +750,8 @@ The following special functions make it possible to discover or narrow expressio
|=== |===
| Special function | Purpose | Signature | JPA standard | Special function | Purpose | Signature | JPA standard
| `type()` | The (concrete) entity name | `type(e)` | &check; | `type()` | The (concrete) entity or embeddable type | `type(e)` | &check;
| `treat()` | Narrow an entity type | `treat(e as Entity)` | &check; | `treat()` | Narrow an entity or embeddable type | `treat(e as Entity)` | &check;
| `cast()` | Narrow a basic type | `cast(x as Type)` | &cross; | `cast()` | Narrow a basic type | `cast(x as Type)` | &cross;
| `str()` | Cast to a string | `str(x)` | &cross; | `str()` | Cast to a string | `str(x)` | &cross;
|=== |===
@ -761,7 +761,7 @@ Let's see what these functions do.
[[hql-function-type]] [[hql-function-type]]
===== `type()` ===== `type()`
The function `type()`, applied to an identification variable, evaluates to the entity name of the referenced entity. The function `type()`, applied to an identification variable or to an entity-valued or embeddable-valued path expression, evaluates to the concrete type, that is, the Java `Class`, of the referenced entity or embeddable.
This is mainly useful when dealing with entity inheritance hierarchies. This is mainly useful when dealing with entity inheritance hierarchies.
[[hql-entity-type-exp-example]] [[hql-entity-type-exp-example]]
@ -777,7 +777,7 @@ include::{example-dir-hql}/HQLTest.java[tags=hql-entity-type-exp-example]
===== `treat()` ===== `treat()`
The function `treat()` may be used to narrow the type of an identification variable. The function `treat()` may be used to narrow the type of an identification variable.
This is useful when dealing with entity inheritance hierarchies. This is useful when dealing with entity or embeddable inheritance hierarchies.
[[hql-treat-example]] [[hql-treat-example]]
==== ====

View File

@ -18,6 +18,7 @@ import java.util.UUID;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.function.Function; import java.util.function.Function;
import java.util.function.Supplier;
import org.hibernate.AssertionFailure; import org.hibernate.AssertionFailure;
import org.hibernate.DuplicateMappingException; import org.hibernate.DuplicateMappingException;
@ -95,6 +96,7 @@ import org.hibernate.mapping.RootClass;
import org.hibernate.mapping.SimpleValue; import org.hibernate.mapping.SimpleValue;
import org.hibernate.mapping.Table; import org.hibernate.mapping.Table;
import org.hibernate.metamodel.CollectionClassification; import org.hibernate.metamodel.CollectionClassification;
import org.hibernate.metamodel.mapping.DiscriminatorType;
import org.hibernate.metamodel.spi.EmbeddableInstantiator; import org.hibernate.metamodel.spi.EmbeddableInstantiator;
import org.hibernate.query.named.NamedObjectRepository; import org.hibernate.query.named.NamedObjectRepository;
import org.hibernate.query.sqm.function.SqmFunctionDescriptor; import org.hibernate.query.sqm.function.SqmFunctionDescriptor;
@ -136,6 +138,7 @@ public class InFlightMetadataCollectorImpl implements InFlightMetadataCollector,
private final List<Component> composites = new ArrayList<>(); private final List<Component> composites = new ArrayList<>();
private final Map<Class<?>, Component> genericComponentsMap = new HashMap<>(); private final Map<Class<?>, Component> genericComponentsMap = new HashMap<>();
private final Map<XClass, List<XClass>> embeddableSubtypes = new HashMap<>(); private final Map<XClass, List<XClass>> embeddableSubtypes = new HashMap<>();
private final Map<Class<?>, DiscriminatorType<?>> embeddableDiscriminatorTypesMap = new HashMap<>();
private final Map<String,Collection> collectionBindingMap = new HashMap<>(); private final Map<String,Collection> collectionBindingMap = new HashMap<>();
private final Map<String, FilterDefinition> filterDefinitionMap = new HashMap<>(); private final Map<String, FilterDefinition> filterDefinitionMap = new HashMap<>();
@ -296,6 +299,13 @@ public class InFlightMetadataCollectorImpl implements InFlightMetadataCollector,
return subclasses != null ? subclasses : List.of(); return subclasses != null ? subclasses : List.of();
} }
@Override
public DiscriminatorType<?> resolveEmbeddableDiscriminatorType(
Class<?> embeddableClass,
Supplier<DiscriminatorType<?>> supplier) {
return embeddableDiscriminatorTypesMap.computeIfAbsent( embeddableClass, k -> supplier.get() );
}
@Override @Override
public SessionFactoryBuilder getSessionFactoryBuilder() { public SessionFactoryBuilder getSessionFactoryBuilder() {
throw new UnsupportedOperationException( throw new UnsupportedOperationException(
@ -2072,6 +2082,7 @@ public class InFlightMetadataCollectorImpl implements InFlightMetadataCollector,
entityBindingMap, entityBindingMap,
composites, composites,
genericComponentsMap, genericComponentsMap,
embeddableDiscriminatorTypesMap,
mappedSuperClasses, mappedSuperClasses,
collectionBindingMap, collectionBindingMap,
typeDefRegistry.copyRegistrationMap(), typeDefRegistry.copyRegistrationMap(),

View File

@ -16,6 +16,7 @@ import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.UUID; import java.util.UUID;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.function.Supplier;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import org.hibernate.HibernateException; import org.hibernate.HibernateException;
@ -60,6 +61,7 @@ import org.hibernate.mapping.Property;
import org.hibernate.mapping.Table; import org.hibernate.mapping.Table;
import org.hibernate.mapping.UserDefinedObjectType; import org.hibernate.mapping.UserDefinedObjectType;
import org.hibernate.mapping.UserDefinedType; import org.hibernate.mapping.UserDefinedType;
import org.hibernate.metamodel.mapping.DiscriminatorType;
import org.hibernate.procedure.spi.NamedCallableQueryMemento; import org.hibernate.procedure.spi.NamedCallableQueryMemento;
import org.hibernate.query.internal.NamedObjectRepositoryImpl; import org.hibernate.query.internal.NamedObjectRepositoryImpl;
import org.hibernate.query.named.NamedObjectRepository; import org.hibernate.query.named.NamedObjectRepository;
@ -91,6 +93,7 @@ public class MetadataImpl implements MetadataImplementor, Serializable {
private final Map<String,PersistentClass> entityBindingMap; private final Map<String,PersistentClass> entityBindingMap;
private final List<Component> composites; private final List<Component> composites;
private final Map<Class<?>, Component> genericComponentsMap; private final Map<Class<?>, Component> genericComponentsMap;
private final Map<Class<?>, DiscriminatorType<?>> embeddableDiscriminatorTypesMap;
private final Map<Class<?>, MappedSuperclass> mappedSuperclassMap; private final Map<Class<?>, MappedSuperclass> mappedSuperclassMap;
private final Map<String,Collection> collectionBindingMap; private final Map<String,Collection> collectionBindingMap;
private final Map<String, TypeDefinition> typeDefinitionMap; private final Map<String, TypeDefinition> typeDefinitionMap;
@ -112,6 +115,7 @@ public class MetadataImpl implements MetadataImplementor, Serializable {
Map<String, PersistentClass> entityBindingMap, Map<String, PersistentClass> entityBindingMap,
List<Component> composites, List<Component> composites,
Map<Class<?>, Component> genericComponentsMap, Map<Class<?>, Component> genericComponentsMap,
Map<Class<?>, DiscriminatorType<?>> embeddableDiscriminatorTypesMap,
Map<Class<?>, MappedSuperclass> mappedSuperclassMap, Map<Class<?>, MappedSuperclass> mappedSuperclassMap,
Map<String, Collection> collectionBindingMap, Map<String, Collection> collectionBindingMap,
Map<String, TypeDefinition> typeDefinitionMap, Map<String, TypeDefinition> typeDefinitionMap,
@ -132,6 +136,7 @@ public class MetadataImpl implements MetadataImplementor, Serializable {
this.entityBindingMap = entityBindingMap; this.entityBindingMap = entityBindingMap;
this.composites = composites; this.composites = composites;
this.genericComponentsMap = genericComponentsMap; this.genericComponentsMap = genericComponentsMap;
this.embeddableDiscriminatorTypesMap = embeddableDiscriminatorTypesMap;
this.mappedSuperclassMap = mappedSuperclassMap; this.mappedSuperclassMap = mappedSuperclassMap;
this.collectionBindingMap = collectionBindingMap; this.collectionBindingMap = collectionBindingMap;
this.typeDefinitionMap = typeDefinitionMap; this.typeDefinitionMap = typeDefinitionMap;
@ -569,6 +574,13 @@ public class MetadataImpl implements MetadataImplementor, Serializable {
return genericComponentsMap.get( componentClass ); return genericComponentsMap.get( componentClass );
} }
@Override
public DiscriminatorType<?> resolveEmbeddableDiscriminatorType(
Class<?> embeddableClass,
Supplier<DiscriminatorType<?>> supplier) {
return embeddableDiscriminatorTypesMap.computeIfAbsent( embeddableClass, k -> supplier.get() );
}
@Override @Override
public org.hibernate.type.Type getIdentifierType(String entityName) throws MappingException { public org.hibernate.type.Type getIdentifierType(String entityName) throws MappingException {
final PersistentClass pc = entityBindingMap.get( entityName ); final PersistentClass pc = entityBindingMap.get( entityName );
@ -664,4 +676,7 @@ public class MetadataImpl implements MetadataImplementor, Serializable {
return genericComponentsMap; return genericComponentsMap;
} }
public Map<Class<?>, DiscriminatorType<?>> getEmbeddableDiscriminatorTypesMap() {
return embeddableDiscriminatorTypesMap;
}
} }

View File

@ -75,6 +75,7 @@ import static org.hibernate.boot.model.internal.GeneratorBinder.buildIdGenerator
import static org.hibernate.boot.model.internal.InheritanceState.getInheritanceStateOfSuperEntity; import static org.hibernate.boot.model.internal.InheritanceState.getInheritanceStateOfSuperEntity;
import static org.hibernate.boot.model.internal.InheritanceState.getSuperclassInheritanceState; import static org.hibernate.boot.model.internal.InheritanceState.getSuperclassInheritanceState;
import static org.hibernate.internal.CoreLogging.messageLogger; import static org.hibernate.internal.CoreLogging.messageLogger;
import static org.hibernate.internal.util.StringHelper.unqualify;
import static org.hibernate.mapping.MetadataSource.ANNOTATIONS; import static org.hibernate.mapping.MetadataSource.ANNOTATIONS;
/** /**
@ -404,7 +405,7 @@ public final class AnnotationBinder {
private static void handleImport(XClass annotatedClass, MetadataBuildingContext context) { private static void handleImport(XClass annotatedClass, MetadataBuildingContext context) {
if ( annotatedClass.isAnnotationPresent( Imported.class ) ) { if ( annotatedClass.isAnnotationPresent( Imported.class ) ) {
String qualifiedName = annotatedClass.getName(); String qualifiedName = annotatedClass.getName();
String name = StringHelper.unqualify( qualifiedName ); String name = unqualify( qualifiedName );
String rename = annotatedClass.getAnnotation( Imported.class ).rename(); String rename = annotatedClass.getAnnotation( Imported.class ).rename();
context.getMetadataCollector().addImport( rename.isEmpty() ? name : rename, qualifiedName ); context.getMetadataCollector().addImport( rename.isEmpty() ? name : rename, qualifiedName );
} }
@ -693,6 +694,11 @@ public final class AnnotationBinder {
getSuperclassInheritanceState( clazz, inheritanceStatePerClass ); getSuperclassInheritanceState( clazz, inheritanceStatePerClass );
final InheritanceState state = final InheritanceState state =
new InheritanceState( clazz, inheritanceStatePerClass, buildingContext ); new InheritanceState( clazz, inheritanceStatePerClass, buildingContext );
final AnnotatedClassType classType = buildingContext.getMetadataCollector().getClassType( clazz );
if ( classType == EMBEDDABLE && !clazz.isAnnotationPresent( Imported.class ) ) {
final String className = clazz.getName();
buildingContext.getMetadataCollector().addImport( unqualify( className ), className );
}
if ( superclassState != null ) { if ( superclassState != null ) {
//the classes are ordered thus preventing an NPE //the classes are ordered thus preventing an NPE
superclassState.setHasSiblings( true ); superclassState.setHasSiblings( true );
@ -700,7 +706,7 @@ public final class AnnotationBinder {
getInheritanceStateOfSuperEntity( clazz, inheritanceStatePerClass ); getInheritanceStateOfSuperEntity( clazz, inheritanceStatePerClass );
if ( superEntityState != null ) { if ( superEntityState != null ) {
state.setHasParents( true ); state.setHasParents( true );
if ( buildingContext.getMetadataCollector().getClassType( clazz ) == EMBEDDABLE ) { if ( classType == EMBEDDABLE ) {
buildingContext.getMetadataCollector().registerEmbeddableSubclass( buildingContext.getMetadataCollector().registerEmbeddableSubclass(
superEntityState.getClazz(), superEntityState.getClazz(),
clazz clazz
@ -712,7 +718,7 @@ public final class AnnotationBinder {
state.setType( superclassState.getType() ); state.setType( superclassState.getType() );
} }
} }
switch ( buildingContext.getMetadataCollector().getClassType( clazz ) ) { switch ( classType ) {
case ENTITY: case ENTITY:
case MAPPED_SUPERCLASS: case MAPPED_SUPERCLASS:
case EMBEDDABLE: case EMBEDDABLE:

View File

@ -11,6 +11,7 @@ import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.UUID; import java.util.UUID;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.function.Supplier;
import org.hibernate.MappingException; import org.hibernate.MappingException;
import org.hibernate.SessionFactory; import org.hibernate.SessionFactory;
@ -30,6 +31,7 @@ import org.hibernate.mapping.FetchProfile;
import org.hibernate.mapping.MappedSuperclass; import org.hibernate.mapping.MappedSuperclass;
import org.hibernate.mapping.PersistentClass; import org.hibernate.mapping.PersistentClass;
import org.hibernate.mapping.Table; import org.hibernate.mapping.Table;
import org.hibernate.metamodel.mapping.DiscriminatorType;
import org.hibernate.query.named.NamedObjectRepository; import org.hibernate.query.named.NamedObjectRepository;
import org.hibernate.query.sqm.function.SqmFunctionDescriptor; import org.hibernate.query.sqm.function.SqmFunctionDescriptor;
import org.hibernate.query.sqm.function.SqmFunctionRegistry; import org.hibernate.query.sqm.function.SqmFunctionRegistry;
@ -249,6 +251,13 @@ public abstract class AbstractDelegatingMetadata implements MetadataImplementor
return delegate().getGenericComponent( componentClass ); return delegate().getGenericComponent( componentClass );
} }
@Override
public DiscriminatorType<?> resolveEmbeddableDiscriminatorType(
Class<?> embeddableClass,
Supplier<DiscriminatorType<?>> supplier) {
return delegate().resolveEmbeddableDiscriminatorType( embeddableClass, supplier );
}
@Override @Override
public NamedObjectRepository buildNamedQueryRepository(SessionFactoryImplementor sessionFactory) { public NamedObjectRepository buildNamedQueryRepository(SessionFactoryImplementor sessionFactory) {
return delegate().buildNamedQueryRepository( sessionFactory ); return delegate().buildNamedQueryRepository( sessionFactory );

View File

@ -8,6 +8,7 @@ package org.hibernate.boot.spi;
import java.util.Set; import java.util.Set;
import java.util.function.Consumer; import java.util.function.Consumer;
import java.util.function.Supplier;
import org.hibernate.Incubating; import org.hibernate.Incubating;
import org.hibernate.MappingException; import org.hibernate.MappingException;
@ -15,6 +16,7 @@ import org.hibernate.boot.Metadata;
import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.mapping.Component; import org.hibernate.mapping.Component;
import org.hibernate.mapping.MappedSuperclass; import org.hibernate.mapping.MappedSuperclass;
import org.hibernate.metamodel.mapping.DiscriminatorType;
import org.hibernate.query.named.NamedObjectRepository; import org.hibernate.query.named.NamedObjectRepository;
import org.hibernate.query.sqm.function.SqmFunctionRegistry; import org.hibernate.query.sqm.function.SqmFunctionRegistry;
import org.hibernate.type.spi.TypeConfiguration; import org.hibernate.type.spi.TypeConfiguration;
@ -58,4 +60,6 @@ public interface MetadataImplementor extends Metadata {
void visitRegisteredComponents(Consumer<Component> consumer); void visitRegisteredComponents(Consumer<Component> consumer);
Component getGenericComponent(Class<?> componentClass); Component getGenericComponent(Class<?> componentClass);
DiscriminatorType<?> resolveEmbeddableDiscriminatorType(Class<?> embeddableClass, Supplier<DiscriminatorType<?>> supplier);
} }

View File

@ -136,8 +136,8 @@ public class StructHelper {
instantiator = representationStrategy.getInstantiator(); instantiator = representationStrategy.getInstantiator();
} }
else { else {
// the discriminator here is the composite class name because it gets converted to the domain type when extracted // the discriminator here is the composite class because it gets converted to the domain type when extracted
instantiator = representationStrategy.getInstantiatorForClass( (String) attributeValues.getDiscriminator() ); instantiator = representationStrategy.getInstantiatorForClass( ( (Class<?>) attributeValues.getDiscriminator() ).getName() );
} }
return instantiator.instantiate( attributeValues, sessionFactory ); return instantiator.instantiate( attributeValues, sessionFactory );
} }

View File

@ -35,6 +35,7 @@ import org.hibernate.metamodel.UnsupportedMappingException;
import org.hibernate.metamodel.ValueClassification; import org.hibernate.metamodel.ValueClassification;
import org.hibernate.metamodel.mapping.AttributeMapping; import org.hibernate.metamodel.mapping.AttributeMapping;
import org.hibernate.metamodel.mapping.CompositeIdentifierMapping; import org.hibernate.metamodel.mapping.CompositeIdentifierMapping;
import org.hibernate.metamodel.mapping.DiscriminatorType;
import org.hibernate.metamodel.mapping.EmbeddableMappingType; import org.hibernate.metamodel.mapping.EmbeddableMappingType;
import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart; import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart;
import org.hibernate.metamodel.mapping.EntityIdentifierMapping; import org.hibernate.metamodel.mapping.EntityIdentifierMapping;
@ -268,7 +269,7 @@ public class AttributeFactory {
false, false,
context.getJpaMetamodel() context.getJpaMetamodel()
); );
context.registerEmbeddableType( embeddableType, component); context.registerEmbeddableType( embeddableType, component );
if ( component.isPolymorphic() ) { if ( component.isPolymorphic() ) {
final java.util.Collection<String> embeddableSubclasses = component.getDiscriminatorValues().values(); final java.util.Collection<String> embeddableSubclasses = component.getDiscriminatorValues().values();
@ -283,12 +284,14 @@ public class AttributeFactory {
continue; continue;
} }
final Class<?> subclass = cls.classForName( subclassName ); final Class<?> subclass = cls.classForName( subclassName );
context.registerEmbeddableType( new EmbeddableTypeImpl<>( final EmbeddableTypeImpl<?> subType = new EmbeddableTypeImpl<>(
context.getJavaTypeRegistry().resolveManagedTypeDescriptor( subclass ), context.getJavaTypeRegistry().resolveManagedTypeDescriptor( subclass ),
domainTypes.get( component.getSuperclass( subclassName ) ), domainTypes.get( component.getSuperclass( subclassName ) ),
false, false,
context.getJpaMetamodel() context.getJpaMetamodel()
), component ); );
domainTypes.put( subclassName, subType );
context.registerEmbeddableType( subType, component );
} }
} }

View File

@ -7,7 +7,6 @@
package org.hibernate.metamodel.internal; package org.hibernate.metamodel.internal;
import java.util.Collection; import java.util.Collection;
import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.Locale; import java.util.Locale;

View File

@ -47,7 +47,7 @@ public class DefaultDiscriminatorConverter<O,R> extends DiscriminatorConverter<O
JavaType<O> domainJavaType, JavaType<O> domainJavaType,
JavaType<R> relationalJavaType, JavaType<R> relationalJavaType,
MappingMetamodelImplementor mappingMetamodel) { MappingMetamodelImplementor mappingMetamodel) {
super( discriminatorRole, domainJavaType, relationalJavaType ); super( discriminatorRole.getFullPath(), domainJavaType, relationalJavaType );
this.mappingMetamodel = mappingMetamodel; this.mappingMetamodel = mappingMetamodel;
} }

View File

@ -7,7 +7,6 @@
package org.hibernate.metamodel.mapping; package org.hibernate.metamodel.mapping;
import org.hibernate.metamodel.RepresentationMode; import org.hibernate.metamodel.RepresentationMode;
import org.hibernate.metamodel.model.domain.NavigableRole;
import org.hibernate.type.descriptor.converter.spi.BasicValueConverter; import org.hibernate.type.descriptor.converter.spi.BasicValueConverter;
import org.hibernate.type.descriptor.java.JavaType; import org.hibernate.type.descriptor.java.JavaType;
@ -20,21 +19,21 @@ import java.util.function.Function;
*/ */
public abstract class DiscriminatorConverter<O,R> implements BasicValueConverter<O,R> { public abstract class DiscriminatorConverter<O,R> implements BasicValueConverter<O,R> {
private final NavigableRole discriminatorRole; private final String discriminatorName;
private final JavaType<O> domainJavaType; private final JavaType<O> domainJavaType;
private final JavaType<R> relationalJavaType; private final JavaType<R> relationalJavaType;
public DiscriminatorConverter( public DiscriminatorConverter(
NavigableRole discriminatorRole, String discriminatorName,
JavaType<O> domainJavaType, JavaType<O> domainJavaType,
JavaType<R> relationalJavaType) { JavaType<R> relationalJavaType) {
this.discriminatorRole = discriminatorRole; this.discriminatorName = discriminatorName;
this.domainJavaType = domainJavaType; this.domainJavaType = domainJavaType;
this.relationalJavaType = relationalJavaType; this.relationalJavaType = relationalJavaType;
} }
public NavigableRole getNavigableRole() { public String getDiscriminatorName() {
return discriminatorRole; return discriminatorName;
} }
@Override @Override
@ -95,7 +94,7 @@ public abstract class DiscriminatorConverter<O,R> implements BasicValueConverter
@Override @Override
public String toString() { public String toString() {
return "DiscriminatorConverter(" + discriminatorRole.getFullPath() + ")"; return "DiscriminatorConverter(" + discriminatorName + ")";
} }
public abstract void forEachValueDetail(Consumer<DiscriminatorValueDetails> consumer); public abstract void forEachValueDetail(Consumer<DiscriminatorValueDetails> consumer);

View File

@ -15,6 +15,8 @@ import java.util.function.Function;
import org.hibernate.AssertionFailure; import org.hibernate.AssertionFailure;
import org.hibernate.HibernateException; import org.hibernate.HibernateException;
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.metamodel.mapping.internal.EmbeddableDiscriminatorValueDetailsImpl; import org.hibernate.metamodel.mapping.internal.EmbeddableDiscriminatorValueDetailsImpl;
import org.hibernate.metamodel.model.domain.NavigableRole; import org.hibernate.metamodel.model.domain.NavigableRole;
import org.hibernate.type.BasicType; import org.hibernate.type.BasicType;
@ -29,32 +31,34 @@ import org.hibernate.type.descriptor.java.JavaType;
*/ */
public class EmbeddableDiscriminatorConverter<O, R> extends DiscriminatorConverter<O, R> { public class EmbeddableDiscriminatorConverter<O, R> extends DiscriminatorConverter<O, R> {
public static <O, R> EmbeddableDiscriminatorConverter<O, R> fromValueMappings( public static <O, R> EmbeddableDiscriminatorConverter<O, R> fromValueMappings(
NavigableRole role, String discriminatedType,
JavaType<O> domainJavaType, JavaType<O> domainJavaType,
BasicType<R> underlyingJdbcMapping, BasicType<R> underlyingJdbcMapping,
Map<Object, String> valueMappings) { Map<Object, String> valueMappings,
final List<DiscriminatorValueDetails> valueDetailsList = new ArrayList<>( valueMappings.size() ); SessionFactoryImplementor sessionFactory) {
final List<EmbeddableDiscriminatorValueDetailsImpl> valueDetailsList = new ArrayList<>( valueMappings.size() );
final ClassLoaderService cls = sessionFactory.getServiceRegistry().requireService( ClassLoaderService.class );
valueMappings.forEach( (value, embeddableClassName) -> valueDetailsList.add( new EmbeddableDiscriminatorValueDetailsImpl( valueMappings.forEach( (value, embeddableClassName) -> valueDetailsList.add( new EmbeddableDiscriminatorValueDetailsImpl(
value, value,
embeddableClassName cls.classForName( embeddableClassName )
) ) ); ) ) );
return new EmbeddableDiscriminatorConverter<>( return new EmbeddableDiscriminatorConverter<>(
role, discriminatedType,
domainJavaType, domainJavaType,
underlyingJdbcMapping.getJavaTypeDescriptor(), underlyingJdbcMapping.getJavaTypeDescriptor(),
valueDetailsList valueDetailsList
); );
} }
private final Map<Object, DiscriminatorValueDetails> discriminatorValueToDetailsMap; private final Map<Object, EmbeddableDiscriminatorValueDetailsImpl> discriminatorValueToDetailsMap;
private final Map<String, DiscriminatorValueDetails> embeddableClassNameToDetailsMap; private final Map<String, EmbeddableDiscriminatorValueDetailsImpl> embeddableClassNameToDetailsMap;
public EmbeddableDiscriminatorConverter( public EmbeddableDiscriminatorConverter(
NavigableRole discriminatorRole, String discriminatorName,
JavaType<O> domainJavaType, JavaType<O> domainJavaType,
JavaType<R> relationalJavaType, JavaType<R> relationalJavaType,
List<DiscriminatorValueDetails> valueMappings) { List<EmbeddableDiscriminatorValueDetailsImpl> valueMappings) {
super( discriminatorRole, domainJavaType, relationalJavaType ); super( discriminatorName, domainJavaType, relationalJavaType );
this.discriminatorValueToDetailsMap = new HashMap<>( valueMappings.size() ); this.discriminatorValueToDetailsMap = new HashMap<>( valueMappings.size() );
this.embeddableClassNameToDetailsMap = new HashMap<>( valueMappings.size() ); this.embeddableClassNameToDetailsMap = new HashMap<>( valueMappings.size() );
@ -68,32 +72,18 @@ public class EmbeddableDiscriminatorConverter<O, R> extends DiscriminatorConvert
public O toDomainValue(R relationalForm) { public O toDomainValue(R relationalForm) {
assert relationalForm == null || getRelationalJavaType().isInstance( relationalForm ); assert relationalForm == null || getRelationalJavaType().isInstance( relationalForm );
final DiscriminatorValueDetails matchingValueDetails = getDetailsForDiscriminatorValue( relationalForm ); final EmbeddableDiscriminatorValueDetailsImpl matchingValueDetails = getDetailsForDiscriminatorValue( relationalForm );
if ( matchingValueDetails == null ) { if ( matchingValueDetails == null ) {
throw new IllegalStateException( "Could not resolve discriminator value" ); throw new IllegalStateException( "Could not resolve discriminator value" );
} }
//noinspection unchecked //noinspection unchecked
return (O) matchingValueDetails.getIndicatedEntityName(); return (O) matchingValueDetails.getEmbeddableClass();
} }
@Override @Override
public R toRelationalValue(O domainForm) { public EmbeddableDiscriminatorValueDetailsImpl getDetailsForDiscriminatorValue(Object value) {
assert domainForm == null || domainForm instanceof String; final EmbeddableDiscriminatorValueDetailsImpl valueMatch = discriminatorValueToDetailsMap.get( value );
if ( domainForm == null ) {
return null;
}
final String embeddableClassName = (String) domainForm;
//noinspection unchecked
return (R) getDetailsForEntityName( embeddableClassName ).getValue();
}
@Override
public DiscriminatorValueDetails getDetailsForDiscriminatorValue(Object value) {
final DiscriminatorValueDetails valueMatch = discriminatorValueToDetailsMap.get( value );
if ( valueMatch != null ) { if ( valueMatch != null ) {
return valueMatch; return valueMatch;
} }

View File

@ -72,7 +72,7 @@ public class MappedDiscriminatorConverter<O,R> extends DiscriminatorConverter<O,
JavaType<O> domainJavaType, JavaType<O> domainJavaType,
JavaType<R> relationalJavaType, JavaType<R> relationalJavaType,
List<DiscriminatorValueDetails> valueMappings) { List<DiscriminatorValueDetails> valueMappings) {
super( discriminatorRole, domainJavaType, relationalJavaType ); super( discriminatorRole.getFullPath(), domainJavaType, relationalJavaType );
this.discriminatorValueToEntityNameMap = CollectionHelper.concurrentMap( valueMappings.size() ); this.discriminatorValueToEntityNameMap = CollectionHelper.concurrentMap( valueMappings.size() );
this.entityNameToDiscriminatorValueMap = CollectionHelper.concurrentMap( valueMappings.size() ); this.entityNameToDiscriminatorValueMap = CollectionHelper.concurrentMap( valueMappings.size() );

View File

@ -27,8 +27,8 @@ public class DiscriminatorTypeImpl<O> extends ConvertedBasicTypeImpl<O> implemen
BasicType<?> underlyingJdbcMapping, BasicType<?> underlyingJdbcMapping,
DiscriminatorConverter<O,?> discriminatorValueConverter) { DiscriminatorConverter<O,?> discriminatorValueConverter) {
super( super(
discriminatorValueConverter.getNavigableRole().getFullPath(), discriminatorValueConverter.getDiscriminatorName(),
"Discriminator type " + discriminatorValueConverter.getNavigableRole().getFullPath(), "Discriminator type " + discriminatorValueConverter.getDiscriminatorName(),
underlyingJdbcMapping.getJdbcType(), underlyingJdbcMapping.getJdbcType(),
discriminatorValueConverter discriminatorValueConverter
); );

View File

@ -20,11 +20,15 @@ import org.hibernate.metamodel.mapping.EntityMappingType;
*/ */
public class EmbeddableDiscriminatorValueDetailsImpl implements DiscriminatorValueDetails { public class EmbeddableDiscriminatorValueDetailsImpl implements DiscriminatorValueDetails {
final Object value; final Object value;
final String embeddableClassName; final Class<?> embeddableClass;
public EmbeddableDiscriminatorValueDetailsImpl(Object value, String embeddableClassName) { public EmbeddableDiscriminatorValueDetailsImpl(Object value, Class<?> embeddableClass) {
this.value = value; this.value = value;
this.embeddableClassName = embeddableClassName; this.embeddableClass = embeddableClass;
}
public Class<?> getEmbeddableClass() {
return embeddableClass;
} }
@Override @Override
@ -34,7 +38,7 @@ public class EmbeddableDiscriminatorValueDetailsImpl implements DiscriminatorVal
@Override @Override
public String getIndicatedEntityName() { public String getIndicatedEntityName() {
return embeddableClassName; return embeddableClass.getName();
} }
@Override @Override

View File

@ -16,7 +16,6 @@ import java.util.function.Function;
import org.hibernate.MappingException; import org.hibernate.MappingException;
import org.hibernate.SharedSessionContract; import org.hibernate.SharedSessionContract;
import org.hibernate.WrongClassException;
import org.hibernate.cfg.Environment; import org.hibernate.cfg.Environment;
import org.hibernate.dialect.Dialect; import org.hibernate.dialect.Dialect;
import org.hibernate.dialect.aggregate.AggregateSupport; import org.hibernate.dialect.aggregate.AggregateSupport;
@ -47,6 +46,7 @@ import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart;
import org.hibernate.metamodel.mapping.EntityDiscriminatorMapping; import org.hibernate.metamodel.mapping.EntityDiscriminatorMapping;
import org.hibernate.metamodel.mapping.EntityMappingType; import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.mapping.JdbcMapping; import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.mapping.ModelPart;
import org.hibernate.metamodel.mapping.SelectableConsumer; import org.hibernate.metamodel.mapping.SelectableConsumer;
import org.hibernate.metamodel.mapping.SelectableMapping; import org.hibernate.metamodel.mapping.SelectableMapping;
import org.hibernate.metamodel.mapping.SelectableMappings; import org.hibernate.metamodel.mapping.SelectableMappings;
@ -54,7 +54,6 @@ import org.hibernate.metamodel.mapping.SelectablePath;
import org.hibernate.metamodel.model.domain.NavigableRole; import org.hibernate.metamodel.model.domain.NavigableRole;
import org.hibernate.metamodel.spi.EmbeddableRepresentationStrategy; import org.hibernate.metamodel.spi.EmbeddableRepresentationStrategy;
import org.hibernate.metamodel.spi.RuntimeModelCreationContext; import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
import org.hibernate.persister.entity.DiscriminatorHelper;
import org.hibernate.persister.entity.EntityPersister; import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.property.access.spi.Getter; import org.hibernate.property.access.spi.Getter;
import org.hibernate.property.access.spi.PropertyAccess; import org.hibernate.property.access.spi.PropertyAccess;
@ -83,6 +82,7 @@ import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeRegistry;
import org.hibernate.type.spi.CompositeTypeImplementor; import org.hibernate.type.spi.CompositeTypeImplementor;
import org.hibernate.type.spi.TypeConfiguration; import org.hibernate.type.spi.TypeConfiguration;
import static org.hibernate.internal.util.StringHelper.qualify;
import static org.hibernate.persister.entity.DiscriminatorHelper.getDiscriminatorType; import static org.hibernate.persister.entity.DiscriminatorHelper.getDiscriminatorType;
import static org.hibernate.type.SqlTypes.JSON; import static org.hibernate.type.SqlTypes.JSON;
@ -736,9 +736,12 @@ public class EmbeddableMappingTypeImpl extends AbstractEmbeddableMapping impleme
scale = column.getScale(); scale = column.getScale();
} }
final DiscriminatorType<?> discriminatorType = buildDiscriminatorType( final DiscriminatorType<?> discriminatorType = creationContext.getMetadata().resolveEmbeddableDiscriminatorType(
bootDescriptor, bootDescriptor.getComponentClass(),
creationContext () -> buildDiscriminatorType(
bootDescriptor,
creationContext
)
); );
return new ExplicitColumnDiscriminatorMappingImpl( return new ExplicitColumnDiscriminatorMappingImpl(
@ -758,17 +761,18 @@ public class EmbeddableMappingTypeImpl extends AbstractEmbeddableMapping impleme
); );
} }
private DiscriminatorType<?> buildDiscriminatorType( private static DiscriminatorType<?> buildDiscriminatorType(
Component bootDescriptor, Component bootDescriptor,
RuntimeModelCreationContext creationContext) { RuntimeModelCreationContext creationContext) {
final JavaTypeRegistry javaTypeRegistry = creationContext.getSessionFactory().getTypeConfiguration().getJavaTypeRegistry(); final JavaTypeRegistry javaTypeRegistry = creationContext.getSessionFactory().getTypeConfiguration().getJavaTypeRegistry();
final JavaType<String> domainJavaType = javaTypeRegistry.resolveDescriptor( String.class ); final JavaType<String> domainJavaType = javaTypeRegistry.resolveDescriptor( Class.class );
final BasicType<?> discriminatorType = getDiscriminatorType( bootDescriptor ); final BasicType<?> discriminatorType = getDiscriminatorType( bootDescriptor );
final DiscriminatorConverter<String, ?> converter = EmbeddableDiscriminatorConverter.fromValueMappings( final DiscriminatorConverter<String, ?> converter = EmbeddableDiscriminatorConverter.fromValueMappings(
getNavigableRole().append( EntityDiscriminatorMapping.DISCRIMINATOR_ROLE_NAME ), qualify( bootDescriptor.getComponentClassName(), EntityDiscriminatorMapping.DISCRIMINATOR_ROLE_NAME ),
domainJavaType, domainJavaType,
discriminatorType, discriminatorType,
bootDescriptor.getDiscriminatorValues() bootDescriptor.getDiscriminatorValues(),
creationContext.getSessionFactory()
); );
return new DiscriminatorTypeImpl<>( discriminatorType, converter ); return new DiscriminatorTypeImpl<>( discriminatorType, converter );
} }
@ -882,6 +886,15 @@ public class EmbeddableMappingTypeImpl extends AbstractEmbeddableMapping impleme
} }
} }
@Override
public ModelPart findSubPart(String name, EntityMappingType treatTargetType) {
if ( EntityDiscriminatorMapping.matchesRoleName( name ) ) {
return discriminatorMapping;
}
return super.findSubPart( name, treatTargetType );
}
@Override @Override
public <X, Y> int breakDownJdbcValues( public <X, Y> int breakDownJdbcValues(
Object domainValue, Object domainValue,

View File

@ -6,8 +6,10 @@
*/ */
package org.hibernate.metamodel.model.domain; package org.hibernate.metamodel.model.domain;
import org.hibernate.query.BindableType; import java.util.Collection;
import org.hibernate.query.sqm.SqmExpressible; import org.hibernate.query.sqm.SqmExpressible;
import org.hibernate.query.sqm.SqmPathSource;
import jakarta.persistence.metamodel.EmbeddableType; import jakarta.persistence.metamodel.EmbeddableType;
@ -20,5 +22,16 @@ import jakarta.persistence.metamodel.EmbeddableType;
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public interface EmbeddableDomainType<J> public interface EmbeddableDomainType<J>
extends ManagedDomainType<J>, EmbeddableType<J>, SqmExpressible<J> { extends TreatableDomainType<J>, EmbeddableType<J>, SqmExpressible<J> {
@Override
default EmbeddableDomainType<J> getSqmType() {
return this;
}
@Override
Collection<? extends EmbeddableDomainType<? extends J>> getSubTypes();
default boolean isPolymorphic() {
return getSuperType() != null || !getSubTypes().isEmpty();
}
} }

View File

@ -17,14 +17,14 @@ import org.hibernate.query.sqm.SqmPathSource;
* *
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public interface EntityDomainType<J> extends IdentifiableDomainType<J>, EntityType<J>, SqmPathSource<J> { public interface EntityDomainType<J> extends IdentifiableDomainType<J>, EntityType<J>, TreatableDomainType<J> {
String getHibernateEntityName(); String getHibernateEntityName();
@Override @Override
Collection<? extends EntityDomainType<? extends J>> getSubTypes(); Collection<? extends EntityDomainType<? extends J>> getSubTypes();
@Override @Override
default DomainType<J> getSqmType() { default EntityDomainType<J> getSqmType() {
return this; return this;
} }
} }

View File

@ -47,11 +47,21 @@ public interface JpaMetamodel extends Metamodel {
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Extended features // Extended features
/**
* Access to a managed type through its name
*/
<X> ManagedDomainType<X> managedType(String typeName);
/** /**
* Access to an entity supporting Hibernate's entity-name feature * Access to an entity supporting Hibernate's entity-name feature
*/ */
<X> EntityDomainType<X> entity(String entityName); <X> EntityDomainType<X> entity(String entityName);
/**
* Access to an embeddable type from FQN
*/
<X> EmbeddableDomainType<X> embeddable(String embeddableName);
/** /**
* Specialized handling for resolving entity-name references in * Specialized handling for resolving entity-name references in
* an HQL query * an HQL query

View File

@ -37,9 +37,6 @@ public interface ManagedDomainType<J> extends SqmExpressible<J>, DomainType<J>,
/** /**
* The descriptor of the supertype of this type. * The descriptor of the supertype of this type.
*
* @apiNote we define this here in anticipation of eventually supporting
* embeddable inheritance
*/ */
ManagedDomainType<? super J> getSuperType(); ManagedDomainType<? super J> getSuperType();

View File

@ -0,0 +1,19 @@
/*
* 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.metamodel.model.domain;
import org.hibernate.query.sqm.SqmPathSource;
/**
* @author Marco Belladelli
*/
public interface TreatableDomainType<J> extends ManagedDomainType<J>, SqmPathSource<J> {
@Override
default DomainType<J> getSqmType() {
return this;
}
}

View File

@ -0,0 +1,46 @@
/*
* 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.metamodel.model.domain.internal;
import org.hibernate.metamodel.model.domain.DomainType;
import org.hibernate.query.ReturnableType;
import org.hibernate.query.sqm.SqmPathSource;
import static jakarta.persistence.metamodel.Bindable.BindableType.SINGULAR_ATTRIBUTE;
import static org.hibernate.metamodel.mapping.EntityDiscriminatorMapping.DISCRIMINATOR_ROLE_NAME;
/**
* Abstract SqmPathSource implementation for discriminators
*
* @author Steve Ebersole
*/
public abstract class AbstractDiscriminatorSqmPathSource<D> extends AbstractSqmPathSource<D>
implements ReturnableType<D> {
public AbstractDiscriminatorSqmPathSource(DomainType<D> domainType) {
super( DISCRIMINATOR_ROLE_NAME, null, domainType, SINGULAR_ATTRIBUTE );
}
@Override
public SqmPathSource<?> findSubPathSource(String name) {
throw new IllegalStateException( "Entity discriminator cannot be de-referenced" );
}
@Override
public PersistenceType getPersistenceType() {
return PersistenceType.BASIC;
}
@Override
public Class<D> getJavaType() {
return getExpressibleJavaType().getJavaTypeClass();
}
@Override
public DomainType<D> getSqmType() {
return this;
}
}

View File

@ -7,12 +7,17 @@
package org.hibernate.metamodel.model.domain.internal; package org.hibernate.metamodel.model.domain.internal;
import java.io.Serializable; import java.io.Serializable;
import java.util.Collection;
import org.hibernate.metamodel.UnsupportedMappingException;
import org.hibernate.metamodel.model.domain.AbstractManagedType; import org.hibernate.metamodel.model.domain.AbstractManagedType;
import org.hibernate.metamodel.model.domain.DomainType; import org.hibernate.metamodel.model.domain.DomainType;
import org.hibernate.metamodel.model.domain.EmbeddableDomainType; import org.hibernate.metamodel.model.domain.EmbeddableDomainType;
import org.hibernate.metamodel.model.domain.ManagedDomainType; import org.hibernate.metamodel.model.domain.ManagedDomainType;
import org.hibernate.metamodel.model.domain.PersistentAttribute;
import org.hibernate.metamodel.model.domain.spi.JpaMetamodelImplementor; import org.hibernate.metamodel.model.domain.spi.JpaMetamodelImplementor;
import org.hibernate.query.sqm.SqmPathSource;
import org.hibernate.query.sqm.tree.domain.SqmPath;
import org.hibernate.type.descriptor.java.JavaType; import org.hibernate.type.descriptor.java.JavaType;
import jakarta.persistence.metamodel.SingularAttribute; import jakarta.persistence.metamodel.SingularAttribute;
@ -56,4 +61,40 @@ public class EmbeddableTypeImpl<J>
} }
return count; return count;
} }
@Override
public Collection<? extends EmbeddableDomainType<? extends J>> getSubTypes() {
//noinspection unchecked
return (Collection<? extends EmbeddableDomainType<? extends J>>) super.getSubTypes();
}
@Override
public String getPathName() {
return getTypeName();
}
@Override
public EmbeddableDomainType<J> getSqmPathType() {
return this;
}
@Override
public SqmPathSource<?> findSubPathSource(String name) {
final PersistentAttribute<? super J, ?> attribute = getSqmPathType().findAttribute( name );
if ( attribute != null ) {
return (SqmPathSource<?>) attribute;
}
return (SqmPathSource<?>) findSubTypesAttribute( name );
}
@Override
public SqmPath<J> createSqmPath(SqmPath<?> lhs, SqmPathSource<?> intermediatePathSource) {
throw new UnsupportedMappingException( "EmbeddableType cannot be used to create an SqmPath" );
}
@Override
public BindableType getBindableType() {
return BindableType.SINGULAR_ATTRIBUTE;
}
} }

View File

@ -0,0 +1,60 @@
/*
* 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.metamodel.model.domain.internal;
import org.hibernate.metamodel.model.domain.DiscriminatorSqmPath;
import org.hibernate.metamodel.model.domain.EmbeddableDomainType;
import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.SemanticQueryWalker;
import org.hibernate.query.sqm.SqmPathSource;
import org.hibernate.query.sqm.tree.SqmCopyContext;
import org.hibernate.query.sqm.tree.domain.AbstractSqmPath;
import org.hibernate.query.sqm.tree.domain.SqmPath;
import org.hibernate.spi.NavigablePath;
/**
* {@link SqmPath} specialization for an embeddable discriminator
*
* @author Marco Belladelli
*/
public class EmbeddedDiscriminatorSqmPath<T> extends AbstractSqmPath<T> implements DiscriminatorSqmPath<T> {
private final EmbeddableDomainType<T> embeddableDomainType;
@SuppressWarnings( { "rawtypes", "unchecked" } )
protected EmbeddedDiscriminatorSqmPath(
NavigablePath navigablePath,
SqmPathSource referencedPathSource,
SqmPath<?> lhs,
EmbeddableDomainType embeddableDomainType,
NodeBuilder nodeBuilder) {
super( navigablePath, referencedPathSource, lhs, nodeBuilder );
this.embeddableDomainType = embeddableDomainType;
}
@Override
public EmbeddableDomainType<T> getExpressible() {
return embeddableDomainType;
}
@Override
public EmbeddedDiscriminatorSqmPath<T> copy(SqmCopyContext context) {
final EmbeddedDiscriminatorSqmPath<T> existing = context.getCopy( this );
if ( existing != null ) {
return existing;
}
//noinspection unchecked
return context.registerCopy(
this,
(EmbeddedDiscriminatorSqmPath<T>) getLhs().copy( context ).type()
);
}
@Override
public <X> X accept(SemanticQueryWalker<X> walker) {
return walker.visitDiscriminatorPath( this );
}
}

View File

@ -0,0 +1,36 @@
/*
* 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.metamodel.model.domain.internal;
import org.hibernate.metamodel.model.domain.EmbeddableDomainType;
import org.hibernate.query.sqm.SqmPathSource;
import org.hibernate.query.sqm.tree.domain.SqmPath;
/**
* SqmPathSource implementation for embeddable discriminator
*
* @author Marco Belladelli
*/
public class EmbeddedDiscriminatorSqmPathSource<D> extends AbstractDiscriminatorSqmPathSource<D> {
private final EmbeddableDomainType<D> embeddableDomainType;
public EmbeddedDiscriminatorSqmPathSource(EmbeddableDomainType<D> embeddableDomainType) {
super( embeddableDomainType );
this.embeddableDomainType = embeddableDomainType;
}
@Override
public SqmPath<D> createSqmPath(SqmPath<?> lhs, SqmPathSource<?> intermediatePathSource) {
return new EmbeddedDiscriminatorSqmPath<>(
PathHelper.append( lhs, this, intermediatePathSource ),
pathModel,
lhs,
embeddableDomainType,
lhs.nodeBuilder()
);
}
}

View File

@ -14,6 +14,8 @@ import org.hibernate.query.sqm.SqmPathSource;
import org.hibernate.query.sqm.tree.domain.SqmEmbeddedValuedSimplePath; import org.hibernate.query.sqm.tree.domain.SqmEmbeddedValuedSimplePath;
import org.hibernate.query.sqm.tree.domain.SqmPath; import org.hibernate.query.sqm.tree.domain.SqmPath;
import static org.hibernate.metamodel.mapping.EntityDiscriminatorMapping.DISCRIMINATOR_ROLE_NAME;
/** /**
* @author Steve Ebersole * @author Steve Ebersole
*/ */
@ -21,6 +23,7 @@ public class EmbeddedSqmPathSource<J>
extends AbstractSqmPathSource<J> extends AbstractSqmPathSource<J>
implements CompositeSqmPathSource<J> { implements CompositeSqmPathSource<J> {
private final boolean isGeneric; private final boolean isGeneric;
private final EmbeddedDiscriminatorSqmPathSource<?> discriminatorPathSource;
public EmbeddedSqmPathSource( public EmbeddedSqmPathSource(
String localPathName, String localPathName,
@ -30,6 +33,12 @@ public class EmbeddedSqmPathSource<J>
boolean isGeneric) { boolean isGeneric) {
super( localPathName, pathModel, domainType, jpaBindableType ); super( localPathName, pathModel, domainType, jpaBindableType );
this.isGeneric = isGeneric; this.isGeneric = isGeneric;
if ( domainType.isPolymorphic() ) {
discriminatorPathSource = new EmbeddedDiscriminatorSqmPathSource<>( domainType );
}
else {
discriminatorPathSource = null;
}
} }
@Override @Override
@ -38,18 +47,17 @@ public class EmbeddedSqmPathSource<J>
} }
@Override @Override
public SqmPathSource<?> findSubPathSource(String name, JpaMetamodelImplementor metamodel) { public SqmPathSource<?> findSubPathSource(String name) {
final PersistentAttribute<? super J, ?> attribute = getSqmPathType().findAttribute( name ); final SqmPathSource<?> subPathSource = getSqmPathType().findSubPathSource( name );
if ( attribute != null ) { if ( subPathSource != null ) {
return (SqmPathSource<?>) attribute; return subPathSource;
} }
return (SqmPathSource<?>) getSqmPathType().findSubTypesAttribute( name ); if ( name.equals( DISCRIMINATOR_ROLE_NAME ) && discriminatorPathSource != null ) {
} return discriminatorPathSource;
}
@Override return null;
public SqmPathSource<?> findSubPathSource(String name) {
return (SqmPathSource<?>) getSqmPathType().findAttribute( name );
} }
@Override @Override

View File

@ -49,8 +49,8 @@ public class EntityDiscriminatorSqmPath<T> extends AbstractSqmPath<T> implements
} }
@Override @Override
public DiscriminatorSqmPathSource getExpressible() { public EntityDiscriminatorSqmPathSource getExpressible() {
return (DiscriminatorSqmPathSource) getNodeType(); return (EntityDiscriminatorSqmPathSource) getNodeType();
} }
@Override @Override

View File

@ -9,28 +9,23 @@ package org.hibernate.metamodel.model.domain.internal;
import org.hibernate.metamodel.mapping.EntityMappingType; import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.model.domain.DomainType; import org.hibernate.metamodel.model.domain.DomainType;
import org.hibernate.metamodel.model.domain.EntityDomainType; import org.hibernate.metamodel.model.domain.EntityDomainType;
import org.hibernate.query.ReturnableType;
import org.hibernate.query.sqm.SqmPathSource; import org.hibernate.query.sqm.SqmPathSource;
import org.hibernate.query.sqm.tree.domain.SqmPath; import org.hibernate.query.sqm.tree.domain.SqmPath;
import static jakarta.persistence.metamodel.Bindable.BindableType.SINGULAR_ATTRIBUTE;
import static org.hibernate.metamodel.mapping.EntityDiscriminatorMapping.DISCRIMINATOR_ROLE_NAME;
/** /**
* SqmPathSource implementation for entity discriminator * SqmPathSource implementation for entity discriminator
* *
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public class DiscriminatorSqmPathSource<D> extends AbstractSqmPathSource<D> public class EntityDiscriminatorSqmPathSource<D> extends AbstractDiscriminatorSqmPathSource<D> {
implements ReturnableType<D> {
private final EntityDomainType<?> entityDomainType; private final EntityDomainType<?> entityDomainType;
private final EntityMappingType entityMapping; private final EntityMappingType entityMapping;
public DiscriminatorSqmPathSource( public EntityDiscriminatorSqmPathSource(
DomainType<D> discriminatorValueType, DomainType<D> discriminatorValueType,
EntityDomainType<?> entityDomainType, EntityDomainType<?> entityDomainType,
EntityMappingType entityMapping) { EntityMappingType entityMapping) {
super( DISCRIMINATOR_ROLE_NAME, null, discriminatorValueType, SINGULAR_ATTRIBUTE ); super( discriminatorValueType );
this.entityDomainType = entityDomainType; this.entityDomainType = entityDomainType;
this.entityMapping = entityMapping; this.entityMapping = entityMapping;
} }
@ -54,24 +49,4 @@ public class DiscriminatorSqmPathSource<D> extends AbstractSqmPathSource<D>
lhs.nodeBuilder() lhs.nodeBuilder()
); );
} }
@Override
public SqmPathSource<?> findSubPathSource(String name) {
throw new IllegalStateException( "Entity discriminator cannot be de-referenced" );
}
@Override
public PersistenceType getPersistenceType() {
return PersistenceType.BASIC;
}
@Override
public Class<D> getJavaType() {
return getExpressibleJavaType().getJavaTypeClass();
}
@Override
public DomainType<D> getSqmType() {
return this;
}
} }

View File

@ -85,7 +85,7 @@ public class EntityTypeImpl<J>
.resolve( StandardBasicTypes.STRING ); .resolve( StandardBasicTypes.STRING );
} }
this.discriminatorPathSource = discriminatorType == null ? null : new DiscriminatorSqmPathSource( this.discriminatorPathSource = discriminatorType == null ? null : new EntityDiscriminatorSqmPathSource(
discriminatorType, discriminatorType,
this, this,
entityDescriptor entityDescriptor

View File

@ -10,6 +10,7 @@ import java.io.ObjectStreamException;
import java.io.Serializable; import java.io.Serializable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Collections;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.List; import java.util.List;
@ -17,6 +18,7 @@ import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.TreeMap; import java.util.TreeMap;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
import org.hibernate.boot.model.NamedEntityGraphDefinition; import org.hibernate.boot.model.NamedEntityGraphDefinition;
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService; import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
@ -88,10 +90,9 @@ public class JpaMetamodelImpl implements JpaMetamodelImplementor, Serializable {
private final MappingMetamodel mappingMetamodel; private final MappingMetamodel mappingMetamodel;
private final ServiceRegistry serviceRegistry; private final ServiceRegistry serviceRegistry;
private final Map<String, EntityDomainType<?>> jpaEntityTypeMap = new TreeMap<>(); // Need ordering for deterministic implementers list in SqmPolymorphicRootDescriptor private final Map<String, ManagedDomainType<?>> managedTypeByName = new TreeMap<>();
private final Map<Class<?>, ManagedDomainType<?>> jpaManagedTypeMap = new HashMap<>(); private final Map<Class<?>, ManagedDomainType<?>> managedTypeByClass = new HashMap<>();
private final Set<ManagedDomainType<?>> jpaManagedTypes = new HashSet<>(); private JpaMetaModelPopulationSetting jpaMetaModelPopulationSetting;
private final Set<EmbeddableDomainType<?>> jpaEmbeddables = new HashSet<>();
private final Map<String, Set<String>> allowedEnumLiteralTexts = new HashMap<>(); private final Map<String, Set<String>> allowedEnumLiteralTexts = new HashMap<>();
private final transient Map<String, RootGraphImplementor<?>> entityGraphMap = new ConcurrentHashMap<>(); private final transient Map<String, RootGraphImplementor<?>> entityGraphMap = new ConcurrentHashMap<>();
@ -129,9 +130,35 @@ public class JpaMetamodelImpl implements JpaMetamodelImplementor, Serializable {
} }
@Override @Override
public <X> EntityDomainType<X> entity(String entityName) { public <X> ManagedDomainType<X> managedType(String typeName) {
//noinspection unchecked //noinspection unchecked
return entityName==null ? null : (EntityDomainType<X>) jpaEntityTypeMap.get( entityName ); return typeName == null ? null : (ManagedDomainType<X>) managedTypeByName.get( typeName );
}
@Override
public <X> EntityDomainType<X> entity(String entityName) {
if ( entityName == null ) {
return null;
}
final ManagedDomainType<?> managedType = managedTypeByName.get( entityName );
if ( !( managedType instanceof EntityDomainType<?> ) ) {
return null;
}
//noinspection unchecked
return (EntityDomainType<X>) managedType;
}
@Override
public <X> EmbeddableDomainType<X> embeddable(String embeddableName) {
if ( embeddableName == null ) {
return null;
}
final ManagedDomainType<?> managedType = managedTypeByName.get( embeddableName );
if ( !( managedType instanceof EmbeddableDomainType<?> ) ) {
return null;
}
//noinspection unchecked
return (EmbeddableDomainType<X>) managedType;
} }
@Override @Override
@ -173,13 +200,13 @@ public class JpaMetamodelImpl implements JpaMetamodelImplementor, Serializable {
@Override @Override
public <X> ManagedDomainType<X> findManagedType(Class<X> cls) { public <X> ManagedDomainType<X> findManagedType(Class<X> cls) {
//noinspection unchecked //noinspection unchecked
return (ManagedDomainType<X>) jpaManagedTypeMap.get( cls ); return (ManagedDomainType<X>) managedTypeByClass.get( cls );
} }
@Override @Override
public <X> EntityDomainType<X> findEntityType(Class<X> cls) { public <X> EntityDomainType<X> findEntityType(Class<X> cls) {
final ManagedType<?> type = jpaManagedTypeMap.get( cls ); final ManagedType<?> type = managedTypeByClass.get( cls );
if ( !( type instanceof EntityType<?> ) ) { if ( !( type instanceof EntityDomainType<?> ) ) {
return null; return null;
} }
//noinspection unchecked //noinspection unchecked
@ -188,7 +215,7 @@ public class JpaMetamodelImpl implements JpaMetamodelImplementor, Serializable {
@Override @Override
public <X> ManagedDomainType<X> managedType(Class<X> cls) { public <X> ManagedDomainType<X> managedType(Class<X> cls) {
final ManagedType<?> type = jpaManagedTypeMap.get( cls ); final ManagedType<?> type = managedTypeByClass.get( cls );
if ( type == null ) { if ( type == null ) {
// per JPA // per JPA
throw new IllegalArgumentException( "Not a managed type: " + cls ); throw new IllegalArgumentException( "Not a managed type: " + cls );
@ -200,7 +227,7 @@ public class JpaMetamodelImpl implements JpaMetamodelImplementor, Serializable {
@Override @Override
public <X> EntityDomainType<X> entity(Class<X> cls) { public <X> EntityDomainType<X> entity(Class<X> cls) {
final ManagedType<?> type = jpaManagedTypeMap.get( cls ); final ManagedType<?> type = managedTypeByClass.get( cls );
if ( !( type instanceof EntityDomainType<?> ) ) { if ( !( type instanceof EntityDomainType<?> ) ) {
throw new IllegalArgumentException( "Not an entity: " + cls.getName() ); throw new IllegalArgumentException( "Not an entity: " + cls.getName() );
} }
@ -210,7 +237,7 @@ public class JpaMetamodelImpl implements JpaMetamodelImplementor, Serializable {
@Override @Override
public <X> EmbeddableDomainType<X> embeddable(Class<X> cls) { public <X> EmbeddableDomainType<X> embeddable(Class<X> cls) {
final ManagedType<?> type = jpaManagedTypeMap.get( cls ); final ManagedType<?> type = managedTypeByClass.get( cls );
if ( !( type instanceof EmbeddableDomainType<?> ) ) { if ( !( type instanceof EmbeddableDomainType<?> ) ) {
throw new IllegalArgumentException( "Not an embeddable: " + cls.getName() ); throw new IllegalArgumentException( "Not an embeddable: " + cls.getName() );
} }
@ -218,25 +245,39 @@ public class JpaMetamodelImpl implements JpaMetamodelImplementor, Serializable {
return (EmbeddableDomainType<X>) type; return (EmbeddableDomainType<X>) type;
} }
private Collection<ManagedDomainType<?>> getAllManagedTypes() {
switch ( jpaMetaModelPopulationSetting ) {
case IGNORE_UNSUPPORTED:
return managedTypeByClass.values();
case ENABLED:
return managedTypeByName.values();
case DISABLED:
return Collections.emptySet();
default:
// should never happen
throw new AssertionError();
}
}
@Override @Override
public Set<ManagedType<?>> getManagedTypes() { public Set<ManagedType<?>> getManagedTypes() {
return new HashSet<>( jpaManagedTypes ); return new HashSet<>( getAllManagedTypes() );
} }
@Override @Override
public Set<EntityType<?>> getEntities() { public Set<EntityType<?>> getEntities() {
final Set<EntityType<?>> entityTypes = new HashSet<>( jpaEntityTypeMap.size() ); return getAllManagedTypes().stream()
for ( ManagedDomainType<?> value : jpaManagedTypes ) { .filter( EntityType.class::isInstance )
if ( value instanceof EntityType<?> ) { .map( t -> (EntityType<?>) t )
entityTypes.add( (EntityType<?>) value ); .collect( Collectors.toSet() );
}
}
return entityTypes;
} }
@Override @Override
public Set<EmbeddableType<?>> getEmbeddables() { public Set<EmbeddableType<?>> getEmbeddables() {
return new HashSet<>( jpaEmbeddables ); return getAllManagedTypes().stream()
.filter( EmbeddableType.class::isInstance )
.map( t -> (EmbeddableType<?>) t )
.collect( Collectors.toSet() );
} }
@Override @Override
@ -454,9 +495,9 @@ public class JpaMetamodelImpl implements JpaMetamodelImplementor, Serializable {
public <T> EntityDomainType<T> resolveEntityReference(Class<T> javaType) { public <T> EntityDomainType<T> resolveEntityReference(Class<T> javaType) {
// try the incoming Java type as a "strict" entity reference // try the incoming Java type as a "strict" entity reference
{ {
final EntityDomainType<?> descriptor = jpaEntityTypeMap.get( javaType.getName() ); final ManagedDomainType<?> managedType = managedTypeByClass.get( javaType );
if ( descriptor != null ) { if ( managedType instanceof EntityDomainType<?> ) {
return (EntityDomainType<T>) descriptor; return (EntityDomainType<T>) managedType;
} }
} }
@ -464,7 +505,7 @@ public class JpaMetamodelImpl implements JpaMetamodelImplementor, Serializable {
{ {
final String proxyEntityName = entityProxyInterfaceMap.get( javaType ); final String proxyEntityName = entityProxyInterfaceMap.get( javaType );
if ( proxyEntityName != null ) { if ( proxyEntityName != null ) {
return (EntityDomainType<T>) jpaEntityTypeMap.get( proxyEntityName ); return entity( proxyEntityName );
} }
} }
@ -478,9 +519,12 @@ public class JpaMetamodelImpl implements JpaMetamodelImplementor, Serializable {
// create a set of descriptors that should be used to build the polymorphic EntityDomainType // create a set of descriptors that should be used to build the polymorphic EntityDomainType
final Set<EntityDomainType<? extends T>> matchingDescriptors = new HashSet<>(); final Set<EntityDomainType<? extends T>> matchingDescriptors = new HashSet<>();
for ( EntityDomainType<?> entityDomainType : jpaEntityTypeMap.values() ) { for ( ManagedDomainType<?> managedType : managedTypeByName.values() ) {
if ( managedType.getPersistenceType() != Type.PersistenceType.ENTITY ) {
continue;
}
// see if we should add `entityDomainType` as one of the matching-descriptors. // see if we should add `entityDomainType` as one of the matching-descriptors.
if ( javaType.isAssignableFrom( entityDomainType.getJavaType() ) ) { if ( javaType.isAssignableFrom( managedType.getJavaType() ) ) {
// the queried type is assignable from the type of the current entity-type // the queried type is assignable from the type of the current entity-type
// we should add it to the collecting set of matching descriptors. it should // we should add it to the collecting set of matching descriptors. it should
// be added aside from a few cases... // be added aside from a few cases...
@ -488,7 +532,7 @@ public class JpaMetamodelImpl implements JpaMetamodelImplementor, Serializable {
// it should not be added if its direct super (if one) is defined without // it should not be added if its direct super (if one) is defined without
// explicit-polymorphism. The super itself will get added and the initializers // explicit-polymorphism. The super itself will get added and the initializers
// for entity mappings already handle loading subtypes - adding it would be redundant // for entity mappings already handle loading subtypes - adding it would be redundant
final ManagedDomainType<?> superType = entityDomainType.getSuperType(); final ManagedDomainType<?> superType = managedType.getSuperType();
if ( superType != null if ( superType != null
&& superType.getPersistenceType() == Type.PersistenceType.ENTITY && superType.getPersistenceType() == Type.PersistenceType.ENTITY
&& javaType.isAssignableFrom( superType.getJavaType() ) ) { && javaType.isAssignableFrom( superType.getJavaType() ) ) {
@ -501,13 +545,13 @@ public class JpaMetamodelImpl implements JpaMetamodelImplementor, Serializable {
// it should not be added if it is mapped with explicit polymorphism itself // it should not be added if it is mapped with explicit polymorphism itself
final EntityMappingType entityPersister = getMappingMetamodel() final EntityMappingType entityPersister = getMappingMetamodel()
.getEntityDescriptor( entityDomainType.getHibernateEntityName() ); .getEntityDescriptor( managedType.getTypeName() );
if ( entityPersister.isExplicitPolymorphism() ) { if ( entityPersister.isExplicitPolymorphism() ) {
continue; continue;
} }
// aside from these special cases, add it // aside from these special cases, add it
matchingDescriptors.add( (EntityDomainType<? extends T>) entityDomainType ); matchingDescriptors.add( (EntityDomainType<? extends T>) managedType );
} }
} }
@ -558,55 +602,27 @@ public class JpaMetamodelImpl implements JpaMetamodelImplementor, Serializable {
context.wrapUp(); context.wrapUp();
for ( Map.Entry<String, IdentifiableDomainType<?>> entry : context.getIdentifiableTypesByName().entrySet() ) { this.jpaMetaModelPopulationSetting = jpaMetaModelPopulationSetting;
if ( entry.getValue() instanceof EntityDomainType<?> ) {
this.jpaEntityTypeMap.put( entry.getKey(), (EntityDomainType<?>) entry.getValue() );
}
}
this.jpaManagedTypeMap.putAll( context.getEntityTypeMap() ); // Identifiable types (Entities and MappedSuperclasses)
this.jpaManagedTypeMap.putAll( context.getMappedSuperclassTypeMap() ); this.managedTypeByName.putAll( context.getIdentifiableTypesByName() );
switch ( jpaMetaModelPopulationSetting ) { this.managedTypeByClass.putAll( context.getEntityTypeMap() );
case IGNORE_UNSUPPORTED: this.managedTypeByClass.putAll( context.getMappedSuperclassTypeMap() );
this.jpaManagedTypes.addAll( context.getEntityTypeMap().values() );
this.jpaManagedTypes.addAll( context.getMappedSuperclassTypeMap().values() );
break;
case ENABLED:
this.jpaManagedTypes.addAll( context.getIdentifiableTypesByName().values() );
break;
}
// Embeddable types
int mapEmbeddables = 0;
for ( EmbeddableDomainType<?> embeddable : context.getEmbeddableTypeSet() ) { for ( EmbeddableDomainType<?> embeddable : context.getEmbeddableTypeSet() ) {
// Do not register the embeddable types for id classes // Do not register the embeddable types for id classes
if ( embeddable.getExpressibleJavaType() instanceof EntityJavaType<?> ) { if ( embeddable.getExpressibleJavaType() instanceof EntityJavaType<?> ) {
continue; continue;
} }
switch ( jpaMetaModelPopulationSetting ) { final Class<?> embeddableClass = embeddable.getJavaType();
case IGNORE_UNSUPPORTED: if ( embeddableClass != Map.class ) {
if ( embeddable.getJavaType() != null && embeddable.getJavaType() != Map.class ) { this.managedTypeByClass.put( embeddable.getJavaType(), embeddable );
this.jpaEmbeddables.add( embeddable ); this.managedTypeByName.put( embeddable.getTypeName(), embeddable );
this.jpaManagedTypes.add( embeddable ); }
if ( !( embeddable.getExpressibleJavaType() instanceof EntityJavaType<?> ) ) { else {
this.jpaManagedTypeMap.put( embeddable.getJavaType(), embeddable ); this.managedTypeByName.put( "dynamic-embeddable-" + mapEmbeddables++, embeddable );
}
}
break;
case ENABLED:
this.jpaEmbeddables.add( embeddable );
this.jpaManagedTypes.add( embeddable );
if ( embeddable.getJavaType() != null
&& !( embeddable.getExpressibleJavaType() instanceof EntityJavaType<?> ) ) {
this.jpaManagedTypeMap.put( embeddable.getJavaType(), embeddable );
}
break;
case DISABLED:
if ( embeddable.getJavaType() == null ) {
throw new UnsupportedOperationException( "ANY not supported" );
}
if ( !( embeddable.getExpressibleJavaType() instanceof EntityJavaType<?> ) ) {
this.jpaManagedTypeMap.put( embeddable.getJavaType(), embeddable );
}
break;
} }
} }

View File

@ -489,11 +489,21 @@ public class MappingMetamodelImpl extends QueryParameterBindingTypeResolverImpl
return jpaMetamodel.getEmbeddables(); return jpaMetamodel.getEmbeddables();
} }
@Override
public <X> ManagedDomainType<X> managedType(String typeName) {
return jpaMetamodel.managedType( typeName );
}
@Override @Override
public <X> EntityDomainType<X> entity(String entityName) { public <X> EntityDomainType<X> entity(String entityName) {
return jpaMetamodel.entity( entityName ); return jpaMetamodel.entity( entityName );
} }
@Override
public <X> EmbeddableDomainType<X> embeddable(String embeddableName) {
return jpaMetamodel.embeddable( embeddableName );
}
@Override @Override
public <X> EntityDomainType<X> getHqlEntityReference(String entityName) { public <X> EntityDomainType<X> getHqlEntityReference(String entityName) {
return jpaMetamodel.getHqlEntityReference( entityName ); return jpaMetamodel.getHqlEntityReference( entityName );

View File

@ -97,7 +97,7 @@ public class DiscriminatorHelper {
); );
} }
private static <T> String jdbcLiteral( public static <T> String jdbcLiteral(
T value, T value,
JdbcLiteralFormatter<T> formatter, JdbcLiteralFormatter<T> formatter,
Dialect dialect) { Dialect dialect) {

View File

@ -9,7 +9,9 @@ package org.hibernate.query.hql.internal;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService; import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
import org.hibernate.metamodel.model.domain.EmbeddableDomainType;
import org.hibernate.metamodel.model.domain.EntityDomainType; import org.hibernate.metamodel.model.domain.EntityDomainType;
import org.hibernate.metamodel.model.domain.ManagedDomainType;
import org.hibernate.metamodel.model.domain.spi.JpaMetamodelImplementor; import org.hibernate.metamodel.model.domain.spi.JpaMetamodelImplementor;
import org.hibernate.query.SemanticException; import org.hibernate.query.SemanticException;
import org.hibernate.query.hql.HqlLogging; import org.hibernate.query.hql.HqlLogging;
@ -24,6 +26,7 @@ import org.hibernate.query.sqm.tree.domain.SqmPath;
import org.hibernate.query.sqm.tree.expression.SqmEnumLiteral; import org.hibernate.query.sqm.tree.expression.SqmEnumLiteral;
import org.hibernate.query.sqm.tree.expression.SqmExpression; import org.hibernate.query.sqm.tree.expression.SqmExpression;
import org.hibernate.query.sqm.tree.expression.SqmFieldLiteral; import org.hibernate.query.sqm.tree.expression.SqmFieldLiteral;
import org.hibernate.query.sqm.tree.expression.SqmLiteralEmbeddableType;
import org.hibernate.query.sqm.tree.expression.SqmLiteralEntityType; import org.hibernate.query.sqm.tree.expression.SqmLiteralEntityType;
import org.hibernate.query.sqm.tree.from.SqmFrom; import org.hibernate.query.sqm.tree.from.SqmFrom;
import org.hibernate.type.descriptor.java.EnumJavaType; import org.hibernate.type.descriptor.java.EnumJavaType;
@ -93,9 +96,16 @@ public class BasicDotIdentifierConsumer implements DotIdentifierConsumer {
} }
@Override @Override
public void consumeTreat(String entityName, boolean isTerminal) { public void consumeTreat(String importableName, boolean isTerminal) {
final SqmPath<?> path = (SqmPath<?>) currentPart; final SqmPath<?> sqmPath = (SqmPath<?>) currentPart;
currentPart = path.treatAs( creationState.getCreationContext().getJpaMetamodel().entity( entityName ) ); currentPart = sqmPath.treatAs( treatTarget( importableName ) );
}
private <T> Class<T> treatTarget(String typeName) {
final ManagedDomainType<T> managedType = creationState.getCreationContext()
.getJpaMetamodel()
.managedType( typeName );
return managedType.getJavaType();
} }
protected void reset() { protected void reset() {
@ -181,9 +191,12 @@ public class BasicDotIdentifierConsumer implements DotIdentifierConsumer {
final String importableName = jpaMetamodel.qualifyImportableName( path ); final String importableName = jpaMetamodel.qualifyImportableName( path );
final NodeBuilder nodeBuilder = creationContext.getNodeBuilder(); final NodeBuilder nodeBuilder = creationContext.getNodeBuilder();
if ( importableName != null ) { if ( importableName != null ) {
final EntityDomainType<?> entityDomainType = jpaMetamodel.entity( importableName ); final ManagedDomainType<?> managedType = jpaMetamodel.managedType( importableName );
if ( entityDomainType != null ) { if ( managedType instanceof EntityDomainType<?> ) {
return new SqmLiteralEntityType<>( entityDomainType, nodeBuilder ); return new SqmLiteralEntityType<>( ( (EntityDomainType<?>) managedType ), nodeBuilder );
}
else if ( managedType instanceof EmbeddableDomainType<?> ) {
return new SqmLiteralEmbeddableType<>( ( (EmbeddableDomainType<?>) managedType ), nodeBuilder );
} }
} }

View File

@ -7,6 +7,7 @@
package org.hibernate.query.hql.internal; package org.hibernate.query.hql.internal;
import org.hibernate.metamodel.model.domain.EntityDomainType; import org.hibernate.metamodel.model.domain.EntityDomainType;
import org.hibernate.metamodel.model.domain.ManagedDomainType;
import org.hibernate.query.PathException; import org.hibernate.query.PathException;
import org.hibernate.query.SemanticException; import org.hibernate.query.SemanticException;
import org.hibernate.query.hql.spi.DotIdentifierConsumer; import org.hibernate.query.hql.spi.DotIdentifierConsumer;
@ -239,7 +240,7 @@ public class QualifiedJoinPathConsumer implements DotIdentifierConsumer {
private interface ConsumerDelegate { private interface ConsumerDelegate {
void consumeIdentifier(String identifier, boolean isTerminal, boolean allowReuse); void consumeIdentifier(String identifier, boolean isTerminal, boolean allowReuse);
void consumeTreat(String entityName, boolean isTerminal); void consumeTreat(String typeName, boolean isTerminal);
SemanticPathPart getConsumedPart(); SemanticPathPart getConsumedPart();
} }
@ -280,20 +281,23 @@ public class QualifiedJoinPathConsumer implements DotIdentifierConsumer {
} }
@Override @Override
public void consumeTreat(String entityName, boolean isTerminal) { public void consumeTreat(String typeName, boolean isTerminal) {
if ( isTerminal ) { if ( isTerminal ) {
currentPath = fetch currentPath = fetch
? ( (SqmAttributeJoin<?, ?>) currentPath ).treatAs( treatTarget( entityName ), alias, true ) ? ( (SqmAttributeJoin<?, ?>) currentPath ).treatAs( treatTarget( typeName ), alias, true )
: currentPath.treatAs( treatTarget( entityName ), alias ); : currentPath.treatAs( treatTarget( typeName ), alias );
} }
else { else {
currentPath = currentPath.treatAs( treatTarget( entityName ) ); currentPath = currentPath.treatAs( treatTarget( typeName ) );
} }
creationState.getCurrentProcessingState().getPathRegistry().register( currentPath ); creationState.getCurrentProcessingState().getPathRegistry().register( currentPath );
} }
private <T> EntityDomainType<T> treatTarget(String entityName) { private <T> Class<T> treatTarget(String typeName) {
return creationState.getCreationContext().getJpaMetamodel().entity(entityName); final ManagedDomainType<T> managedType = creationState.getCreationContext()
.getJpaMetamodel()
.managedType( typeName );
return managedType.getJavaType();
} }
@Override @Override
@ -364,7 +368,7 @@ public class QualifiedJoinPathConsumer implements DotIdentifierConsumer {
} }
@Override @Override
public void consumeTreat(String entityName, boolean isTerminal) { public void consumeTreat(String typeName, boolean isTerminal) {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }

View File

@ -5481,14 +5481,13 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
consumeManagedTypeReference( ctx.path() ); consumeManagedTypeReference( ctx.path() );
final String treatTargetName = ctx.simplePath().getText(); final String treatTargetName = ctx.simplePath().getText();
final String treatTargetEntityName = final String importableName = getCreationContext().getJpaMetamodel().qualifyImportableName( treatTargetName );
getCreationContext().getJpaMetamodel().qualifyImportableName( treatTargetName ); if ( importableName == null ) {
if ( treatTargetEntityName == null ) {
throw new SemanticException( "Could not resolve treat target type '" + treatTargetName + "'", query ); throw new SemanticException( "Could not resolve treat target type '" + treatTargetName + "'", query );
} }
final boolean hasContinuation = ctx.getChildCount() == 7; final boolean hasContinuation = ctx.getChildCount() == 7;
consumer.consumeTreat( treatTargetEntityName, !hasContinuation ); consumer.consumeTreat( importableName, !hasContinuation );
SqmPath<?> result = (SqmPath<?>) consumer.getConsumedPart(); SqmPath<?> result = (SqmPath<?>) consumer.getConsumedPart();
if ( hasContinuation ) { if ( hasContinuation ) {

View File

@ -8,8 +8,8 @@ package org.hibernate.query.sqm;
import java.util.List; import java.util.List;
import org.hibernate.metamodel.model.domain.DiscriminatorSqmPath;
import org.hibernate.metamodel.model.domain.internal.AnyDiscriminatorSqmPath; import org.hibernate.metamodel.model.domain.internal.AnyDiscriminatorSqmPath;
import org.hibernate.metamodel.model.domain.internal.EntityDiscriminatorSqmPath;
import org.hibernate.query.sqm.tree.cte.SqmCteContainer; import org.hibernate.query.sqm.tree.cte.SqmCteContainer;
import org.hibernate.query.sqm.tree.cte.SqmCteStatement; import org.hibernate.query.sqm.tree.cte.SqmCteStatement;
import org.hibernate.query.sqm.tree.delete.SqmDeleteStatement; import org.hibernate.query.sqm.tree.delete.SqmDeleteStatement;
@ -67,6 +67,7 @@ import org.hibernate.query.sqm.tree.expression.SqmFormat;
import org.hibernate.query.sqm.tree.expression.SqmFunction; import org.hibernate.query.sqm.tree.expression.SqmFunction;
import org.hibernate.query.sqm.tree.expression.SqmHqlNumericLiteral; import org.hibernate.query.sqm.tree.expression.SqmHqlNumericLiteral;
import org.hibernate.query.sqm.tree.expression.SqmLiteral; import org.hibernate.query.sqm.tree.expression.SqmLiteral;
import org.hibernate.query.sqm.tree.expression.SqmLiteralEmbeddableType;
import org.hibernate.query.sqm.tree.expression.SqmLiteralEntityType; import org.hibernate.query.sqm.tree.expression.SqmLiteralEntityType;
import org.hibernate.query.sqm.tree.expression.SqmModifiedSubQueryExpression; import org.hibernate.query.sqm.tree.expression.SqmModifiedSubQueryExpression;
import org.hibernate.query.sqm.tree.expression.SqmNamedParameter; import org.hibernate.query.sqm.tree.expression.SqmNamedParameter;
@ -238,7 +239,7 @@ public interface SemanticQueryWalker<T> {
T visitFkExpression(SqmFkExpression<?> fkExpression); T visitFkExpression(SqmFkExpression<?> fkExpression);
T visitDiscriminatorPath(EntityDiscriminatorSqmPath sqmPath); T visitDiscriminatorPath(DiscriminatorSqmPath<?> sqmPath);
T visitIndexedPluralAccessPath(SqmIndexedCollectionAccessPath<?> path); T visitIndexedPluralAccessPath(SqmIndexedCollectionAccessPath<?> path);
@ -320,6 +321,8 @@ public interface SemanticQueryWalker<T> {
T visitEntityTypeLiteralExpression(SqmLiteralEntityType<?> expression); T visitEntityTypeLiteralExpression(SqmLiteralEntityType<?> expression);
T visitEmbeddableTypeLiteralExpression(SqmLiteralEmbeddableType<?> expression);
T visitAnyDiscriminatorTypeExpression(AnyDiscriminatorSqmPath<?> expression); T visitAnyDiscriminatorTypeExpression(AnyDiscriminatorSqmPath<?> expression);
T visitAnyDiscriminatorTypeValueExpression(SqmAnyDiscriminatorValue<?> expression); T visitAnyDiscriminatorTypeValueExpression(SqmAnyDiscriminatorValue<?> expression);

View File

@ -21,6 +21,7 @@ import org.hibernate.metamodel.model.domain.BasicDomainType;
import org.hibernate.metamodel.model.domain.DomainType; import org.hibernate.metamodel.model.domain.DomainType;
import org.hibernate.metamodel.model.domain.EmbeddableDomainType; import org.hibernate.metamodel.model.domain.EmbeddableDomainType;
import org.hibernate.metamodel.model.domain.EntityDomainType; import org.hibernate.metamodel.model.domain.EntityDomainType;
import org.hibernate.metamodel.model.domain.ManagedDomainType;
import org.hibernate.metamodel.model.domain.MappedSuperclassDomainType; import org.hibernate.metamodel.model.domain.MappedSuperclassDomainType;
import org.hibernate.metamodel.model.domain.internal.AnyMappingSqmPathSource; import org.hibernate.metamodel.model.domain.internal.AnyMappingSqmPathSource;
import org.hibernate.metamodel.model.domain.internal.BasicSqmPathSource; import org.hibernate.metamodel.model.domain.internal.BasicSqmPathSource;
@ -35,7 +36,6 @@ import org.hibernate.query.sqm.tree.SqmTypedNode;
import org.hibernate.query.sqm.tree.cte.SqmCteTable; import org.hibernate.query.sqm.tree.cte.SqmCteTable;
import org.hibernate.query.sqm.tree.domain.AbstractSqmSpecificPluralPartPath; import org.hibernate.query.sqm.tree.domain.AbstractSqmSpecificPluralPartPath;
import org.hibernate.query.sqm.tree.domain.SqmPath; import org.hibernate.query.sqm.tree.domain.SqmPath;
import org.hibernate.query.sqm.tree.domain.SqmPolymorphicRootDescriptor;
import org.hibernate.query.sqm.tree.domain.SqmTreatedPath; import org.hibernate.query.sqm.tree.domain.SqmTreatedPath;
import org.hibernate.spi.NavigablePath; import org.hibernate.spi.NavigablePath;
import org.hibernate.sql.ast.tree.from.TableGroup; import org.hibernate.sql.ast.tree.from.TableGroup;
@ -43,6 +43,7 @@ import org.hibernate.type.BasicType;
import org.hibernate.type.descriptor.java.JavaType; import org.hibernate.type.descriptor.java.JavaType;
import jakarta.persistence.metamodel.Bindable; import jakarta.persistence.metamodel.Bindable;
import jakarta.persistence.metamodel.Type;
/** /**
* Helper for dealing with Hibernate's "mapping model" while processing an SQM which is defined * Helper for dealing with Hibernate's "mapping model" while processing an SQM which is defined
@ -180,17 +181,21 @@ public class SqmMappingModelHelper {
if ( sqmPath instanceof SqmTreatedPath<?, ?> ) { if ( sqmPath instanceof SqmTreatedPath<?, ?> ) {
final SqmTreatedPath<?, ?> treatedPath = (SqmTreatedPath<?, ?>) sqmPath; final SqmTreatedPath<?, ?> treatedPath = (SqmTreatedPath<?, ?>) sqmPath;
final EntityDomainType<?> treatTargetType = treatedPath.getTreatTarget(); final ManagedDomainType<?> treatTarget = treatedPath.getTreatTarget();
return domainModel.findEntityDescriptor( treatTargetType.getHibernateEntityName() ); if ( treatTarget.getPersistenceType() == Type.PersistenceType.ENTITY ) {
final EntityDomainType<?> treatTargetType = (EntityDomainType<?>) treatTarget;
return domainModel.findEntityDescriptor( treatTargetType.getHibernateEntityName() );
}
} }
// see if the LHS is treated // see if the LHS is treated
if ( sqmPath.getLhs() instanceof SqmTreatedPath<?, ?> ) { if ( sqmPath.getLhs() instanceof SqmTreatedPath<?, ?> ) {
final SqmTreatedPath<?, ?> treatedPath = (SqmTreatedPath<?, ?>) sqmPath.getLhs(); final SqmTreatedPath<?, ?> treatedPath = (SqmTreatedPath<?, ?>) sqmPath.getLhs();
final EntityDomainType<?> treatTargetType = treatedPath.getTreatTarget(); final ManagedDomainType<?> treatTarget = treatedPath.getTreatTarget();
final EntityPersister container = domainModel.findEntityDescriptor( treatTargetType.getHibernateEntityName() ); if ( treatTarget.getPersistenceType() == Type.PersistenceType.ENTITY ) {
final EntityPersister container = domainModel.findEntityDescriptor( treatTarget.getTypeName() );
return container.findSubPart( sqmPath.getNavigablePath().getLocalName(), container ); return container.findSubPart( sqmPath.getNavigablePath().getLocalName(), container );
}
} }
// Plural path parts are not joined and thus also have no table group // Plural path parts are not joined and thus also have no table group
@ -253,9 +258,15 @@ public class SqmMappingModelHelper {
SqmPath<?> sqmPath, SqmPath<?> sqmPath,
SqmToSqlAstConverter converter) { SqmToSqlAstConverter converter) {
final SqmPath<?> parentPath = sqmPath.getLhs(); final SqmPath<?> parentPath = sqmPath.getLhs();
if ( parentPath instanceof SqmTreatedPath ) { if ( parentPath instanceof SqmTreatedPath<?, ?> ) {
final SqmTreatedPath<?, ?> treatedPath = (SqmTreatedPath<?, ?>) parentPath; final SqmTreatedPath<?, ?> treatedPath = (SqmTreatedPath<?, ?>) parentPath;
return resolveEntityPersister( treatedPath.getTreatTarget(), converter.getCreationContext().getSessionFactory() ); final ManagedDomainType<?> treatTarget = treatedPath.getTreatTarget();
if ( treatTarget.getPersistenceType() == Type.PersistenceType.ENTITY ) {
return resolveEntityPersister(
( (EntityDomainType<?>) treatTarget ),
converter.getCreationContext().getSessionFactory()
);
}
} }
return null; return null;

View File

@ -9,8 +9,8 @@ package org.hibernate.query.sqm.internal;
import java.util.List; import java.util.List;
import java.util.Locale; import java.util.Locale;
import org.hibernate.metamodel.model.domain.DiscriminatorSqmPath;
import org.hibernate.metamodel.model.domain.internal.AnyDiscriminatorSqmPath; import org.hibernate.metamodel.model.domain.internal.AnyDiscriminatorSqmPath;
import org.hibernate.metamodel.model.domain.internal.EntityDiscriminatorSqmPath;
import org.hibernate.query.QueryLogging; import org.hibernate.query.QueryLogging;
import org.hibernate.query.sqm.SemanticQueryWalker; import org.hibernate.query.sqm.SemanticQueryWalker;
import org.hibernate.query.sqm.tree.SqmStatement; import org.hibernate.query.sqm.tree.SqmStatement;
@ -56,6 +56,7 @@ import org.hibernate.query.sqm.tree.expression.SqmFormat;
import org.hibernate.query.sqm.tree.expression.SqmFunction; import org.hibernate.query.sqm.tree.expression.SqmFunction;
import org.hibernate.query.sqm.tree.expression.SqmHqlNumericLiteral; import org.hibernate.query.sqm.tree.expression.SqmHqlNumericLiteral;
import org.hibernate.query.sqm.tree.expression.SqmLiteral; import org.hibernate.query.sqm.tree.expression.SqmLiteral;
import org.hibernate.query.sqm.tree.expression.SqmLiteralEmbeddableType;
import org.hibernate.query.sqm.tree.expression.SqmLiteralEntityType; import org.hibernate.query.sqm.tree.expression.SqmLiteralEntityType;
import org.hibernate.query.sqm.tree.expression.SqmModifiedSubQueryExpression; import org.hibernate.query.sqm.tree.expression.SqmModifiedSubQueryExpression;
import org.hibernate.query.sqm.tree.expression.SqmNamedParameter; import org.hibernate.query.sqm.tree.expression.SqmNamedParameter;
@ -723,7 +724,7 @@ public class SqmTreePrinter implements SemanticQueryWalker<Object> {
} }
@Override @Override
public Object visitDiscriminatorPath(EntityDiscriminatorSqmPath sqmPath) { public Object visitDiscriminatorPath(DiscriminatorSqmPath<?> sqmPath) {
logWithIndentation( "-> [discriminator-path] - `%s`", sqmPath.getNavigablePath() ); logWithIndentation( "-> [discriminator-path] - `%s`", sqmPath.getNavigablePath() );
return null; return null;
@ -807,6 +808,11 @@ public class SqmTreePrinter implements SemanticQueryWalker<Object> {
return null; return null;
} }
@Override
public Object visitEmbeddableTypeLiteralExpression(SqmLiteralEmbeddableType<?> expression) {
return null;
}
@Override @Override
public Object visitParameterizedEntityTypeExpression(SqmParameterizedEntityType expression) { public Object visitParameterizedEntityTypeExpression(SqmParameterizedEntityType expression) {
return null; return null;

View File

@ -7,13 +7,14 @@
package org.hibernate.query.sqm.internal; package org.hibernate.query.sqm.internal;
import jakarta.persistence.criteria.Expression; import jakarta.persistence.criteria.Expression;
import jakarta.persistence.metamodel.EmbeddableType;
import jakarta.persistence.metamodel.EntityType; import jakarta.persistence.metamodel.EntityType;
import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.metamodel.mapping.JdbcMapping; import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.model.domain.DomainType; import org.hibernate.metamodel.model.domain.DomainType;
import org.hibernate.metamodel.model.domain.EmbeddableDomainType;
import org.hibernate.metamodel.model.domain.ManagedDomainType;
import org.hibernate.metamodel.model.domain.TupleType; import org.hibernate.metamodel.model.domain.TupleType;
import org.hibernate.metamodel.model.domain.internal.DiscriminatorSqmPathSource; import org.hibernate.metamodel.model.domain.internal.EntityDiscriminatorSqmPathSource;
import org.hibernate.persister.entity.EntityPersister; import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.query.SemanticException; import org.hibernate.query.SemanticException;
import org.hibernate.query.sqm.BinaryArithmeticOperator; import org.hibernate.query.sqm.BinaryArithmeticOperator;
@ -128,8 +129,8 @@ public class TypecheckUtil {
// for embeddables, the embeddable class must match exactly // for embeddables, the embeddable class must match exactly
final EmbeddableType<?> lhsEmbeddable = getEmbeddableType( lhsDomainType ); final EmbeddableDomainType<?> lhsEmbeddable = getEmbeddableType( lhsDomainType );
final EmbeddableType<?> rhsEmbeddable = getEmbeddableType( rhsDomainType ); final EmbeddableDomainType<?> rhsEmbeddable = getEmbeddableType( rhsDomainType );
if ( lhsEmbeddable != null && rhsEmbeddable != null ) { if ( lhsEmbeddable != null && rhsEmbeddable != null ) {
return areEmbeddableTypesComparable( lhsEmbeddable, rhsEmbeddable ); return areEmbeddableTypesComparable( lhsEmbeddable, rhsEmbeddable );
} }
@ -157,11 +158,11 @@ public class TypecheckUtil {
// entities can be compared to discriminators if they belong to // entities can be compared to discriminators if they belong to
// the same inheritance hierarchy // the same inheritance hierarchy
if ( lhsDomainType instanceof DiscriminatorSqmPathSource ) { if ( lhsDomainType instanceof EntityDiscriminatorSqmPathSource ) {
return isDiscriminatorTypeComparable( (DiscriminatorSqmPathSource<?>) lhsDomainType, rhsDomainType, factory ); return isDiscriminatorTypeComparable( (EntityDiscriminatorSqmPathSource<?>) lhsDomainType, rhsDomainType, factory );
} }
if ( rhsDomainType instanceof DiscriminatorSqmPathSource ) { if ( rhsDomainType instanceof EntityDiscriminatorSqmPathSource ) {
return isDiscriminatorTypeComparable( (DiscriminatorSqmPathSource<?>) rhsDomainType, lhsDomainType, factory ); return isDiscriminatorTypeComparable( (EntityDiscriminatorSqmPathSource<?>) rhsDomainType, lhsDomainType, factory );
} }
// Treat the expressions as comparable if they belong to the same // Treat the expressions as comparable if they belong to the same
@ -197,15 +198,26 @@ public class TypecheckUtil {
return false; return false;
} }
private static EmbeddableType<?> getEmbeddableType(SqmExpressible<?> expressible) { private static EmbeddableDomainType<?> getEmbeddableType(SqmExpressible<?> expressible) {
return expressible instanceof EmbeddableType<?> ? (EmbeddableType<?>) expressible : null; return expressible instanceof EmbeddableDomainType<?> ? (EmbeddableDomainType<?>) expressible : null;
} }
private static boolean areEmbeddableTypesComparable( private static boolean areEmbeddableTypesComparable(
EmbeddableType<?> lhsType, EmbeddableDomainType<?> lhsType,
EmbeddableType<?> rhsType) { EmbeddableDomainType<?> rhsType) {
// no polymorphism for embeddable types if ( rhsType.getJavaType() == lhsType.getJavaType() ) {
return rhsType.getJavaType() == lhsType.getJavaType(); return true;
}
return lhsType.isPolymorphic() && getRootEmbeddableType( lhsType ) == getRootEmbeddableType( rhsType );
}
private static ManagedDomainType<?> getRootEmbeddableType(EmbeddableDomainType<?> embeddableType) {
ManagedDomainType<?> rootType = embeddableType;
while ( rootType.getSuperType() != null ) {
rootType = rootType.getSuperType();
}
return rootType;
} }
private static boolean areTupleTypesComparable( private static boolean areTupleTypesComparable(
@ -234,7 +246,7 @@ public class TypecheckUtil {
} }
private static boolean isDiscriminatorTypeComparable( private static boolean isDiscriminatorTypeComparable(
DiscriminatorSqmPathSource<?> lhsDiscriminator, SqmExpressible<?> rhsType, EntityDiscriminatorSqmPathSource<?> lhsDiscriminator, SqmExpressible<?> rhsType,
SessionFactoryImplementor factory) { SessionFactoryImplementor factory) {
String entityName = lhsDiscriminator.getEntityDomainType().getHibernateEntityName(); String entityName = lhsDiscriminator.getEntityDomainType().getHibernateEntityName();
EntityPersister lhsEntity = factory.getMappingMetamodel().getEntityDescriptor( entityName ); EntityPersister lhsEntity = factory.getMappingMetamodel().getEntityDescriptor( entityName );
@ -243,8 +255,8 @@ public class TypecheckUtil {
EntityPersister rhsEntity = getEntityDescriptor( factory, rhsEntityName ); EntityPersister rhsEntity = getEntityDescriptor( factory, rhsEntityName );
return lhsEntity.getRootEntityName().equals( rhsEntity.getRootEntityName() ); return lhsEntity.getRootEntityName().equals( rhsEntity.getRootEntityName() );
} }
else if ( rhsType instanceof DiscriminatorSqmPathSource ) { else if ( rhsType instanceof EntityDiscriminatorSqmPathSource ) {
DiscriminatorSqmPathSource<?> discriminator = (DiscriminatorSqmPathSource<?>) rhsType; EntityDiscriminatorSqmPathSource<?> discriminator = (EntityDiscriminatorSqmPathSource<?>) rhsType;
String rhsEntityName = discriminator.getEntityDomainType().getHibernateEntityName(); String rhsEntityName = discriminator.getEntityDomainType().getHibernateEntityName();
EntityPersister rhsEntity = factory.getMappingMetamodel().getEntityDescriptor( rhsEntityName ); EntityPersister rhsEntity = factory.getMappingMetamodel().getEntityDescriptor( rhsEntityName );
return rhsEntity.getRootEntityName().equals( lhsEntity.getRootEntityName() ); return rhsEntity.getRootEntityName().equals( lhsEntity.getRootEntityName() );

View File

@ -8,8 +8,8 @@ package org.hibernate.query.sqm.spi;
import java.util.List; import java.util.List;
import org.hibernate.metamodel.model.domain.DiscriminatorSqmPath;
import org.hibernate.metamodel.model.domain.internal.AnyDiscriminatorSqmPath; import org.hibernate.metamodel.model.domain.internal.AnyDiscriminatorSqmPath;
import org.hibernate.metamodel.model.domain.internal.EntityDiscriminatorSqmPath;
import org.hibernate.query.sqm.InterpretationException; import org.hibernate.query.sqm.InterpretationException;
import org.hibernate.query.sqm.SemanticQueryWalker; import org.hibernate.query.sqm.SemanticQueryWalker;
import org.hibernate.query.sqm.tree.SqmVisitableNode; import org.hibernate.query.sqm.tree.SqmVisitableNode;
@ -57,6 +57,7 @@ import org.hibernate.query.sqm.tree.expression.SqmFormat;
import org.hibernate.query.sqm.tree.expression.SqmFunction; import org.hibernate.query.sqm.tree.expression.SqmFunction;
import org.hibernate.query.sqm.tree.expression.SqmHqlNumericLiteral; import org.hibernate.query.sqm.tree.expression.SqmHqlNumericLiteral;
import org.hibernate.query.sqm.tree.expression.SqmLiteral; import org.hibernate.query.sqm.tree.expression.SqmLiteral;
import org.hibernate.query.sqm.tree.expression.SqmLiteralEmbeddableType;
import org.hibernate.query.sqm.tree.expression.SqmLiteralEntityType; import org.hibernate.query.sqm.tree.expression.SqmLiteralEntityType;
import org.hibernate.query.sqm.tree.expression.SqmModifiedSubQueryExpression; import org.hibernate.query.sqm.tree.expression.SqmModifiedSubQueryExpression;
import org.hibernate.query.sqm.tree.expression.SqmNamedParameter; import org.hibernate.query.sqm.tree.expression.SqmNamedParameter;
@ -468,7 +469,7 @@ public abstract class BaseSemanticQueryWalker implements SemanticQueryWalker<Obj
} }
@Override @Override
public Object visitDiscriminatorPath(EntityDiscriminatorSqmPath path) { public Object visitDiscriminatorPath(DiscriminatorSqmPath<?> path) {
return path; return path;
} }
@ -719,6 +720,11 @@ public abstract class BaseSemanticQueryWalker implements SemanticQueryWalker<Obj
return expression; return expression;
} }
@Override
public Object visitEmbeddableTypeLiteralExpression(SqmLiteralEmbeddableType<?> expression) {
return expression;
}
@Override @Override
public Object visitAnyDiscriminatorTypeExpression(AnyDiscriminatorSqmPath<?> expression) { public Object visitAnyDiscriminatorTypeExpression(AnyDiscriminatorSqmPath<?> expression) {
return expression; return expression;

View File

@ -74,8 +74,10 @@ import org.hibernate.metamodel.mapping.internal.SqlTypedMappingImpl;
import org.hibernate.metamodel.mapping.internal.ToOneAttributeMapping; import org.hibernate.metamodel.mapping.internal.ToOneAttributeMapping;
import org.hibernate.metamodel.mapping.ordering.OrderByFragment; import org.hibernate.metamodel.mapping.ordering.OrderByFragment;
import org.hibernate.metamodel.model.domain.BasicDomainType; import org.hibernate.metamodel.model.domain.BasicDomainType;
import org.hibernate.metamodel.model.domain.DiscriminatorSqmPath;
import org.hibernate.metamodel.model.domain.EmbeddableDomainType; import org.hibernate.metamodel.model.domain.EmbeddableDomainType;
import org.hibernate.metamodel.model.domain.EntityDomainType; import org.hibernate.metamodel.model.domain.EntityDomainType;
import org.hibernate.metamodel.model.domain.ManagedDomainType;
import org.hibernate.metamodel.model.domain.PersistentAttribute; import org.hibernate.metamodel.model.domain.PersistentAttribute;
import org.hibernate.metamodel.model.domain.PluralPersistentAttribute; import org.hibernate.metamodel.model.domain.PluralPersistentAttribute;
import org.hibernate.metamodel.model.domain.internal.AnyDiscriminatorSqmPath; import org.hibernate.metamodel.model.domain.internal.AnyDiscriminatorSqmPath;
@ -198,6 +200,7 @@ import org.hibernate.query.sqm.tree.expression.SqmFunction;
import org.hibernate.query.sqm.tree.expression.SqmHqlNumericLiteral; import org.hibernate.query.sqm.tree.expression.SqmHqlNumericLiteral;
import org.hibernate.query.sqm.tree.expression.SqmJpaCriteriaParameterWrapper; import org.hibernate.query.sqm.tree.expression.SqmJpaCriteriaParameterWrapper;
import org.hibernate.query.sqm.tree.expression.SqmLiteral; import org.hibernate.query.sqm.tree.expression.SqmLiteral;
import org.hibernate.query.sqm.tree.expression.SqmLiteralEmbeddableType;
import org.hibernate.query.sqm.tree.expression.SqmLiteralEntityType; import org.hibernate.query.sqm.tree.expression.SqmLiteralEntityType;
import org.hibernate.query.sqm.tree.expression.SqmLiteralNull; import org.hibernate.query.sqm.tree.expression.SqmLiteralNull;
import org.hibernate.query.sqm.tree.expression.SqmModifiedSubQueryExpression; import org.hibernate.query.sqm.tree.expression.SqmModifiedSubQueryExpression;
@ -301,6 +304,7 @@ import org.hibernate.sql.ast.tree.expression.ColumnReference;
import org.hibernate.sql.ast.tree.expression.Distinct; import org.hibernate.sql.ast.tree.expression.Distinct;
import org.hibernate.sql.ast.tree.expression.Duration; import org.hibernate.sql.ast.tree.expression.Duration;
import org.hibernate.sql.ast.tree.expression.DurationUnit; import org.hibernate.sql.ast.tree.expression.DurationUnit;
import org.hibernate.sql.ast.tree.expression.EmbeddableTypeLiteral;
import org.hibernate.sql.ast.tree.expression.EntityTypeLiteral; import org.hibernate.sql.ast.tree.expression.EntityTypeLiteral;
import org.hibernate.sql.ast.tree.expression.Every; import org.hibernate.sql.ast.tree.expression.Every;
import org.hibernate.sql.ast.tree.expression.Expression; import org.hibernate.sql.ast.tree.expression.Expression;
@ -424,6 +428,7 @@ import java.util.function.Consumer;
import java.util.function.Function; import java.util.function.Function;
import java.util.function.Supplier; import java.util.function.Supplier;
import static jakarta.persistence.metamodel.Type.PersistenceType.ENTITY;
import static java.util.Collections.singletonList; import static java.util.Collections.singletonList;
import static org.hibernate.boot.model.internal.SoftDeleteHelper.createNonSoftDeletedRestriction; import static org.hibernate.boot.model.internal.SoftDeleteHelper.createNonSoftDeletedRestriction;
import static org.hibernate.generator.EventType.INSERT; import static org.hibernate.generator.EventType.INSERT;
@ -2475,14 +2480,11 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
} }
private Predicate visitWhereClause(SqmPredicate sqmPredicate) { private Predicate visitWhereClause(SqmPredicate sqmPredicate) {
if ( sqmPredicate == null ) {
return null;
}
currentClauseStack.push( Clause.WHERE ); currentClauseStack.push( Clause.WHERE );
inferrableTypeAccessStack.push( () -> null ); inferrableTypeAccessStack.push( () -> null );
try { try {
return combinePredicates( return combinePredicates(
(Predicate) sqmPredicate.accept( this ), sqmPredicate != null ? (Predicate) sqmPredicate.accept( this ) : null,
consumeConjunctTreatTypeRestrictions() consumeConjunctTreatTypeRestrictions()
); );
} }
@ -2494,14 +2496,11 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
@Override @Override
public Predicate visitHavingClause(SqmPredicate sqmPredicate) { public Predicate visitHavingClause(SqmPredicate sqmPredicate) {
if ( sqmPredicate == null ) {
return null;
}
currentClauseStack.push( Clause.HAVING ); currentClauseStack.push( Clause.HAVING );
inferrableTypeAccessStack.push( () -> null ); inferrableTypeAccessStack.push( () -> null );
try { try {
return combinePredicates( return combinePredicates(
(Predicate) sqmPredicate.accept( this ), sqmPredicate != null ? (Predicate) sqmPredicate.accept( this ) : null,
consumeConjunctTreatTypeRestrictions() consumeConjunctTreatTypeRestrictions()
); );
} }
@ -2911,10 +2910,10 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
* If the path is a treat, registers {@link EntityNameUse#TREAT} for all treated subtypes instead. * If the path is a treat, registers {@link EntityNameUse#TREAT} for all treated subtypes instead.
*/ */
private void registerEntityNameProjectionUsage(SqmPath<?> projectedPath, TableGroup tableGroup) { private void registerEntityNameProjectionUsage(SqmPath<?> projectedPath, TableGroup tableGroup) {
final EntityDomainType<?> treatedType; final ManagedDomainType<?> treatedType;
if ( projectedPath instanceof SqmTreatedPath<?, ?> ) { if ( projectedPath instanceof SqmTreatedPath<?, ?> ) {
treatedType = ( (SqmTreatedPath<?, ?>) projectedPath ).getTreatTarget(); treatedType = ( (SqmTreatedPath<?, ?>) projectedPath ).getTreatTarget();
registerEntityNameUsage( tableGroup, EntityNameUse.TREAT, treatedType.getHibernateEntityName(), true ); registerEntityNameUsage( tableGroup, EntityNameUse.TREAT, treatedType.getTypeName(), true );
if ( projectedPath instanceof SqmFrom<?, ?> ) { if ( projectedPath instanceof SqmFrom<?, ?> ) {
// Register that the TREAT uses for the SqmFrom node may not be downgraded // Register that the TREAT uses for the SqmFrom node may not be downgraded
@ -2926,7 +2925,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
} }
else if ( projectedPath.getNodeType().getSqmPathType() instanceof EntityDomainType<?> ) { else if ( projectedPath.getNodeType().getSqmPathType() instanceof EntityDomainType<?> ) {
treatedType = (EntityDomainType<?>) projectedPath.getNodeType().getSqmPathType(); treatedType = (EntityDomainType<?>) projectedPath.getNodeType().getSqmPathType();
registerEntityNameUsage( tableGroup, EntityNameUse.PROJECTION, treatedType.getHibernateEntityName(), true ); registerEntityNameUsage( tableGroup, EntityNameUse.PROJECTION, treatedType.getTypeName(), true );
if ( projectedPath instanceof SqmFrom<?, ?> ) { if ( projectedPath instanceof SqmFrom<?, ?> ) {
// Register that the TREAT uses for the SqmFrom node may not be downgraded // Register that the TREAT uses for the SqmFrom node may not be downgraded
@ -2970,31 +2969,33 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
final EntityMappingType parentType; final EntityMappingType parentType;
if ( parentPath instanceof SqmTreatedPath<?, ?> ) { if ( parentPath instanceof SqmTreatedPath<?, ?> ) {
// A treated attribute usage i.e. `treat(alias as Subtype).attribute = 1` // A treated attribute usage i.e. `treat(alias as Subtype).attribute = 1`
final ManagedDomainType<?> treatTarget = ( (SqmTreatedPath<?, ?>) parentPath ).getTreatTarget();
if ( treatTarget.getPersistenceType() == ENTITY ) {
parentType = creationContext.getMappingMetamodel().getEntityDescriptor( treatTarget.getTypeName() );
final EntityDomainType<?> treatTarget = ( (SqmTreatedPath<?, ?>) parentPath ).getTreatTarget(); // The following is an optimization to avoid rendering treat conditions into predicates.
// Imagine an HQL predicate like `treat(alias as Subtype).attribute is null or alias.name = '...'`.
// If the `attribute` is basic, we will render a case wrapper around the column expression
// and hence we can safely skip adding the `type(alias) = Subtype and ...` condition to the SQL.
parentType = creationContext.getMappingMetamodel() final ModelPart subPart = parentType.findSubPart( attributeName );
.getEntityDescriptor( treatTarget.getHibernateEntityName() ); final EntityNameUse entityNameUse;
// We only apply this optimization for basic valued model parts for now
// The following is an optimization to avoid rendering treat conditions into predicates. if ( subPart.asBasicValuedModelPart() != null ) {
// Imagine an HQL predicate like `treat(alias as Subtype).attribute is null or alias.name = '...'`. entityNameUse = EntityNameUse.OPTIONAL_TREAT;
// If the `attribute` is basic, we will render a case wrapper around the column expression }
// and hence we can safely skip adding the `type(alias) = Subtype and ...` condition to the SQL. else {
entityNameUse = EntityNameUse.BASE_TREAT;
final ModelPart subPart = parentType.findSubPart( attributeName ); }
final EntityNameUse entityNameUse; registerEntityNameUsage(
// We only apply this optimization for basic valued model parts for now tableGroup,
if ( subPart.asBasicValuedModelPart() != null ) { entityNameUse,
entityNameUse = EntityNameUse.OPTIONAL_TREAT; treatTarget.getTypeName()
);
} }
else { else {
entityNameUse = EntityNameUse.BASE_TREAT; parentType = entityType;
} }
registerEntityNameUsage(
tableGroup,
entityNameUse,
treatTarget.getHibernateEntityName()
);
} }
else { else {
// A simple attribute usage e.g. `alias.attribute = 1` // A simple attribute usage e.g. `alias.attribute = 1`
@ -3047,11 +3048,11 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
public void registerEntityNameUsage( public void registerEntityNameUsage(
TableGroup tableGroup, TableGroup tableGroup,
EntityNameUse entityNameUse, EntityNameUse entityNameUse,
String hibernateEntityName) { String treatTargetTypeName) {
registerEntityNameUsage( registerEntityNameUsage(
tableGroup, tableGroup,
entityNameUse, entityNameUse,
hibernateEntityName, treatTargetTypeName,
entityNameUse.getKind() == EntityNameUse.UseKind.PROJECTION entityNameUse.getKind() == EntityNameUse.UseKind.PROJECTION
); );
} }
@ -3059,14 +3060,27 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
private void registerEntityNameUsage( private void registerEntityNameUsage(
TableGroup tableGroup, TableGroup tableGroup,
EntityNameUse entityNameUse, EntityNameUse entityNameUse,
String hibernateEntityName, String treatTargetTypeName,
boolean projection) { boolean projection) {
final AbstractEntityPersister persister = (AbstractEntityPersister) creationContext.getSessionFactory() final AbstractEntityPersister persister;
.getRuntimeMetamodels() if ( tableGroup.getModelPart() instanceof EmbeddableValuedModelPart ) {
.getMappingMetamodel() persister = null;
.findEntityDescriptor( hibernateEntityName ); final EmbeddableDomainType<?> embeddableDomainType = creationContext.getSessionFactory()
if ( persister == null || !persister.isPolymorphic() ) { .getRuntimeMetamodels()
return; .getJpaMetamodel()
.embeddable( treatTargetTypeName );
if ( embeddableDomainType == null || !embeddableDomainType.isPolymorphic() ) {
return;
}
}
else {
persister = (AbstractEntityPersister) creationContext.getSessionFactory()
.getRuntimeMetamodels()
.getMappingMetamodel()
.findEntityDescriptor( treatTargetTypeName );
if ( persister == null || !persister.isPolymorphic() ) {
return;
}
} }
final TableGroup actualTableGroup; final TableGroup actualTableGroup;
final EntityNameUse finalEntityNameUse; final EntityNameUse finalEntityNameUse;
@ -3094,10 +3108,15 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
tg -> new HashMap<>( 1 ) tg -> new HashMap<>( 1 )
); );
entityNameUses.compute( entityNameUses.compute(
hibernateEntityName, treatTargetTypeName,
(s, existingUse) -> finalEntityNameUse.stronger( existingUse ) (s, existingUse) -> finalEntityNameUse.stronger( existingUse )
); );
if ( persister == null ) {
// No need to do anything else for embeddables
return;
}
// Resolve the table reference for all types which we register an entity name use for. // Resolve the table reference for all types which we register an entity name use for.
// Also, force table group initialization for treats when needed to ensure correct cardinality // Also, force table group initialization for treats when needed to ensure correct cardinality
final EntityNameUse.UseKind useKind = finalEntityNameUse.getKind(); final EntityNameUse.UseKind useKind = finalEntityNameUse.getKind();
@ -3156,7 +3175,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
return false; return false;
} }
protected void registerTypeUsage(EntityDiscriminatorSqmPath path) { protected void registerTypeUsage(DiscriminatorSqmPath<?> path) {
registerTypeUsage( getFromClauseAccess().getTableGroup( path.getNavigablePath().getParent() ) ); registerTypeUsage( getFromClauseAccess().getTableGroup( path.getNavigablePath().getParent() ) );
} }
@ -3172,20 +3191,23 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
// but for `a = 1 and type(..) = A or type(..) = B` we can infer `A, B` // but for `a = 1 and type(..) = A or type(..) = B` we can infer `A, B`
// The OR junction allows to create a union of entity name lists of all sub-predicates // The OR junction allows to create a union of entity name lists of all sub-predicates
// The AND junction allows to create an intersection of entity name lists of all sub-predicates // The AND junction allows to create an intersection of entity name lists of all sub-predicates
final EntityMappingType mappingType = (EntityMappingType) tableGroup.getModelPart().getPartMappingType(); final MappingType partMappingType = tableGroup.getModelPart().getPartMappingType();
final AbstractEntityPersister persister = (AbstractEntityPersister) mappingType.getEntityPersister(); if ( partMappingType instanceof EntityMappingType ) {
// Avoid resolving subclass tables for persisters with physical discriminators as we won't need them final EntityMappingType mappingType = (EntityMappingType) partMappingType;
if ( persister.getDiscriminatorMapping().hasPhysicalColumn() ) { final AbstractEntityPersister persister = (AbstractEntityPersister) mappingType.getEntityPersister();
return; // Avoid resolving subclass tables for persisters with physical discriminators as we won't need them
} if ( persister.getDiscriminatorMapping().hasPhysicalColumn() ) {
if ( getCurrentClauseStack().getCurrent() != Clause.WHERE && getCurrentClauseStack().getCurrent() != Clause.HAVING ) { return;
// Where and having clauses are handled specially with EntityNameUse.FILTER and pruning }
registerEntityNameUsage( tableGroup, EntityNameUse.PROJECTION, persister.getEntityName(), true ); if ( getCurrentClauseStack().getCurrent() != Clause.WHERE && getCurrentClauseStack().getCurrent() != Clause.HAVING ) {
} // Where and having clauses are handled specially with EntityNameUse.FILTER and pruning
else { registerEntityNameUsage( tableGroup, EntityNameUse.PROJECTION, persister.getEntityName(), true );
final int subclassTableSpan = persister.getSubclassTableSpan(); }
for ( int i = 0; i < subclassTableSpan; i++ ) { else {
tableGroup.resolveTableReference( null, persister.getSubclassTableName( i ) ); final int subclassTableSpan = persister.getSubclassTableSpan();
for ( int i = 0; i < subclassTableSpan; i++ ) {
tableGroup.resolveTableReference( null, persister.getSubclassTableName( i ) );
}
} }
} }
} }
@ -3196,16 +3218,19 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
if ( tableGroup.isInitialized() ) { if ( tableGroup.isInitialized() ) {
final Map<String, EntityNameUse> entityNameUses = entry.getValue(); final Map<String, EntityNameUse> entityNameUses = entry.getValue();
final ModelPartContainer modelPart = tableGroup.getModelPart(); final ModelPartContainer modelPart = tableGroup.getModelPart();
final EntityPersister tableGroupPersister; final MappingType partMappingType;
if ( modelPart instanceof PluralAttributeMapping ) { if ( modelPart instanceof PluralAttributeMapping ) {
tableGroupPersister = (EntityPersister) ( (PluralAttributeMapping) modelPart ) partMappingType = ( (PluralAttributeMapping) modelPart )
.getElementDescriptor() .getElementDescriptor()
.getPartMappingType(); .getPartMappingType();
} }
else { else {
tableGroupPersister = (EntityPersister) modelPart.getPartMappingType(); partMappingType = modelPart.getPartMappingType();
}
if ( partMappingType instanceof EntityPersister ) {
( (EntityPersister) partMappingType ).pruneForSubclasses( tableGroup, entityNameUses );
} }
tableGroupPersister.pruneForSubclasses( tableGroup, entityNameUses );
} }
} }
} }
@ -3235,7 +3260,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
for ( SqmFrom<?, ?> sqmTreat : sqmTreats ) { for ( SqmFrom<?, ?> sqmTreat : sqmTreats ) {
final TableGroup actualTableGroup = getActualTableGroup( lhsTableGroup, sqmTreat ); final TableGroup actualTableGroup = getActualTableGroup( lhsTableGroup, sqmTreat );
// We don't know the context yet in which a treat is used, so we have to register base treats and track the usage // We don't know the context yet in which a treat is used, so we have to register base treats and track the usage
registerEntityNameUsage( actualTableGroup, EntityNameUse.BASE_TREAT, ( (SqmTreatedPath<?, ?>) sqmTreat ).getTreatTarget().getHibernateEntityName() ); registerEntityNameUsage( actualTableGroup, EntityNameUse.BASE_TREAT, ( (SqmTreatedPath<?, ?>) sqmTreat ).getTreatTarget().getTypeName() );
consumeExplicitJoins( sqmTreat, actualTableGroup ); consumeExplicitJoins( sqmTreat, actualTableGroup );
} }
} }
@ -3408,12 +3433,15 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
// Since joins on treated paths will never cause table pruning, we need to add a join condition for the treat // Since joins on treated paths will never cause table pruning, we need to add a join condition for the treat
if ( sqmJoin.getLhs() instanceof SqmTreatedPath<?, ?> ) { if ( sqmJoin.getLhs() instanceof SqmTreatedPath<?, ?> ) {
final SqmTreatedPath<?, ?> treatedPath = (SqmTreatedPath<?, ?>) sqmJoin.getLhs(); final SqmTreatedPath<?, ?> treatedPath = (SqmTreatedPath<?, ?>) sqmJoin.getLhs();
joinForPredicate.applyPredicate( final ManagedDomainType<?> treatTarget = treatedPath.getTreatTarget();
createTreatTypeRestriction( if ( treatTarget.getPersistenceType() == ENTITY ) {
treatedPath.getWrappedPath(), joinForPredicate.applyPredicate(
treatedPath.getTreatTarget() createTreatTypeRestriction(
) treatedPath.getWrappedPath(),
); (EntityDomainType<?>) treatTarget
)
);
}
} }
if ( transitive ) { if ( transitive ) {
@ -3681,11 +3709,14 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
Consumer<TableGroup> implicitJoinChecker) { Consumer<TableGroup> implicitJoinChecker) {
final SqmPath<?> sqmPath = (SqmPath<?>) path; final SqmPath<?> sqmPath = (SqmPath<?>) path;
final SqmPath<?> parentPath; final SqmPath<?> parentPath;
final boolean treated;
if ( sqmPath instanceof SqmTreatedPath<?, ?> ) { if ( sqmPath instanceof SqmTreatedPath<?, ?> ) {
parentPath = ( (SqmTreatedPath<?, ?>) sqmPath ).getWrappedPath(); parentPath = ( (SqmTreatedPath<?, ?>) sqmPath ).getWrappedPath();
treated = true;
} }
else { else {
parentPath = sqmPath.getLhs(); parentPath = sqmPath.getLhs();
treated = false;
} }
if ( parentPath == null ) { if ( parentPath == null ) {
if ( sqmPath instanceof SqmFunctionPath<?> ) { if ( sqmPath instanceof SqmFunctionPath<?> ) {
@ -3730,10 +3761,13 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
if ( newTableGroup != null ) { if ( newTableGroup != null ) {
implicitJoinChecker.accept( newTableGroup ); implicitJoinChecker.accept( newTableGroup );
registerPathAttributeEntityNameUsage( sqmPath, newTableGroup ); registerPathAttributeEntityNameUsage( sqmPath, newTableGroup );
if ( treated ) {
fromClauseIndex.register( sqmPath, newTableGroup );
}
} }
return newTableGroup; return newTableGroup;
} }
else if ( sqmPath instanceof SqmTreatedPath<?, ?> ) { else if ( treated ) {
fromClauseIndex.register( sqmPath, parentTableGroup ); fromClauseIndex.register( sqmPath, parentTableGroup );
} }
@ -3827,8 +3861,8 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
final FromClauseIndex fromClauseIndex = getFromClauseIndex(); final FromClauseIndex fromClauseIndex = getFromClauseIndex();
final ModelPart subPart = parentTableGroup.getModelPart().findSubPart( final ModelPart subPart = parentTableGroup.getModelPart().findSubPart(
joinedPath.getReferencedPathSource().getPathName(), joinedPath.getReferencedPathSource().getPathName(),
lhsPath instanceof SqmTreatedPath lhsPath instanceof SqmTreatedPath<?, ?> && ( (SqmTreatedPath<?, ?>) lhsPath ).getTreatTarget().getPersistenceType() == ENTITY
? resolveEntityPersister( ( (SqmTreatedPath<?, ?>) lhsPath ).getTreatTarget() ) ? resolveEntityPersister( (EntityDomainType<?>) ( (SqmTreatedPath<?, ?>) lhsPath ).getTreatTarget() )
: null : null
); );
@ -4059,7 +4093,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
throw new InterpretationException( "SqmEntityJoin not yet resolved to TableGroup" ); throw new InterpretationException( "SqmEntityJoin not yet resolved to TableGroup" );
} }
private Expression visitTableGroup(TableGroup tableGroup, SqmFrom<?, ?> path) { private Expression visitTableGroup(TableGroup tableGroup, SqmPath<?> path) {
final ModelPartContainer tableGroupModelPart = tableGroup.getModelPart(); final ModelPartContainer tableGroupModelPart = tableGroup.getModelPart();
final ModelPart actualModelPart; final ModelPart actualModelPart;
@ -4213,11 +4247,12 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
} }
final EntityMappingType treatedMapping; final EntityMappingType treatedMapping;
if ( path instanceof SqmTreatedPath ) { if ( path instanceof SqmTreatedPath<?, ?> && ( (SqmTreatedPath<?, ?>) path ).getTreatTarget().getPersistenceType() == ENTITY ) {
final ManagedDomainType<?> treatTarget = ( (SqmTreatedPath<?, ?>) path ).getTreatTarget();
treatedMapping = creationContext.getSessionFactory() treatedMapping = creationContext.getSessionFactory()
.getRuntimeMetamodels() .getRuntimeMetamodels()
.getMappingMetamodel() .getMappingMetamodel()
.findEntityDescriptor( ( (SqmTreatedPath<?,?>) path ).getTreatTarget().getHibernateEntityName() ); .findEntityDescriptor( treatTarget.getTypeName() );
} }
else { else {
treatedMapping = interpretationModelPart.getEntityMappingType(); treatedMapping = interpretationModelPart.getEntityMappingType();
@ -4501,7 +4536,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
} }
@Override @Override
public Object visitDiscriminatorPath(EntityDiscriminatorSqmPath sqmPath) { public Object visitDiscriminatorPath(DiscriminatorSqmPath<?> sqmPath) {
return prepareReusablePath( return prepareReusablePath(
sqmPath, sqmPath,
() -> { () -> {
@ -4574,7 +4609,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
final TableGroup resolved = getFromClauseAccess().findTableGroup( sqmTreatedPath.getNavigablePath() ); final TableGroup resolved = getFromClauseAccess().findTableGroup( sqmTreatedPath.getNavigablePath() );
if ( resolved != null ) { if ( resolved != null ) {
log.tracef( "SqmTreatedPath [%s] resolved to existing TableGroup [%s]", sqmTreatedPath, resolved ); log.tracef( "SqmTreatedPath [%s] resolved to existing TableGroup [%s]", sqmTreatedPath, resolved );
return visitTableGroup( resolved, (SqmFrom<?, ?>) sqmTreatedPath ); return visitTableGroup( resolved, sqmTreatedPath );
} }
throw new InterpretationException( "SqmTreatedPath not yet resolved to TableGroup" ); throw new InterpretationException( "SqmTreatedPath not yet resolved to TableGroup" );
@ -5152,13 +5187,20 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
} }
if ( lhs instanceof SqmTreatedPath<?, ?> ) { if ( lhs instanceof SqmTreatedPath<?, ?> ) {
final SqmTreatedPath<?, ?> treatedPath = (SqmTreatedPath<?, ?>) lhs; final SqmTreatedPath<?, ?> treatedPath = (SqmTreatedPath<?, ?>) lhs;
final Class<?> treatTargetJavaType = treatedPath.getTreatTarget().getJavaType(); final ManagedDomainType<?> treatTarget = treatedPath.getTreatTarget();
final Class<?> treatTargetJavaType = treatTarget.getJavaType();
final SqmPath<?> wrappedPath = treatedPath.getWrappedPath(); final SqmPath<?> wrappedPath = treatedPath.getWrappedPath();
final Class<?> originalJavaType = wrappedPath.getJavaType(); final Class<?> originalJavaType = wrappedPath.getJavaType();
if ( treatTargetJavaType.isAssignableFrom( originalJavaType ) ) { if ( treatTargetJavaType.isAssignableFrom( originalJavaType ) ) {
// Treating a node to a super type can be ignored // Treating a node to a super type can be ignored
return expression; return expression;
} }
if ( treatTarget instanceof EmbeddableDomainType<?> ) {
// For embedded treats we simply register a TREAT use
final TableGroup tableGroup = getFromClauseIndex().findTableGroup( wrappedPath.getNavigablePath() );
registerEntityNameUsage( tableGroup, EntityNameUse.TREAT, treatTarget.getTypeName(), false );
return expression;
}
if ( !( expression.getExpressionType() instanceof BasicValuedMapping ) ) { if ( !( expression.getExpressionType() instanceof BasicValuedMapping ) ) {
// A case wrapper for non-basic paths is not possible, // A case wrapper for non-basic paths is not possible,
// because a case expression must return a scalar value. // because a case expression must return a scalar value.
@ -5167,9 +5209,8 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
// by registering the treat into tableGroupEntityNameUses. // by registering the treat into tableGroupEntityNameUses.
// Joins don't need the restriction as it will be embedded into // Joins don't need the restriction as it will be embedded into
// the joined table group itself by #pruneTableGroupJoins // the joined table group itself by #pruneTableGroupJoins
final String treatedName = treatedPath.getTreatTarget().getHibernateEntityName();
final TableGroup tableGroup = getFromClauseIndex().findTableGroup( wrappedPath.getNavigablePath() ); final TableGroup tableGroup = getFromClauseIndex().findTableGroup( wrappedPath.getNavigablePath() );
registerEntityNameUsage( tableGroup, EntityNameUse.TREAT, treatedName ); registerEntityNameUsage( tableGroup, EntityNameUse.TREAT, treatTarget.getTypeName(), false );
} }
return expression; return expression;
} }
@ -5182,7 +5223,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
// Only need a case expression around the basic valued path for the parent treat expression // Only need a case expression around the basic valued path for the parent treat expression
// if the column of the basic valued path is shared between subclasses // if the column of the basic valued path is shared between subclasses
if ( persister.isSharedColumn( basicPath.getColumnReference().getColumnExpression() ) ) { if ( persister.isSharedColumn( basicPath.getColumnReference().getColumnExpression() ) ) {
return createCaseExpression( wrappedPath, treatedPath.getTreatTarget(), expression ); return createCaseExpression( wrappedPath, (EntityDomainType<?>) treatTarget, expression );
} }
} }
return expression; return expression;
@ -5219,40 +5260,67 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
Predicate predicate = null; Predicate predicate = null;
for ( Map.Entry<TableGroup, Map<String, EntityNameUse>> entry : conjunctTreatUsages.entrySet() ) { for ( Map.Entry<TableGroup, Map<String, EntityNameUse>> entry : conjunctTreatUsages.entrySet() ) {
final TableGroup tableGroup = entry.getKey(); final TableGroup tableGroup = entry.getKey();
final Set<String> entityNames = determineEntityNamesForTreatTypeRestriction(
(EntityMappingType) tableGroup.getModelPart().getPartMappingType(),
entry.getValue()
);
if ( entityNames.isEmpty() ) {
continue;
}
final ModelPartContainer modelPart = tableGroup.getModelPart(); final ModelPartContainer modelPart = tableGroup.getModelPart();
final Set<String> typeNames;
final EntityMappingType entityMapping; final EntityMappingType entityMapping;
if ( modelPart instanceof EntityValuedModelPart ) { final EmbeddableMappingType embeddableMapping;
if ( modelPart instanceof PluralAttributeMapping ) {
entityMapping = (EntityMappingType) ( (PluralAttributeMapping) modelPart ).getElementDescriptor()
.getPartMappingType();
embeddableMapping = null;
}
else if ( modelPart instanceof EntityValuedModelPart ) {
entityMapping = ( (EntityValuedModelPart) modelPart ).getEntityMappingType(); entityMapping = ( (EntityValuedModelPart) modelPart ).getEntityMappingType();
embeddableMapping = null;
}
else if ( modelPart instanceof EmbeddableValuedModelPart ) {
embeddableMapping = ( (EmbeddableValuedModelPart) modelPart ).getEmbeddableTypeDescriptor();
entityMapping = null;
} }
else { else {
entityMapping = (EntityMappingType) ( (PluralAttributeMapping) modelPart ).getElementDescriptor().getPartMappingType(); throw new IllegalStateException( "Unrecognized model part for treated table group: " + tableGroup );
}
final DiscriminatorPathInterpretation<?> typeExpression;
if ( entityMapping != null ) {
typeNames = determineEntityNamesForTreatTypeRestriction( entityMapping, entry.getValue() );
if ( typeNames.isEmpty() ) {
continue;
}
typeExpression = new DiscriminatorPathInterpretation<>(
tableGroup.getNavigablePath().append( EntityDiscriminatorMapping.DISCRIMINATOR_ROLE_NAME ),
entityMapping,
tableGroup,
this
);
registerTypeUsage( tableGroup );
}
else {
assert embeddableMapping != null;
typeNames = determineEmbeddableNamesForTreatTypeRestriction( embeddableMapping, entry.getValue() );
if ( typeNames.isEmpty() ) {
continue;
}
typeExpression = new DiscriminatorPathInterpretation<>(
tableGroup.getNavigablePath().append( EntityDiscriminatorMapping.DISCRIMINATOR_ROLE_NAME ),
embeddableMapping.getDiscriminatorMapping(),
tableGroup,
this
);
} }
final DiscriminatorPathInterpretation<?> typeExpression = new DiscriminatorPathInterpretation<>(
tableGroup.getNavigablePath().append( EntityDiscriminatorMapping.DISCRIMINATOR_ROLE_NAME ),
entityMapping,
tableGroup,
this
);
// We need to check if this is a treated left or full join, which case we should // We need to check if this is a treated left or full join, which case we should
// allow null discriminator values to maintain correct semantics // allow null discriminator values to maintain correct semantics
final TableGroupJoin join = getParentTableGroupJoin( tableGroup ); final TableGroupJoin join = getParentTableGroupJoin( tableGroup );
final boolean allowNulls = join != null && ( join.getJoinType() == SqlAstJoinType.LEFT || join.getJoinType() == SqlAstJoinType.FULL ); final boolean allowNulls = join != null && ( join.getJoinType() == SqlAstJoinType.LEFT || join.getJoinType() == SqlAstJoinType.FULL );
registerTypeUsage( tableGroup );
predicate = combinePredicates( predicate = combinePredicates(
predicate, predicate,
createTreatTypeRestriction( createTreatTypeRestriction(
typeExpression, typeExpression,
entityNames, typeNames,
allowNulls allowNulls,
entityMapping != null
) )
); );
} }
@ -5334,6 +5402,22 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
return entityNames; return entityNames;
} }
private Set<String> determineEmbeddableNamesForTreatTypeRestriction(
EmbeddableMappingType embeddableMappingType,
Map<String, EntityNameUse> entityNameUses) {
final EmbeddableDomainType<?> embeddableDomainType = creationContext.getSessionFactory()
.getRuntimeMetamodels()
.getJpaMetamodel()
.embeddable( embeddableMappingType.getJavaType().getJavaTypeClass() );
final Set<String> entityNameUsesSet = new HashSet<>( entityNameUses.keySet() );
ManagedDomainType<?> superType = embeddableDomainType;
while ( superType != null ) {
entityNameUsesSet.remove( superType.getTypeName() );
superType = superType.getSuperType();
}
return entityNameUsesSet;
}
private Predicate createTreatTypeRestriction(SqmPath<?> lhs, EntityDomainType<?> treatTarget) { private Predicate createTreatTypeRestriction(SqmPath<?> lhs, EntityDomainType<?> treatTarget) {
final AbstractEntityPersister entityDescriptor = (AbstractEntityPersister) domainModel.findEntityDescriptor( treatTarget.getHibernateEntityName() ); final AbstractEntityPersister entityDescriptor = (AbstractEntityPersister) domainModel.findEntityDescriptor( treatTarget.getHibernateEntityName() );
if ( entityDescriptor.isPolymorphic() && lhs.getNodeType() != treatTarget ) { if ( entityDescriptor.isPolymorphic() && lhs.getNodeType() != treatTarget ) {
@ -5351,26 +5435,28 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
return createTreatTypeRestriction( return createTreatTypeRestriction(
DiscriminatorPathInterpretation.from( discriminatorSqmPath, this ), DiscriminatorPathInterpretation.from( discriminatorSqmPath, this ),
subclassEntityNames, subclassEntityNames,
false false,
true
); );
} }
private Predicate createTreatTypeRestriction( private Predicate createTreatTypeRestriction(
Expression typeExpression, SqmPathInterpretation<?> typeExpression,
Set<String> subclassEntityNames, Set<String> subtypeNames,
boolean allowNulls) { boolean allowNulls,
boolean entity) {
final Predicate discriminatorPredicate; final Predicate discriminatorPredicate;
if ( subclassEntityNames.size() == 1 ) { if ( subtypeNames.size() == 1 ) {
discriminatorPredicate = new ComparisonPredicate( discriminatorPredicate = new ComparisonPredicate(
typeExpression, typeExpression,
ComparisonOperator.EQUAL, ComparisonOperator.EQUAL,
new EntityTypeLiteral( domainModel.findEntityDescriptor( subclassEntityNames.iterator().next() ) ) getTypeLiteral( typeExpression, subtypeNames.iterator().next(), entity )
); );
} }
else { else {
final List<Expression> typeLiterals = new ArrayList<>( subclassEntityNames.size() ); final List<Expression> typeLiterals = new ArrayList<>( subtypeNames.size() );
for ( String subclassEntityName : subclassEntityNames ) { for ( String subtypeName : subtypeNames ) {
typeLiterals.add( new EntityTypeLiteral( domainModel.findEntityDescriptor( subclassEntityName ) ) ); typeLiterals.add( getTypeLiteral( typeExpression, subtypeName, entity ) );
} }
discriminatorPredicate = new InListPredicate( typeExpression, typeLiterals ); discriminatorPredicate = new InListPredicate( typeExpression, typeLiterals );
} }
@ -5384,6 +5470,22 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
return discriminatorPredicate; return discriminatorPredicate;
} }
private Expression getTypeLiteral(SqmPathInterpretation<?> typeExpression, String typeName, boolean entity) {
if ( entity ) {
return new EntityTypeLiteral( domainModel.findEntityDescriptor( typeName ) );
}
else {
final EmbeddableDomainType<?> embeddable = creationContext.getSessionFactory()
.getRuntimeMetamodels()
.getJpaMetamodel()
.embeddable( typeName );
return new EmbeddableTypeLiteral(
embeddable,
(BasicType<?>) typeExpression.getExpressionType().getSingleJdbcMapping()
);
}
}
private MappingModelExpressible<?> resolveInferredType() { private MappingModelExpressible<?> resolveInferredType() {
final Supplier<MappingModelExpressible<?>> inferableTypeAccess = inferrableTypeAccessStack.getCurrent(); final Supplier<MappingModelExpressible<?>> inferableTypeAccess = inferrableTypeAccessStack.getCurrent();
if ( inTypeInference || inferableTypeAccess == null ) { if ( inTypeInference || inferableTypeAccess == null ) {
@ -7130,6 +7232,16 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
return new EntityTypeLiteral( mappingDescriptor ); return new EntityTypeLiteral( mappingDescriptor );
} }
@Override
public Object visitEmbeddableTypeLiteralExpression(SqmLiteralEmbeddableType<?> expression) {
final MappingModelExpressible<?> inferredValueMapping = getInferredValueMapping();
// The inferred value mapping for literal embeddable types will either be the
// discriminator mapping for polymorphic embeddables or the Class<?> basic type
final BasicType<?> basicType = inferredValueMapping != null ?
(BasicType<?>) inferredValueMapping.getSingleJdbcMapping() :
expression.getNodeType();
return new EmbeddableTypeLiteral( expression.getExpressible(), basicType );
}
@Override @Override
public Expression visitAnyDiscriminatorTypeValueExpression(SqmAnyDiscriminatorValue<?> expression) { public Expression visitAnyDiscriminatorTypeValueExpression(SqmAnyDiscriminatorValue<?> expression) {
@ -7278,7 +7390,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
disjunctEntityNameUsesArray = new Map[predicate.getPredicates().size()]; disjunctEntityNameUsesArray = new Map[predicate.getPredicates().size()];
entityNameUsesToPropagate = previousTableGroupEntityNameUses == null entityNameUsesToPropagate = previousTableGroupEntityNameUses == null
? new IdentityHashMap<>() ? new IdentityHashMap<>()
: previousTableGroupEntityNameUses; : new IdentityHashMap<>( previousTableGroupEntityNameUses );
} }
if ( i == 0 ) { if ( i == 0 ) {
// Collect the table groups for which filters are registered // Collect the table groups for which filters are registered
@ -7420,48 +7532,56 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
return disjunction; return disjunction;
} }
// Build the intersection of the conjunct treat usages, if ( !tableGroupEntityNameUses.isEmpty() ) {
// so that we can push that up and infer during pruning, which entity subclasses can be omitted // Build the intersection of the conjunct treat usages,
final Iterator<Map.Entry<TableGroup, Map<String, EntityNameUse>>> iterator = tableGroupEntityNameUses.entrySet().iterator(); // so that we can push that up and infer during pruning, which entity subclasses can be omitted
while ( iterator.hasNext() ) { final Iterator<Map.Entry<TableGroup, Map<String, EntityNameUse>>> iterator = tableGroupEntityNameUses.entrySet().iterator();
final Map.Entry<TableGroup, Map<String, EntityNameUse>> entry = iterator.next(); while ( iterator.hasNext() ) {
final Map<String, EntityNameUse> intersected = new HashMap<>( entry.getValue() ); final Map.Entry<TableGroup, Map<String, EntityNameUse>> entry = iterator.next();
entry.setValue( intersected ); final Map<String, EntityNameUse> intersected = new HashMap<>( entry.getValue() );
boolean remove = false; entry.setValue( intersected );
for ( Map<TableGroup, Map<String, EntityNameUse>> conjunctTreatUsages : disjunctEntityNameUsesArray ) { boolean remove = false;
final Map<String, EntityNameUse> entityNames; for ( Map<TableGroup, Map<String, EntityNameUse>> conjunctTreatUsages : disjunctEntityNameUsesArray ) {
if ( conjunctTreatUsages == null || ( entityNames = conjunctTreatUsages.get( entry.getKey() ) ) == null ) { final Map<String, EntityNameUse> entityNames;
remove = true; if ( conjunctTreatUsages == null || ( entityNames = conjunctTreatUsages.get( entry.getKey() ) ) == null ) {
continue; remove = true;
} break;
// Intersect the two sets and transfer the common elements to the intersection
final Iterator<Map.Entry<String, EntityNameUse>> intersectedIter = intersected.entrySet().iterator();
while ( intersectedIter.hasNext() ) {
final Map.Entry<String, EntityNameUse> intersectedEntry = intersectedIter.next();
final EntityNameUse intersectedUseKind = intersectedEntry.getValue();
final EntityNameUse useKind = entityNames.get( intersectedEntry.getKey() );
if ( useKind == null ) {
intersectedIter.remove();
} }
else { // Intersect the two sets and transfer the common elements to the intersection
// Possibly downgrade a FILTER use to EXPRESSION if one of the disjunctions does not use FILTER final Iterator<Map.Entry<String, EntityNameUse>> intersectedIter = intersected.entrySet()
intersectedEntry.setValue( intersectedUseKind.weaker( useKind ) ); .iterator();
while ( intersectedIter.hasNext() ) {
final Map.Entry<String, EntityNameUse> intersectedEntry = intersectedIter.next();
final EntityNameUse intersectedUseKind = intersectedEntry.getValue();
final EntityNameUse useKind = entityNames.get( intersectedEntry.getKey() );
if ( useKind == null ) {
intersectedIter.remove();
}
else {
// Possibly downgrade a FILTER use to EXPRESSION if one of the disjunctions does not use FILTER
intersectedEntry.setValue( intersectedUseKind.weaker( useKind ) );
}
}
if ( intersected.isEmpty() ) {
remove = true;
break;
}
entityNames.keySet().removeAll( intersected.keySet() );
if ( entityNames.isEmpty() ) {
conjunctTreatUsages.remove( entry.getKey() );
} }
} }
if ( intersected.isEmpty() ) {
remove = true;
continue;
}
entityNames.keySet().removeAll( intersected.keySet() );
if ( entityNames.isEmpty() ) {
conjunctTreatUsages.remove( entry.getKey() );
}
}
if ( remove ) { if ( remove ) {
iterator.remove(); entityNameUsesToPropagate.remove( entry.getKey() );
iterator.remove();
}
} }
} }
else {
// If there's no baseline to construct the intersection from don't propagate
entityNameUsesToPropagate.clear();
}
// Prepend the treat type usages to the respective conjuncts // Prepend the treat type usages to the respective conjuncts
for ( int i = 0; i < disjunctEntityNameUsesArray.length; i++ ) { for ( int i = 0; i < disjunctEntityNameUsesArray.length; i++ ) {
@ -7476,6 +7596,12 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
); );
} }
} }
// Restore the parent context entity name uses state
tableGroupEntityNameUses.clear();
if ( previousTableGroupEntityNameUses != null ) {
tableGroupEntityNameUses.putAll( previousTableGroupEntityNameUses );
}
// Propagate the union of the entity name uses upwards // Propagate the union of the entity name uses upwards
for ( Map.Entry<TableGroup, Map<String, EntityNameUse>> entry : entityNameUsesToPropagate.entrySet() ) { for ( Map.Entry<TableGroup, Map<String, EntityNameUse>> entry : entityNameUsesToPropagate.entrySet() ) {
final Map<String, EntityNameUse> entityNameUses = tableGroupEntityNameUses.putIfAbsent( final Map<String, EntityNameUse> entityNameUses = tableGroupEntityNameUses.putIfAbsent(
@ -7638,7 +7764,11 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
List<EntityTypeLiteral> literalExpressions, List<EntityTypeLiteral> literalExpressions,
boolean inclusive) { boolean inclusive) {
final TableGroup tableGroup = getFromClauseIndex().getTableGroup( typeExpression.getNavigablePath().getParent() ); final TableGroup tableGroup = getFromClauseIndex().getTableGroup( typeExpression.getNavigablePath().getParent() );
final EntityMappingType entityMappingType = (EntityMappingType) tableGroup.getModelPart().getPartMappingType(); final MappingType partMappingType = tableGroup.getModelPart().getPartMappingType();
if ( !( partMappingType instanceof EntityMappingType ) ) {
return;
}
final EntityMappingType entityMappingType = (EntityMappingType) partMappingType;
if ( entityMappingType.getDiscriminatorMapping().hasPhysicalColumn() ) { if ( entityMappingType.getDiscriminatorMapping().hasPhysicalColumn() ) {
// If the entity has a physical discriminator column we don't need to register any FILTER usages. // If the entity has a physical discriminator column we don't need to register any FILTER usages.
// Register only an EXPRESSION usage to prevent pruning of the root type's table reference which // Register only an EXPRESSION usage to prevent pruning of the root type's table reference which

View File

@ -33,6 +33,7 @@ import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.ast.tree.from.TableReference; import org.hibernate.sql.ast.tree.from.TableReference;
import org.hibernate.sql.ast.tree.update.Assignable; import org.hibernate.sql.ast.tree.update.Assignable;
import static jakarta.persistence.metamodel.Type.PersistenceType.ENTITY;
import static org.hibernate.internal.util.NullnessUtil.castNonNull; import static org.hibernate.internal.util.NullnessUtil.castNonNull;
import static org.hibernate.query.sqm.internal.SqmUtil.getTargetMappingIfNeeded; import static org.hibernate.query.sqm.internal.SqmUtil.getTargetMappingIfNeeded;
@ -51,8 +52,8 @@ public class BasicValuedPathInterpretation<T> extends AbstractSqmPathInterpretat
final TableGroup tableGroup = sqlAstCreationState.getFromClauseAccess().getTableGroup( lhs.getNavigablePath() ); final TableGroup tableGroup = sqlAstCreationState.getFromClauseAccess().getTableGroup( lhs.getNavigablePath() );
EntityMappingType treatTarget = null; EntityMappingType treatTarget = null;
final ModelPartContainer modelPartContainer; final ModelPartContainer modelPartContainer;
if ( lhs instanceof SqmTreatedPath<?, ?> ) { if ( lhs instanceof SqmTreatedPath<?, ?> && ( (SqmTreatedPath<?, ?>) lhs ).getTreatTarget().getPersistenceType() == ENTITY ) {
final EntityDomainType<?> treatTargetDomainType = ( (SqmTreatedPath<?, ?>) lhs ).getTreatTarget(); final EntityDomainType<?> treatTargetDomainType = (EntityDomainType<?>) ( (SqmTreatedPath<?, ?>) lhs ).getTreatTarget();
final MappingMetamodel mappingMetamodel = sqlAstCreationState.getCreationContext() final MappingMetamodel mappingMetamodel = sqlAstCreationState.getCreationContext()
.getSessionFactory() .getSessionFactory()

View File

@ -13,6 +13,8 @@ import org.hibernate.metamodel.mapping.EntityValuedModelPart;
import org.hibernate.metamodel.mapping.JdbcMapping; import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.mapping.ModelPartContainer; import org.hibernate.metamodel.mapping.ModelPartContainer;
import org.hibernate.metamodel.mapping.PluralAttributeMapping; import org.hibernate.metamodel.mapping.PluralAttributeMapping;
import org.hibernate.metamodel.model.domain.DiscriminatorSqmPath;
import org.hibernate.metamodel.model.domain.internal.EmbeddedDiscriminatorSqmPath;
import org.hibernate.metamodel.model.domain.internal.EntityDiscriminatorSqmPath; import org.hibernate.metamodel.model.domain.internal.EntityDiscriminatorSqmPath;
import org.hibernate.query.results.ResultSetMappingSqlSelection; import org.hibernate.query.results.ResultSetMappingSqlSelection;
import org.hibernate.query.sqm.sql.SqmToSqlAstConverter; import org.hibernate.query.sqm.sql.SqmToSqlAstConverter;
@ -27,6 +29,8 @@ import org.hibernate.sql.results.graph.DomainResultCreationState;
import org.hibernate.type.descriptor.java.JavaType; import org.hibernate.type.descriptor.java.JavaType;
import org.hibernate.type.spi.TypeConfiguration; import org.hibernate.type.spi.TypeConfiguration;
import static org.hibernate.query.sqm.internal.SqmMappingModelHelper.resolveMappingModelExpressible;
/** /**
* SqmPathInterpretation and DomainResultProducer implementation for entity discriminator * SqmPathInterpretation and DomainResultProducer implementation for entity discriminator
* *
@ -58,22 +62,38 @@ public class DiscriminatorPathInterpretation<T> extends AbstractSqmPathInterpret
} }
public static SqmPathInterpretation<?> from( public static SqmPathInterpretation<?> from(
EntityDiscriminatorSqmPath path, DiscriminatorSqmPath<?> path,
SqmToSqlAstConverter converter) { SqmToSqlAstConverter converter) {
assert path.getEntityDescriptor().hasSubclasses();
final NavigablePath navigablePath = path.getNavigablePath(); final NavigablePath navigablePath = path.getNavigablePath();
final TableGroup tableGroup = converter.getFromClauseAccess().getTableGroup( navigablePath.getParent() ); final TableGroup tableGroup = converter.getFromClauseAccess().getTableGroup( navigablePath.getParent() );
final ModelPartContainer modelPart = tableGroup.getModelPart(); final ModelPartContainer modelPart = tableGroup.getModelPart();
final EntityMappingType entityMapping;
if ( modelPart instanceof EntityValuedModelPart ) { if ( path instanceof EntityDiscriminatorSqmPath<?> ) {
entityMapping = ( (EntityValuedModelPart) modelPart ).getEntityMappingType(); assert ((EntityDiscriminatorSqmPath<?>) path).getEntityDescriptor().hasSubclasses();
final EntityMappingType entityMapping;
if ( modelPart instanceof EntityValuedModelPart ) {
entityMapping = ( (EntityValuedModelPart) modelPart ).getEntityMappingType();
}
else {
entityMapping = (EntityMappingType) ( (PluralAttributeMapping) modelPart ).getElementDescriptor().getPartMappingType();
}
return new DiscriminatorPathInterpretation<>( navigablePath, entityMapping, tableGroup, converter );
} }
else { else {
entityMapping = (EntityMappingType) ( (PluralAttributeMapping) modelPart ).getElementDescriptor().getPartMappingType(); final EmbeddedDiscriminatorSqmPath<?> embeddableDiscriminator = (EmbeddedDiscriminatorSqmPath<?>) path;
final DiscriminatorMapping discriminator = (DiscriminatorMapping) resolveMappingModelExpressible(
embeddableDiscriminator,
converter.getCreationContext().getMappingMetamodel(),
converter.getFromClauseAccess()::findTableGroup
);
return new DiscriminatorPathInterpretation<>(
navigablePath,
discriminator,
tableGroup,
converter
);
} }
return new DiscriminatorPathInterpretation<>( navigablePath, entityMapping, tableGroup, converter );
} }
public EntityDiscriminatorMapping getDiscriminatorMapping() { public EntityDiscriminatorMapping getDiscriminatorMapping() {

View File

@ -28,6 +28,7 @@ import org.hibernate.sql.ast.tree.expression.SqlTupleContainer;
import org.hibernate.sql.ast.tree.from.TableGroup; import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.ast.tree.update.Assignable; import org.hibernate.sql.ast.tree.update.Assignable;
import static jakarta.persistence.metamodel.Type.PersistenceType.ENTITY;
import static org.hibernate.query.sqm.internal.SqmUtil.getTargetMappingIfNeeded; import static org.hibernate.query.sqm.internal.SqmUtil.getTargetMappingIfNeeded;
/** /**
@ -50,16 +51,14 @@ public class EmbeddableValuedPathInterpretation<T> extends AbstractSqmPathInterp
.getSessionFactory() .getSessionFactory()
.getRuntimeMetamodels() .getRuntimeMetamodels()
.getMappingMetamodel(); .getMappingMetamodel();
if ( lhs instanceof SqmTreatedPath ) { if ( lhs instanceof SqmTreatedPath<?, ?> && ( (SqmTreatedPath<?, ?>) lhs ).getTreatTarget().getPersistenceType() == ENTITY ) {
//noinspection rawtypes final EntityDomainType<?> treatTargetDomainType = (EntityDomainType<?>) ( (SqmTreatedPath<?, ?>) lhs ).getTreatTarget();
final EntityDomainType<?> treatTargetDomainType = ( (SqmTreatedPath) lhs ).getTreatTarget();
treatTarget = mappingMetamodel.findEntityDescriptor( treatTargetDomainType.getHibernateEntityName() ); treatTarget = mappingMetamodel.findEntityDescriptor( treatTargetDomainType.getHibernateEntityName() );
} }
else if ( lhs.getNodeType() instanceof EntityDomainType ) { else if ( lhs.getNodeType() instanceof EntityDomainType ) {
//noinspection rawtypes //noinspection rawtypes
final EntityDomainType<?> entityDomainType = (EntityDomainType) lhs.getNodeType(); final EntityDomainType<?> entityDomainType = (EntityDomainType) lhs.getNodeType();
treatTarget = mappingMetamodel.findEntityDescriptor( entityDomainType.getHibernateEntityName() ); treatTarget = mappingMetamodel.findEntityDescriptor( entityDomainType.getHibernateEntityName() );
} }
} }

View File

@ -286,22 +286,16 @@ public abstract class AbstractSqmFrom<O,T> extends AbstractSqmPath<T> implements
} }
} }
@Override
public boolean hasTreats() {
return treats != null && !treats.isEmpty();
}
@Override @Override
public List<SqmFrom<?, ?>> getSqmTreats() { public List<SqmFrom<?, ?>> getSqmTreats() {
return treats == null ? Collections.emptyList() : treats; return treats == null ? Collections.emptyList() : treats;
} }
protected <S, X extends SqmFrom<?, S>> X findTreat(EntityDomainType<S> targetType, String alias) { protected <S, X extends SqmFrom<?, S>> X findTreat(ManagedDomainType<S> targetType, String alias) {
if ( treats != null ) { if ( treats != null ) {
for ( SqmFrom<?, ?> treat : treats ) { for ( SqmFrom<?, ?> treat : treats ) {
if ( treat.getModel() == targetType ) { if ( treat.getModel() == targetType ) {
if ( treat.getExplicitAlias() == null && alias == null if ( Objects.equals( treat.getExplicitAlias(), alias ) ) {
|| Objects.equals( treat.getExplicitAlias(), alias ) ) {
//noinspection unchecked //noinspection unchecked
return (X) treat; return (X) treat;
} }

View File

@ -17,6 +17,7 @@ import org.hibernate.internal.util.NullnessUtil;
import org.hibernate.metamodel.mapping.CollectionPart; import org.hibernate.metamodel.mapping.CollectionPart;
import org.hibernate.metamodel.mapping.EntityDiscriminatorMapping; import org.hibernate.metamodel.mapping.EntityDiscriminatorMapping;
import org.hibernate.metamodel.model.domain.DomainType; import org.hibernate.metamodel.model.domain.DomainType;
import org.hibernate.metamodel.model.domain.EmbeddableDomainType;
import org.hibernate.metamodel.model.domain.EntityDomainType; import org.hibernate.metamodel.model.domain.EntityDomainType;
import org.hibernate.metamodel.model.domain.ManagedDomainType; import org.hibernate.metamodel.model.domain.ManagedDomainType;
import org.hibernate.metamodel.model.domain.PersistentAttribute; import org.hibernate.metamodel.model.domain.PersistentAttribute;
@ -219,12 +220,17 @@ public abstract class AbstractSqmPath<T> extends AbstractSqmExpression<T> implem
} }
} }
protected <S extends T> SqmTreatedPath<T, S> getTreatedPath(EntityDomainType<S> treatTarget) { protected <S extends T> SqmTreatedPath<T, S> getTreatedPath(ManagedDomainType<S> treatTarget) {
final NavigablePath treat = getNavigablePath().treatAs( treatTarget.getHibernateEntityName() ); final NavigablePath treat = getNavigablePath().treatAs( treatTarget.getTypeName() );
//noinspection unchecked //noinspection unchecked
SqmTreatedPath<T, S> path = (SqmTreatedPath<T, S>) getLhs().getReusablePath( treat.getLocalName() ); SqmTreatedPath<T, S> path = (SqmTreatedPath<T, S>) getLhs().getReusablePath( treat.getLocalName() );
if ( path == null ) { if ( path == null ) {
path = new SqmTreatedSimplePath<>( this, treatTarget, nodeBuilder() ); if ( treatTarget instanceof EntityDomainType<?> ) {
path = new SqmTreatedEntityValuedSimplePath<>( this, (EntityDomainType<S>) treatTarget, nodeBuilder() );
}
else {
path = new SqmTreatedEmbeddedValuedSimplePath<>( this, (EmbeddableDomainType<S>) treatTarget );
}
getLhs().registerReusablePath( path ); getLhs().registerReusablePath( path );
} }
return path; return path;

View File

@ -10,6 +10,8 @@ import java.util.Collection;
import org.hibernate.metamodel.model.domain.BagPersistentAttribute; import org.hibernate.metamodel.model.domain.BagPersistentAttribute;
import org.hibernate.metamodel.model.domain.EntityDomainType; import org.hibernate.metamodel.model.domain.EntityDomainType;
import org.hibernate.metamodel.model.domain.ManagedDomainType;
import org.hibernate.metamodel.model.domain.TreatableDomainType;
import org.hibernate.query.sqm.SemanticQueryWalker; import org.hibernate.query.sqm.SemanticQueryWalker;
import org.hibernate.spi.NavigablePath; import org.hibernate.spi.NavigablePath;
import org.hibernate.query.criteria.JpaCollectionJoin; import org.hibernate.query.criteria.JpaCollectionJoin;
@ -116,8 +118,8 @@ public class SqmBagJoin<O, E> extends AbstractSqmPluralJoin<O,Collection<E>, E>
} }
@Override @Override
public <S extends E> SqmTreatedBagJoin<O, E, S> treatAs(Class<S> treatAsType) { public <S extends E> SqmTreatedBagJoin<O, E, S> treatAs(Class<S> treatJavaType) {
return treatAs( nodeBuilder().getDomainModel().entity( treatAsType ) ); return treatAs( treatJavaType, null );
} }
@Override @Override
@ -127,7 +129,7 @@ public class SqmBagJoin<O, E> extends AbstractSqmPluralJoin<O,Collection<E>, E>
@Override @Override
public <S extends E> SqmTreatedBagJoin<O,E,S> treatAs(Class<S> treatJavaType, String alias) { public <S extends E> SqmTreatedBagJoin<O,E,S> treatAs(Class<S> treatJavaType, String alias) {
return treatAs( nodeBuilder().getDomainModel().entity( treatJavaType ), alias ); return treatAs( treatJavaType, alias, false );
} }
@Override @Override
@ -136,8 +138,18 @@ public class SqmBagJoin<O, E> extends AbstractSqmPluralJoin<O,Collection<E>, E>
} }
@Override @Override
public <S extends E> SqmTreatedBagJoin<O,E,S> treatAs(Class<S> treatJavaType, String alias, boolean fetch) { public <S extends E> SqmTreatedBagJoin<O, E, S> treatAs(Class<S> treatJavaType, String alias, boolean fetch) {
return treatAs( nodeBuilder().getDomainModel().entity( treatJavaType ), alias, fetch ); final ManagedDomainType<S> treatTarget = nodeBuilder().getDomainModel().managedType( treatJavaType );
final SqmTreatedBagJoin<O, E, S> treat = findTreat( treatTarget, alias );
if ( treat == null ) {
if ( treatTarget instanceof TreatableDomainType<?> ) {
return addTreat( new SqmTreatedBagJoin<>( this, (TreatableDomainType<S>) treatTarget, alias, fetch ) );
}
else {
throw new IllegalArgumentException( "Not a treatable type: " + treatJavaType.getName() );
}
}
return treat;
} }
@Override @Override

View File

@ -99,12 +99,12 @@ public class SqmEmbeddedValuedSimplePath<T>
@Override @Override
public <S extends T> SqmTreatedPath<T, S> treatAs(Class<S> treatJavaType) throws PathException { public <S extends T> SqmTreatedPath<T, S> treatAs(Class<S> treatJavaType) throws PathException {
throw new FunctionArgumentException( "Embeddable paths cannot be TREAT-ed" ); return getTreatedPath( nodeBuilder().getDomainModel().embeddable( treatJavaType ) );
} }
@Override @Override
public <S extends T> SqmTreatedPath<T, S> treatAs(EntityDomainType<S> treatTarget) throws PathException { public <S extends T> SqmTreatedPath<T, S> treatAs(EntityDomainType<S> treatTarget) throws PathException {
throw new FunctionArgumentException( "Embeddable paths cannot be TREAT-ed" ); throw new FunctionArgumentException( "Embeddable paths cannot be TREAT-ed to an entity type" );
} }
@Override @Override

View File

@ -78,8 +78,8 @@ public class SqmEntityValuedSimplePath<T> extends AbstractSqmSimplePath<T> {
// } // }
@Override @Override
public <S extends T> SqmTreatedSimplePath<T,S> treatAs(Class<S> treatJavaType) throws PathException { public <S extends T> SqmTreatedEntityValuedSimplePath<T,S> treatAs(Class<S> treatJavaType) throws PathException {
return (SqmTreatedSimplePath<T, S>) treatAs( nodeBuilder().getDomainModel().entity( treatJavaType ) ); return (SqmTreatedEntityValuedSimplePath<T, S>) treatAs( nodeBuilder().getDomainModel().entity( treatJavaType ) );
} }
@Override @Override

View File

@ -10,6 +10,8 @@ import java.util.List;
import org.hibernate.metamodel.model.domain.EntityDomainType; import org.hibernate.metamodel.model.domain.EntityDomainType;
import org.hibernate.metamodel.model.domain.ListPersistentAttribute; import org.hibernate.metamodel.model.domain.ListPersistentAttribute;
import org.hibernate.metamodel.model.domain.ManagedDomainType;
import org.hibernate.metamodel.model.domain.TreatableDomainType;
import org.hibernate.query.sqm.SemanticQueryWalker; import org.hibernate.query.sqm.SemanticQueryWalker;
import org.hibernate.spi.NavigablePath; import org.hibernate.spi.NavigablePath;
import org.hibernate.query.criteria.JpaExpression; import org.hibernate.query.criteria.JpaExpression;
@ -123,8 +125,8 @@ public class SqmListJoin<O,E>
} }
@Override @Override
public <S extends E> SqmTreatedListJoin<O,E,S> treatAs(Class<S> treatAsType) { public <S extends E> SqmTreatedListJoin<O,E,S> treatAs(Class<S> treatJavaType) {
return treatAs( nodeBuilder().getDomainModel().entity( treatAsType ), null ); return treatAs( treatJavaType, null );
} }
@Override @Override
@ -134,7 +136,7 @@ public class SqmListJoin<O,E>
@Override @Override
public <S extends E> SqmTreatedListJoin<O,E,S> treatAs(Class<S> treatJavaType, String alias) { public <S extends E> SqmTreatedListJoin<O,E,S> treatAs(Class<S> treatJavaType, String alias) {
return treatAs( nodeBuilder().getDomainModel().entity( treatJavaType ), alias ); return treatAs( treatJavaType, alias, false );
} }
@Override @Override
@ -143,8 +145,18 @@ public class SqmListJoin<O,E>
} }
@Override @Override
public <S extends E> SqmTreatedListJoin<O,E,S> treatAs(Class<S> treatJavaType, String alias, boolean fetch) { public <S extends E> SqmTreatedListJoin<O, E, S> treatAs(Class<S> treatJavaType, String alias, boolean fetch) {
return treatAs( nodeBuilder().getDomainModel().entity( treatJavaType ), alias, fetch ); final ManagedDomainType<S> treatTarget = nodeBuilder().getDomainModel().managedType( treatJavaType );
final SqmTreatedListJoin<O, E, S> treat = findTreat( treatTarget, alias );
if ( treat == null ) {
if ( treatTarget instanceof TreatableDomainType<?> ) {
return addTreat( new SqmTreatedListJoin<>( this, (TreatableDomainType<S>) treatTarget, alias, fetch ) );
}
else {
throw new IllegalArgumentException( "Not a treatable type: " + treatJavaType.getName() );
}
}
return treat;
} }
@Override @Override

View File

@ -11,7 +11,9 @@ import jakarta.persistence.criteria.Expression;
import jakarta.persistence.criteria.Predicate; import jakarta.persistence.criteria.Predicate;
import org.hibernate.metamodel.model.domain.EntityDomainType; import org.hibernate.metamodel.model.domain.EntityDomainType;
import org.hibernate.metamodel.model.domain.ManagedDomainType;
import org.hibernate.metamodel.model.domain.MapPersistentAttribute; import org.hibernate.metamodel.model.domain.MapPersistentAttribute;
import org.hibernate.metamodel.model.domain.TreatableDomainType;
import org.hibernate.query.sqm.SemanticQueryWalker; import org.hibernate.query.sqm.SemanticQueryWalker;
import org.hibernate.spi.NavigablePath; import org.hibernate.spi.NavigablePath;
import org.hibernate.query.criteria.JpaExpression; import org.hibernate.query.criteria.JpaExpression;
@ -136,7 +138,7 @@ public class SqmMapJoin<O, K, V>
@Override @Override
public <S extends V> SqmTreatedMapJoin<O, K, V, S> treatAs(Class<S> treatJavaType) { public <S extends V> SqmTreatedMapJoin<O, K, V, S> treatAs(Class<S> treatJavaType) {
return treatAs( nodeBuilder().getDomainModel().entity( treatJavaType ) ); return treatAs( treatJavaType, null );
} }
@Override @Override
@ -146,7 +148,7 @@ public class SqmMapJoin<O, K, V>
@Override @Override
public <S extends V> SqmTreatedMapJoin<O, K, V, S> treatAs(Class<S> treatJavaType, String alias) { public <S extends V> SqmTreatedMapJoin<O, K, V, S> treatAs(Class<S> treatJavaType, String alias) {
return treatAs( nodeBuilder().getDomainModel().entity( treatJavaType ), alias ); return treatAs( treatJavaType, alias, false );
} }
@Override @Override
@ -156,7 +158,17 @@ public class SqmMapJoin<O, K, V>
@Override @Override
public <S extends V> SqmTreatedMapJoin<O, K, V, S> treatAs(Class<S> treatJavaType, String alias, boolean fetch) { public <S extends V> SqmTreatedMapJoin<O, K, V, S> treatAs(Class<S> treatJavaType, String alias, boolean fetch) {
return treatAs( nodeBuilder().getDomainModel().entity( treatJavaType ), alias, fetch ); final ManagedDomainType<S> treatTarget = nodeBuilder().getDomainModel().managedType( treatJavaType );
final SqmTreatedMapJoin<O, K, V, S> treat = findTreat( treatTarget, alias );
if ( treat == null ) {
if ( treatTarget instanceof TreatableDomainType<?> ) {
return addTreat( new SqmTreatedMapJoin<>( this, (TreatableDomainType<S>) treatTarget, alias, fetch ) );
}
else {
throw new IllegalArgumentException( "Not a treatable type: " + treatJavaType.getName() );
}
}
return treat;
} }
@Override @Override

View File

@ -171,13 +171,13 @@ public class SqmPluralValuedSimplePath<E> extends AbstractSqmSimplePath<E> {
} }
@Override @Override
public <S extends E> SqmTreatedSimplePath<E,S> treatAs(Class<S> treatJavaType) throws PathException { public <S extends E> SqmTreatedPath<E, S> treatAs(Class<S> treatJavaType) throws PathException {
return (SqmTreatedSimplePath<E, S>) treatAs( nodeBuilder().getDomainModel().entity( treatJavaType ) ); throw new UnsupportedOperationException( "Cannot treat plural valued simple paths" );
} }
@Override @Override
public <S extends E> SqmTreatedPath<E, S> treatAs(EntityDomainType<S> treatTarget) throws PathException { public <S extends E> SqmTreatedEntityValuedSimplePath<E, S> treatAs(EntityDomainType<S> treatTarget) throws PathException {
return getTreatedPath( treatTarget ); throw new UnsupportedOperationException( "Cannot treat plural valued simple paths" );
} }
// @Override // @Override

View File

@ -9,7 +9,9 @@ package org.hibernate.query.sqm.tree.domain;
import java.util.Set; import java.util.Set;
import org.hibernate.metamodel.model.domain.EntityDomainType; import org.hibernate.metamodel.model.domain.EntityDomainType;
import org.hibernate.metamodel.model.domain.ManagedDomainType;
import org.hibernate.metamodel.model.domain.SetPersistentAttribute; import org.hibernate.metamodel.model.domain.SetPersistentAttribute;
import org.hibernate.metamodel.model.domain.TreatableDomainType;
import org.hibernate.query.sqm.SemanticQueryWalker; import org.hibernate.query.sqm.SemanticQueryWalker;
import org.hibernate.spi.NavigablePath; import org.hibernate.spi.NavigablePath;
import org.hibernate.query.criteria.JpaExpression; import org.hibernate.query.criteria.JpaExpression;
@ -116,8 +118,8 @@ public class SqmSetJoin<O, E>
} }
@Override @Override
public <S extends E> SqmTreatedSetJoin<O,E,S> treatAs(Class<S> treatAsType) { public <S extends E> SqmTreatedSetJoin<O,E,S> treatAs(Class<S> treatJavaType) {
return treatAs( nodeBuilder().getDomainModel().entity( treatAsType ) ); return treatAs( treatJavaType, null );
} }
@Override @Override
@ -127,7 +129,7 @@ public class SqmSetJoin<O, E>
@Override @Override
public <S extends E> SqmTreatedSetJoin<O,E,S> treatAs(Class<S> treatJavaType, String alias) { public <S extends E> SqmTreatedSetJoin<O,E,S> treatAs(Class<S> treatJavaType, String alias) {
return treatAs( nodeBuilder().getDomainModel().entity( treatJavaType ), alias ); return treatAs( treatJavaType, alias, false );
} }
@Override @Override
@ -136,8 +138,18 @@ public class SqmSetJoin<O, E>
} }
@Override @Override
public <S extends E> SqmTreatedSetJoin<O,E,S> treatAs(Class<S> treatJavaType, String alias, boolean fetch) { public <S extends E> SqmTreatedSetJoin<O, E, S> treatAs(Class<S> treatJavaType, String alias, boolean fetch) {
return treatAs( nodeBuilder().getDomainModel().entity( treatJavaType ), alias, fetch ); final ManagedDomainType<S> treatTarget = nodeBuilder().getDomainModel().managedType( treatJavaType );
final SqmTreatedSetJoin<O, E, S> treat = findTreat( treatTarget, alias );
if ( treat == null ) {
if ( treatTarget instanceof TreatableDomainType<?> ) {
return addTreat( new SqmTreatedSetJoin<>( this, (TreatableDomainType<S>) treatTarget, alias, fetch ) );
}
else {
throw new IllegalArgumentException( "Not a treatable type: " + treatJavaType.getName() );
}
}
return treat;
} }
@Override @Override

View File

@ -8,8 +8,11 @@ package org.hibernate.query.sqm.tree.domain;
import java.util.Locale; import java.util.Locale;
import org.hibernate.metamodel.model.domain.EmbeddableDomainType;
import org.hibernate.metamodel.model.domain.EntityDomainType; import org.hibernate.metamodel.model.domain.EntityDomainType;
import org.hibernate.metamodel.model.domain.ManagedDomainType;
import org.hibernate.metamodel.model.domain.SingularPersistentAttribute; import org.hibernate.metamodel.model.domain.SingularPersistentAttribute;
import org.hibernate.metamodel.model.domain.TreatableDomainType;
import org.hibernate.query.sqm.SemanticQueryWalker; import org.hibernate.query.sqm.SemanticQueryWalker;
import org.hibernate.spi.NavigablePath; import org.hibernate.spi.NavigablePath;
import org.hibernate.query.hql.spi.SqmCreationProcessingState; import org.hibernate.query.hql.spi.SqmCreationProcessingState;
@ -95,7 +98,7 @@ public class SqmSingularJoin<O,T> extends AbstractSqmAttributeJoin<O,T> {
@Override @Override
public <S extends T> SqmTreatedSingularJoin<O,T,S> treatAs(Class<S> treatJavaType) { public <S extends T> SqmTreatedSingularJoin<O,T,S> treatAs(Class<S> treatJavaType) {
return treatAs( nodeBuilder().getDomainModel().entity( treatJavaType ) ); return treatAs( treatJavaType, null );
} }
@Override @Override
@ -105,7 +108,7 @@ public class SqmSingularJoin<O,T> extends AbstractSqmAttributeJoin<O,T> {
@Override @Override
public <S extends T> SqmTreatedSingularJoin<O,T,S> treatAs(Class<S> treatJavaType, String alias) { public <S extends T> SqmTreatedSingularJoin<O,T,S> treatAs(Class<S> treatJavaType, String alias) {
return treatAs( nodeBuilder().getDomainModel().entity( treatJavaType ), alias ); return treatAs( treatJavaType, alias, false );
} }
@Override @Override
@ -115,7 +118,17 @@ public class SqmSingularJoin<O,T> extends AbstractSqmAttributeJoin<O,T> {
@Override @Override
public <S extends T> SqmTreatedSingularJoin<O,T,S> treatAs(Class<S> treatJavaType, String alias, boolean fetch) { public <S extends T> SqmTreatedSingularJoin<O,T,S> treatAs(Class<S> treatJavaType, String alias, boolean fetch) {
return treatAs( nodeBuilder().getDomainModel().entity( treatJavaType ), alias, fetch ); final ManagedDomainType<S> treatTarget = nodeBuilder().getDomainModel().managedType( treatJavaType );
final SqmTreatedSingularJoin<O, T, S> treat = findTreat( treatTarget, alias );
if ( treat == null ) {
if ( treatTarget instanceof TreatableDomainType<?> ) {
return addTreat( new SqmTreatedSingularJoin<>( this, (TreatableDomainType<S>) treatTarget, alias, fetch ) );
}
else {
throw new IllegalArgumentException( "Not a treatable type: " + treatJavaType.getName() );
}
}
return treat;
} }
@Override @Override

View File

@ -8,7 +8,7 @@ package org.hibernate.query.sqm.tree.domain;
import org.hibernate.metamodel.mapping.CollectionPart; import org.hibernate.metamodel.mapping.CollectionPart;
import org.hibernate.metamodel.model.domain.BagPersistentAttribute; import org.hibernate.metamodel.model.domain.BagPersistentAttribute;
import org.hibernate.metamodel.model.domain.EntityDomainType; import org.hibernate.metamodel.model.domain.TreatableDomainType;
import org.hibernate.query.hql.spi.SqmCreationProcessingState; import org.hibernate.query.hql.spi.SqmCreationProcessingState;
import org.hibernate.query.sqm.SqmPathSource; import org.hibernate.query.sqm.SqmPathSource;
import org.hibernate.query.sqm.tree.SqmCopyContext; import org.hibernate.query.sqm.tree.SqmCopyContext;
@ -20,18 +20,18 @@ import org.hibernate.spi.NavigablePath;
*/ */
public class SqmTreatedBagJoin<O,T, S extends T> extends SqmBagJoin<O,S> implements SqmTreatedPath<T,S> { public class SqmTreatedBagJoin<O,T, S extends T> extends SqmBagJoin<O,S> implements SqmTreatedPath<T,S> {
private final SqmBagJoin<O, T> wrappedPath; private final SqmBagJoin<O, T> wrappedPath;
private final EntityDomainType<S> treatTarget; private final TreatableDomainType<S> treatTarget;
public SqmTreatedBagJoin( public SqmTreatedBagJoin(
SqmBagJoin<O, T> wrappedPath, SqmBagJoin<O, T> wrappedPath,
EntityDomainType<S> treatTarget, TreatableDomainType<S> treatTarget,
String alias) { String alias) {
this( wrappedPath, treatTarget, alias, false ); this( wrappedPath, treatTarget, alias, false );
} }
public SqmTreatedBagJoin( public SqmTreatedBagJoin(
SqmBagJoin<O, T> wrappedPath, SqmBagJoin<O, T> wrappedPath,
EntityDomainType<S> treatTarget, TreatableDomainType<S> treatTarget,
String alias, String alias,
boolean fetched) { boolean fetched) {
//noinspection unchecked //noinspection unchecked
@ -39,7 +39,7 @@ public class SqmTreatedBagJoin<O,T, S extends T> extends SqmBagJoin<O,S> impleme
wrappedPath.getLhs(), wrappedPath.getLhs(),
wrappedPath.getNavigablePath() wrappedPath.getNavigablePath()
.append( CollectionPart.Nature.ELEMENT.getName() ) .append( CollectionPart.Nature.ELEMENT.getName() )
.treatAs( treatTarget.getHibernateEntityName(), alias ), .treatAs( treatTarget.getTypeName(), alias ),
(BagPersistentAttribute<O, S>) wrappedPath.getAttribute(), (BagPersistentAttribute<O, S>) wrappedPath.getAttribute(),
alias, alias,
wrappedPath.getSqmJoinType(), wrappedPath.getSqmJoinType(),
@ -53,16 +53,13 @@ public class SqmTreatedBagJoin<O,T, S extends T> extends SqmBagJoin<O,S> impleme
private SqmTreatedBagJoin( private SqmTreatedBagJoin(
NavigablePath navigablePath, NavigablePath navigablePath,
SqmBagJoin<O, T> wrappedPath, SqmBagJoin<O, T> wrappedPath,
EntityDomainType<S> treatTarget, TreatableDomainType<S> treatTarget,
String alias, String alias,
boolean fetched) { boolean fetched) {
//noinspection unchecked //noinspection unchecked
super( super(
wrappedPath.getLhs(), wrappedPath.getLhs(),
wrappedPath.getNavigablePath().treatAs( navigablePath,
treatTarget.getHibernateEntityName(),
alias
),
(BagPersistentAttribute<O, S>) wrappedPath.getAttribute(), (BagPersistentAttribute<O, S>) wrappedPath.getAttribute(),
alias, alias,
wrappedPath.getSqmJoinType(), wrappedPath.getSqmJoinType(),
@ -99,7 +96,7 @@ public class SqmTreatedBagJoin<O,T, S extends T> extends SqmBagJoin<O,S> impleme
} }
@Override @Override
public EntityDomainType<S> getTreatTarget() { public TreatableDomainType<S> getTreatTarget() {
return treatTarget; return treatTarget;
} }
@ -109,7 +106,7 @@ public class SqmTreatedBagJoin<O,T, S extends T> extends SqmBagJoin<O,S> impleme
} }
@Override @Override
public EntityDomainType<S> getReferencedPathSource() { public TreatableDomainType<S> getReferencedPathSource() {
return treatTarget; return treatTarget;
} }
@ -128,7 +125,7 @@ public class SqmTreatedBagJoin<O,T, S extends T> extends SqmBagJoin<O,S> impleme
sb.append( "treat(" ); sb.append( "treat(" );
wrappedPath.appendHqlString( sb ); wrappedPath.appendHqlString( sb );
sb.append( " as " ); sb.append( " as " );
sb.append( treatTarget.getName() ); sb.append( treatTarget.getTypeName() );
sb.append( ')' ); sb.append( ')' );
} }
} }

View File

@ -0,0 +1,122 @@
/*
* 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.sqm.tree.domain;
import org.hibernate.metamodel.model.domain.EmbeddableDomainType;
import org.hibernate.metamodel.model.domain.EntityDomainType;
import org.hibernate.query.hql.spi.SqmCreationState;
import org.hibernate.query.sqm.SemanticQueryWalker;
import org.hibernate.query.sqm.SqmPathSource;
import org.hibernate.query.sqm.tree.SqmCopyContext;
import org.hibernate.spi.NavigablePath;
/**
* @author Steve Ebersole
*/
public class SqmTreatedEmbeddedValuedSimplePath<T, S extends T> extends SqmEmbeddedValuedSimplePath<S>
implements SqmTreatedPath<T, S> {
private final SqmPath<T> wrappedPath;
private final EmbeddableDomainType<S> treatTarget;
@SuppressWarnings( { "unchecked" } )
public SqmTreatedEmbeddedValuedSimplePath(
SqmPath<T> wrappedPath,
EmbeddableDomainType<S> treatTarget) {
super(
wrappedPath.getNavigablePath().treatAs( treatTarget.getTypeName() ),
(SqmPathSource<S>) wrappedPath.getReferencedPathSource(),
null,
wrappedPath.nodeBuilder()
);
this.wrappedPath = wrappedPath;
this.treatTarget = treatTarget;
}
@SuppressWarnings( { "unchecked" } )
private SqmTreatedEmbeddedValuedSimplePath(
NavigablePath navigablePath,
SqmPath<T> wrappedPath,
EmbeddableDomainType<S> treatTarget) {
super(
navigablePath,
(SqmPathSource<S>) wrappedPath.getReferencedPathSource(),
null,
wrappedPath.nodeBuilder()
);
this.wrappedPath = wrappedPath;
this.treatTarget = treatTarget;
}
@Override
public SqmTreatedEmbeddedValuedSimplePath<T, S> copy(SqmCopyContext context) {
final SqmTreatedEmbeddedValuedSimplePath<T, S> existing = context.getCopy( this );
if ( existing != null ) {
return existing;
}
final SqmTreatedEmbeddedValuedSimplePath<T, S> path = context.registerCopy(
this,
new SqmTreatedEmbeddedValuedSimplePath<>(
getNavigablePath(),
wrappedPath.copy( context ),
treatTarget
)
);
copyTo( path, context );
return path;
}
@Override
public EmbeddableDomainType<S> getTreatTarget() {
return treatTarget;
}
@Override
public SqmPath<T> getWrappedPath() {
return wrappedPath;
}
@Override
public SqmPathSource<S> getNodeType() {
return treatTarget;
}
@Override
public SqmPathSource<?> getResolvedModel() {
return treatTarget;
}
@Override
public EmbeddableDomainType<S> getReferencedPathSource() {
return getTreatTarget();
}
@Override
public SqmPath<?> getLhs() {
return wrappedPath.getLhs();
}
@Override
public <X> X accept(SemanticQueryWalker<X> walker) {
return walker.visitTreatedPath( this );
}
@Override
public SqmPath<?> resolvePathPart(String name, boolean isTerminal, SqmCreationState creationState) {
final SqmPath<?> sqmPath = get( name );
creationState.getProcessingStateStack().getCurrent().getPathRegistry().register( sqmPath );
return sqmPath;
}
@Override
public void appendHqlString(StringBuilder sb) {
sb.append( "treat(" );
wrappedPath.appendHqlString( sb );
sb.append( " as " );
sb.append( treatTarget.getTypeName() );
sb.append( ')' );
}
}

View File

@ -17,14 +17,14 @@ import org.hibernate.spi.NavigablePath;
/** /**
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public class SqmTreatedSimplePath<T, S extends T> public class SqmTreatedEntityValuedSimplePath<T, S extends T>
extends SqmEntityValuedSimplePath<S> extends SqmEntityValuedSimplePath<S>
implements SqmSimplePath<S>, SqmTreatedPath<T,S> { implements SqmSimplePath<S>, SqmTreatedPath<T,S> {
private final EntityDomainType<S> treatTarget; private final EntityDomainType<S> treatTarget;
private final SqmPath<T> wrappedPath; private final SqmPath<T> wrappedPath;
public SqmTreatedSimplePath( public SqmTreatedEntityValuedSimplePath(
SqmPluralValuedSimplePath<T> wrappedPath, SqmPluralValuedSimplePath<T> wrappedPath,
EntityDomainType<S> treatTarget, EntityDomainType<S> treatTarget,
NodeBuilder nodeBuilder) { NodeBuilder nodeBuilder) {
@ -41,7 +41,7 @@ public class SqmTreatedSimplePath<T, S extends T>
this.wrappedPath = wrappedPath; this.wrappedPath = wrappedPath;
} }
public SqmTreatedSimplePath( public SqmTreatedEntityValuedSimplePath(
SqmPath<T> wrappedPath, SqmPath<T> wrappedPath,
EntityDomainType<S> treatTarget, EntityDomainType<S> treatTarget,
NodeBuilder nodeBuilder) { NodeBuilder nodeBuilder) {
@ -58,7 +58,7 @@ public class SqmTreatedSimplePath<T, S extends T>
this.wrappedPath = wrappedPath; this.wrappedPath = wrappedPath;
} }
private SqmTreatedSimplePath( private SqmTreatedEntityValuedSimplePath(
NavigablePath navigablePath, NavigablePath navigablePath,
SqmPath<T> wrappedPath, SqmPath<T> wrappedPath,
EntityDomainType<S> treatTarget, EntityDomainType<S> treatTarget,
@ -75,15 +75,15 @@ public class SqmTreatedSimplePath<T, S extends T>
} }
@Override @Override
public SqmTreatedSimplePath<T, S> copy(SqmCopyContext context) { public SqmTreatedEntityValuedSimplePath<T, S> copy(SqmCopyContext context) {
final SqmTreatedSimplePath<T, S> existing = context.getCopy( this ); final SqmTreatedEntityValuedSimplePath<T, S> existing = context.getCopy( this );
if ( existing != null ) { if ( existing != null ) {
return existing; return existing;
} }
final SqmTreatedSimplePath<T, S> path = context.registerCopy( final SqmTreatedEntityValuedSimplePath<T, S> path = context.registerCopy(
this, this,
new SqmTreatedSimplePath<>( new SqmTreatedEntityValuedSimplePath<>(
getNavigablePath(), getNavigablePath(),
wrappedPath.copy( context ), wrappedPath.copy( context ),
getTreatTarget(), getTreatTarget(),
@ -120,7 +120,7 @@ public class SqmTreatedSimplePath<T, S extends T>
} }
@Override @Override
public <S1 extends S> SqmTreatedSimplePath<S,S1> treatAs(Class<S1> treatJavaType) throws PathException { public <S1 extends S> SqmTreatedEntityValuedSimplePath<S,S1> treatAs(Class<S1> treatJavaType) throws PathException {
return super.treatAs( treatJavaType ); return super.treatAs( treatJavaType );
} }

View File

@ -7,8 +7,8 @@
package org.hibernate.query.sqm.tree.domain; package org.hibernate.query.sqm.tree.domain;
import org.hibernate.metamodel.mapping.CollectionPart; import org.hibernate.metamodel.mapping.CollectionPart;
import org.hibernate.metamodel.model.domain.EntityDomainType;
import org.hibernate.metamodel.model.domain.ListPersistentAttribute; import org.hibernate.metamodel.model.domain.ListPersistentAttribute;
import org.hibernate.metamodel.model.domain.TreatableDomainType;
import org.hibernate.query.hql.spi.SqmCreationProcessingState; import org.hibernate.query.hql.spi.SqmCreationProcessingState;
import org.hibernate.query.hql.spi.SqmCreationState; import org.hibernate.query.hql.spi.SqmCreationState;
import org.hibernate.query.sqm.SqmPathSource; import org.hibernate.query.sqm.SqmPathSource;
@ -22,18 +22,18 @@ import org.hibernate.spi.NavigablePath;
*/ */
public class SqmTreatedListJoin<O,T, S extends T> extends SqmListJoin<O,S> implements SqmTreatedPath<T,S> { public class SqmTreatedListJoin<O,T, S extends T> extends SqmListJoin<O,S> implements SqmTreatedPath<T,S> {
private final SqmListJoin<O,T> wrappedPath; private final SqmListJoin<O,T> wrappedPath;
private final EntityDomainType<S> treatTarget; private final TreatableDomainType<S> treatTarget;
public SqmTreatedListJoin( public SqmTreatedListJoin(
SqmListJoin<O, T> wrappedPath, SqmListJoin<O, T> wrappedPath,
EntityDomainType<S> treatTarget, TreatableDomainType<S> treatTarget,
String alias) { String alias) {
this( wrappedPath, treatTarget, alias, false ); this( wrappedPath, treatTarget, alias, false );
} }
public SqmTreatedListJoin( public SqmTreatedListJoin(
SqmListJoin<O, T> wrappedPath, SqmListJoin<O, T> wrappedPath,
EntityDomainType<S> treatTarget, TreatableDomainType<S> treatTarget,
String alias, String alias,
boolean fetched) { boolean fetched) {
//noinspection unchecked //noinspection unchecked
@ -41,7 +41,7 @@ public class SqmTreatedListJoin<O,T, S extends T> extends SqmListJoin<O,S> imple
wrappedPath.getLhs(), wrappedPath.getLhs(),
wrappedPath.getNavigablePath() wrappedPath.getNavigablePath()
.append( CollectionPart.Nature.ELEMENT.getName() ) .append( CollectionPart.Nature.ELEMENT.getName() )
.treatAs( treatTarget.getHibernateEntityName(), alias ), .treatAs( treatTarget.getTypeName(), alias ),
(ListPersistentAttribute<O, S>) wrappedPath.getAttribute(), (ListPersistentAttribute<O, S>) wrappedPath.getAttribute(),
alias, alias,
wrappedPath.getSqmJoinType(), wrappedPath.getSqmJoinType(),
@ -55,7 +55,7 @@ public class SqmTreatedListJoin<O,T, S extends T> extends SqmListJoin<O,S> imple
private SqmTreatedListJoin( private SqmTreatedListJoin(
NavigablePath navigablePath, NavigablePath navigablePath,
SqmListJoin<O, T> wrappedPath, SqmListJoin<O, T> wrappedPath,
EntityDomainType<S> treatTarget, TreatableDomainType<S> treatTarget,
String alias, String alias,
boolean fetched) { boolean fetched) {
//noinspection unchecked //noinspection unchecked
@ -98,7 +98,7 @@ public class SqmTreatedListJoin<O,T, S extends T> extends SqmListJoin<O,S> imple
} }
@Override @Override
public EntityDomainType<S> getTreatTarget() { public TreatableDomainType<S> getTreatTarget() {
return treatTarget; return treatTarget;
} }
@ -108,7 +108,7 @@ public class SqmTreatedListJoin<O,T, S extends T> extends SqmListJoin<O,S> imple
} }
@Override @Override
public EntityDomainType<S> getReferencedPathSource() { public TreatableDomainType<S> getReferencedPathSource() {
return treatTarget; return treatTarget;
} }
@ -135,7 +135,7 @@ public class SqmTreatedListJoin<O,T, S extends T> extends SqmListJoin<O,S> imple
sb.append( "treat(" ); sb.append( "treat(" );
wrappedPath.appendHqlString( sb ); wrappedPath.appendHqlString( sb );
sb.append( " as " ); sb.append( " as " );
sb.append( treatTarget.getName() ); sb.append( treatTarget.getTypeName() );
sb.append( ')' ); sb.append( ')' );
} }
} }

View File

@ -7,7 +7,7 @@
package org.hibernate.query.sqm.tree.domain; package org.hibernate.query.sqm.tree.domain;
import org.hibernate.metamodel.mapping.CollectionPart; import org.hibernate.metamodel.mapping.CollectionPart;
import org.hibernate.metamodel.model.domain.EntityDomainType; import org.hibernate.metamodel.model.domain.TreatableDomainType;
import org.hibernate.query.hql.spi.SqmCreationProcessingState; import org.hibernate.query.hql.spi.SqmCreationProcessingState;
import org.hibernate.query.sqm.SqmPathSource; import org.hibernate.query.sqm.SqmPathSource;
import org.hibernate.query.sqm.tree.SqmCopyContext; import org.hibernate.query.sqm.tree.SqmCopyContext;
@ -18,18 +18,18 @@ import org.hibernate.spi.NavigablePath;
*/ */
public class SqmTreatedMapJoin<O, K, V, S extends V> extends SqmMapJoin<O, K, S> implements SqmTreatedPath<V, S> { public class SqmTreatedMapJoin<O, K, V, S extends V> extends SqmMapJoin<O, K, S> implements SqmTreatedPath<V, S> {
private final SqmMapJoin<O, K, V> wrappedPath; private final SqmMapJoin<O, K, V> wrappedPath;
private final EntityDomainType<S> treatTarget; private final TreatableDomainType<S> treatTarget;
public SqmTreatedMapJoin( public SqmTreatedMapJoin(
SqmMapJoin<O, K, V> wrappedPath, SqmMapJoin<O, K, V> wrappedPath,
EntityDomainType<S> treatTarget, TreatableDomainType<S> treatTarget,
String alias) { String alias) {
this( wrappedPath, treatTarget, alias, false ); this( wrappedPath, treatTarget, alias, false );
} }
public SqmTreatedMapJoin( public SqmTreatedMapJoin(
SqmMapJoin<O, K, V> wrappedPath, SqmMapJoin<O, K, V> wrappedPath,
EntityDomainType<S> treatTarget, TreatableDomainType<S> treatTarget,
String alias, String alias,
boolean fetched) { boolean fetched) {
//noinspection unchecked //noinspection unchecked
@ -37,7 +37,7 @@ public class SqmTreatedMapJoin<O, K, V, S extends V> extends SqmMapJoin<O, K, S>
wrappedPath.getLhs(), wrappedPath.getLhs(),
wrappedPath.getNavigablePath() wrappedPath.getNavigablePath()
.append( CollectionPart.Nature.ELEMENT.getName() ) .append( CollectionPart.Nature.ELEMENT.getName() )
.treatAs( treatTarget.getHibernateEntityName(), alias ), .treatAs( treatTarget.getTypeName(), alias ),
( (SqmMapJoin<O, K, S>) wrappedPath ).getModel(), ( (SqmMapJoin<O, K, S>) wrappedPath ).getModel(),
alias, alias,
wrappedPath.getSqmJoinType(), wrappedPath.getSqmJoinType(),
@ -51,7 +51,7 @@ public class SqmTreatedMapJoin<O, K, V, S extends V> extends SqmMapJoin<O, K, S>
private SqmTreatedMapJoin( private SqmTreatedMapJoin(
NavigablePath navigablePath, NavigablePath navigablePath,
SqmMapJoin<O, K, V> wrappedPath, SqmMapJoin<O, K, V> wrappedPath,
EntityDomainType<S> treatTarget, TreatableDomainType<S> treatTarget,
String alias, String alias,
boolean fetched) { boolean fetched) {
//noinspection unchecked //noinspection unchecked
@ -94,7 +94,7 @@ public class SqmTreatedMapJoin<O, K, V, S extends V> extends SqmMapJoin<O, K, S>
} }
@Override @Override
public EntityDomainType<S> getTreatTarget() { public TreatableDomainType<S> getTreatTarget() {
return treatTarget; return treatTarget;
} }
@ -104,7 +104,7 @@ public class SqmTreatedMapJoin<O, K, V, S extends V> extends SqmMapJoin<O, K, S>
} }
@Override @Override
public EntityDomainType<S> getReferencedPathSource() { public TreatableDomainType<S> getReferencedPathSource() {
return treatTarget; return treatTarget;
} }
@ -127,7 +127,7 @@ public class SqmTreatedMapJoin<O, K, V, S extends V> extends SqmMapJoin<O, K, S>
sb.append( "treat(" ); sb.append( "treat(" );
wrappedPath.appendHqlString( sb ); wrappedPath.appendHqlString( sb );
sb.append( " as " ); sb.append( " as " );
sb.append( treatTarget.getName() ); sb.append( treatTarget.getTypeName() );
sb.append( ')' ); sb.append( ')' );
} }
} }

View File

@ -6,14 +6,13 @@
*/ */
package org.hibernate.query.sqm.tree.domain; package org.hibernate.query.sqm.tree.domain;
import org.hibernate.metamodel.model.domain.EntityDomainType; import org.hibernate.metamodel.model.domain.ManagedDomainType;
import org.hibernate.query.sqm.SqmPathSource;
/** /**
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public interface SqmTreatedPath<T, S extends T> extends SqmPathWrapper<T, S> { public interface SqmTreatedPath<T, S extends T> extends SqmPathWrapper<T, S> {
EntityDomainType<S> getTreatTarget(); ManagedDomainType<S> getTreatTarget();
@Override @Override
SqmPath<T> getWrappedPath(); SqmPath<T> getWrappedPath();

View File

@ -7,7 +7,7 @@
package org.hibernate.query.sqm.tree.domain; package org.hibernate.query.sqm.tree.domain;
import org.hibernate.metamodel.mapping.CollectionPart; import org.hibernate.metamodel.mapping.CollectionPart;
import org.hibernate.metamodel.model.domain.EntityDomainType; import org.hibernate.metamodel.model.domain.TreatableDomainType;
import org.hibernate.metamodel.model.domain.SetPersistentAttribute; import org.hibernate.metamodel.model.domain.SetPersistentAttribute;
import org.hibernate.query.hql.spi.SqmCreationProcessingState; import org.hibernate.query.hql.spi.SqmCreationProcessingState;
import org.hibernate.query.sqm.SqmPathSource; import org.hibernate.query.sqm.SqmPathSource;
@ -20,18 +20,18 @@ import org.hibernate.spi.NavigablePath;
*/ */
public class SqmTreatedSetJoin<O,T, S extends T> extends SqmSetJoin<O,S> implements SqmTreatedPath<T,S> { public class SqmTreatedSetJoin<O,T, S extends T> extends SqmSetJoin<O,S> implements SqmTreatedPath<T,S> {
private final SqmSetJoin<O,T> wrappedPath; private final SqmSetJoin<O,T> wrappedPath;
private final EntityDomainType<S> treatTarget; private final TreatableDomainType<S> treatTarget;
public SqmTreatedSetJoin( public SqmTreatedSetJoin(
SqmSetJoin<O, T> wrappedPath, SqmSetJoin<O, T> wrappedPath,
EntityDomainType<S> treatTarget, TreatableDomainType<S> treatTarget,
String alias) { String alias) {
this( wrappedPath, treatTarget, alias, false ); this( wrappedPath, treatTarget, alias, false );
} }
public SqmTreatedSetJoin( public SqmTreatedSetJoin(
SqmSetJoin<O, T> wrappedPath, SqmSetJoin<O, T> wrappedPath,
EntityDomainType<S> treatTarget, TreatableDomainType<S> treatTarget,
String alias, String alias,
boolean fetched) { boolean fetched) {
//noinspection unchecked //noinspection unchecked
@ -39,7 +39,7 @@ public class SqmTreatedSetJoin<O,T, S extends T> extends SqmSetJoin<O,S> impleme
wrappedPath.getLhs(), wrappedPath.getLhs(),
wrappedPath.getNavigablePath() wrappedPath.getNavigablePath()
.append( CollectionPart.Nature.ELEMENT.getName() ) .append( CollectionPart.Nature.ELEMENT.getName() )
.treatAs( treatTarget.getHibernateEntityName(), alias ), .treatAs( treatTarget.getTypeName(), alias ),
(SetPersistentAttribute<O, S>) wrappedPath.getAttribute(), (SetPersistentAttribute<O, S>) wrappedPath.getAttribute(),
alias, alias,
wrappedPath.getSqmJoinType(), wrappedPath.getSqmJoinType(),
@ -53,7 +53,7 @@ public class SqmTreatedSetJoin<O,T, S extends T> extends SqmSetJoin<O,S> impleme
private SqmTreatedSetJoin( private SqmTreatedSetJoin(
NavigablePath navigablePath, NavigablePath navigablePath,
SqmSetJoin<O, T> wrappedPath, SqmSetJoin<O, T> wrappedPath,
EntityDomainType<S> treatTarget, TreatableDomainType<S> treatTarget,
String alias, String alias,
boolean fetched) { boolean fetched) {
//noinspection unchecked //noinspection unchecked
@ -96,7 +96,7 @@ public class SqmTreatedSetJoin<O,T, S extends T> extends SqmSetJoin<O,S> impleme
} }
@Override @Override
public EntityDomainType<S> getTreatTarget() { public TreatableDomainType<S> getTreatTarget() {
return treatTarget; return treatTarget;
} }
@ -106,7 +106,7 @@ public class SqmTreatedSetJoin<O,T, S extends T> extends SqmSetJoin<O,S> impleme
} }
@Override @Override
public EntityDomainType<S> getReferencedPathSource() { public TreatableDomainType<S> getReferencedPathSource() {
return treatTarget; return treatTarget;
} }
@ -125,7 +125,7 @@ public class SqmTreatedSetJoin<O,T, S extends T> extends SqmSetJoin<O,S> impleme
sb.append( "treat(" ); sb.append( "treat(" );
wrappedPath.appendHqlString( sb ); wrappedPath.appendHqlString( sb );
sb.append( " as " ); sb.append( " as " );
sb.append( treatTarget.getName() ); sb.append( treatTarget.getTypeName() );
sb.append( ')' ); sb.append( ')' );
} }
} }

View File

@ -6,8 +6,8 @@
*/ */
package org.hibernate.query.sqm.tree.domain; package org.hibernate.query.sqm.tree.domain;
import org.hibernate.metamodel.model.domain.EntityDomainType;
import org.hibernate.metamodel.model.domain.SingularPersistentAttribute; import org.hibernate.metamodel.model.domain.SingularPersistentAttribute;
import org.hibernate.metamodel.model.domain.TreatableDomainType;
import org.hibernate.query.hql.spi.SqmCreationProcessingState; import org.hibernate.query.hql.spi.SqmCreationProcessingState;
import org.hibernate.query.sqm.SqmPathSource; import org.hibernate.query.sqm.SqmPathSource;
import org.hibernate.query.sqm.tree.SqmCopyContext; import org.hibernate.query.sqm.tree.SqmCopyContext;
@ -19,25 +19,25 @@ import org.hibernate.spi.NavigablePath;
*/ */
public class SqmTreatedSingularJoin<O,T, S extends T> extends SqmSingularJoin<O,S> implements SqmTreatedPath<T,S> { public class SqmTreatedSingularJoin<O,T, S extends T> extends SqmSingularJoin<O,S> implements SqmTreatedPath<T,S> {
private final SqmSingularJoin<O,T> wrappedPath; private final SqmSingularJoin<O,T> wrappedPath;
private final EntityDomainType<S> treatTarget; private final TreatableDomainType<S> treatTarget;
public SqmTreatedSingularJoin( public SqmTreatedSingularJoin(
SqmSingularJoin<O,T> wrappedPath, SqmSingularJoin<O,T> wrappedPath,
EntityDomainType<S> treatTarget, TreatableDomainType<S> treatTarget,
String alias) { String alias) {
this( wrappedPath, treatTarget, alias, false ); this( wrappedPath, treatTarget, alias, false );
} }
public SqmTreatedSingularJoin( public SqmTreatedSingularJoin(
SqmSingularJoin<O,T> wrappedPath, SqmSingularJoin<O,T> wrappedPath,
EntityDomainType<S> treatTarget, TreatableDomainType<S> treatTarget,
String alias, String alias,
boolean fetched) { boolean fetched) {
//noinspection unchecked //noinspection unchecked
super( super(
wrappedPath.getLhs(), wrappedPath.getLhs(),
wrappedPath.getNavigablePath().treatAs( wrappedPath.getNavigablePath().treatAs(
treatTarget.getHibernateEntityName(), treatTarget.getTypeName(),
alias alias
), ),
(SingularPersistentAttribute<O, S>) wrappedPath.getAttribute(), (SingularPersistentAttribute<O, S>) wrappedPath.getAttribute(),
@ -53,7 +53,7 @@ public class SqmTreatedSingularJoin<O,T, S extends T> extends SqmSingularJoin<O,
private SqmTreatedSingularJoin( private SqmTreatedSingularJoin(
NavigablePath navigablePath, NavigablePath navigablePath,
SqmSingularJoin<O,T> wrappedPath, SqmSingularJoin<O,T> wrappedPath,
EntityDomainType<S> treatTarget, TreatableDomainType<S> treatTarget,
String alias, String alias,
boolean fetched) { boolean fetched) {
//noinspection unchecked //noinspection unchecked
@ -96,7 +96,7 @@ public class SqmTreatedSingularJoin<O,T, S extends T> extends SqmSingularJoin<O,
} }
@Override @Override
public EntityDomainType<S> getTreatTarget() { public TreatableDomainType<S> getTreatTarget() {
return treatTarget; return treatTarget;
} }
@ -106,7 +106,7 @@ public class SqmTreatedSingularJoin<O,T, S extends T> extends SqmSingularJoin<O,
} }
@Override @Override
public EntityDomainType<S> getReferencedPathSource() { public TreatableDomainType<S> getReferencedPathSource() {
return treatTarget; return treatTarget;
} }
@ -125,7 +125,7 @@ public class SqmTreatedSingularJoin<O,T, S extends T> extends SqmSingularJoin<O,
sb.append( "treat(" ); sb.append( "treat(" );
wrappedPath.appendHqlString( sb ); wrappedPath.appendHqlString( sb );
sb.append( " as " ); sb.append( " as " );
sb.append( treatTarget.getName() ); sb.append( treatTarget.getTypeName() );
sb.append( ')' ); sb.append( ')' );
} }
} }

View File

@ -0,0 +1,110 @@
/*
* 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.sqm.tree.expression;
import org.hibernate.metamodel.model.domain.EmbeddableDomainType;
import org.hibernate.query.hql.HqlInterpretationException;
import org.hibernate.query.hql.spi.SemanticPathPart;
import org.hibernate.query.hql.spi.SqmCreationState;
import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.SemanticQueryWalker;
import org.hibernate.query.sqm.SqmExpressible;
import org.hibernate.query.sqm.tree.SqmCopyContext;
import org.hibernate.query.sqm.tree.domain.SqmPath;
import org.hibernate.query.sqm.tree.select.SqmSelectableNode;
import org.hibernate.type.BasicType;
import org.hibernate.type.StandardBasicTypes;
/**
* Represents a reference to an embeddable type as a literal.
*
* @author Marco Belladelli
*/
public class SqmLiteralEmbeddableType<T>
extends AbstractSqmExpression<T>
implements SqmSelectableNode<T>, SemanticPathPart {
final EmbeddableDomainType<T> embeddableDomainType;
public SqmLiteralEmbeddableType(
EmbeddableDomainType<T> embeddableDomainType,
NodeBuilder nodeBuilder) {
//noinspection unchecked
super(
(SqmExpressible<? super T>) nodeBuilder.getTypeConfiguration()
.getBasicTypeRegistry()
.resolve( StandardBasicTypes.CLASS ),
nodeBuilder
);
this.embeddableDomainType = embeddableDomainType;
}
public EmbeddableDomainType<T> getEmbeddableDomainType() {
return embeddableDomainType;
}
@Override
public BasicType<T> getNodeType() {
return (BasicType<T>) super.getNodeType();
}
@Override
public EmbeddableDomainType<T> getExpressible() {
return embeddableDomainType;
}
@Override
public SqmLiteralEmbeddableType<T> copy(SqmCopyContext context) {
final SqmLiteralEmbeddableType<T> existing = context.getCopy( this );
if ( existing != null ) {
return existing;
}
final SqmLiteralEmbeddableType<T> expression = context.registerCopy(
this,
new SqmLiteralEmbeddableType<>(
embeddableDomainType,
nodeBuilder()
)
);
copyTo( expression, context );
return expression;
}
@Override
public void internalApplyInferableType(SqmExpressible<?> type) {
}
@Override
public <X> X accept(SemanticQueryWalker<X> walker) {
return walker.visitEmbeddableTypeLiteralExpression( this );
}
@Override
public String asLoggableText() {
return "TYPE(" + embeddableDomainType + ")";
}
@Override
public SemanticPathPart resolvePathPart(
String name,
boolean isTerminal,
SqmCreationState creationState) {
throw new HqlInterpretationException( "Cannot dereference an embeddable name" );
}
@Override
public SqmPath<?> resolveIndexedAccess(
SqmExpression<?> selector,
boolean isTerminal,
SqmCreationState creationState) {
throw new HqlInterpretationException( "Cannot dereference an embeddable name" );
}
@Override
public void appendHqlString(StringBuilder sb) {
sb.append( embeddableDomainType.getTypeName() );
}
}

View File

@ -8,11 +8,8 @@ package org.hibernate.query.sqm.tree.from;
import java.util.List; import java.util.List;
import java.util.function.Consumer; import java.util.function.Consumer;
import jakarta.persistence.criteria.CollectionJoin;
import jakarta.persistence.criteria.JoinType; import jakarta.persistence.criteria.JoinType;
import jakarta.persistence.criteria.ListJoin;
import jakarta.persistence.criteria.MapJoin;
import jakarta.persistence.criteria.SetJoin;
import jakarta.persistence.metamodel.CollectionAttribute; import jakarta.persistence.metamodel.CollectionAttribute;
import jakarta.persistence.metamodel.ListAttribute; import jakarta.persistence.metamodel.ListAttribute;
import jakarta.persistence.metamodel.MapAttribute; import jakarta.persistence.metamodel.MapAttribute;
@ -20,11 +17,7 @@ import jakarta.persistence.metamodel.SetAttribute;
import jakarta.persistence.metamodel.SingularAttribute; import jakarta.persistence.metamodel.SingularAttribute;
import org.hibernate.metamodel.model.domain.EntityDomainType; import org.hibernate.metamodel.model.domain.EntityDomainType;
import org.hibernate.query.PathException;
import org.hibernate.query.criteria.JpaFrom; import org.hibernate.query.criteria.JpaFrom;
import org.hibernate.query.criteria.JpaJoin;
import org.hibernate.query.criteria.JpaPath;
import org.hibernate.query.hql.spi.SqmCreationState;
import org.hibernate.query.sqm.SqmPathSource; import org.hibernate.query.sqm.SqmPathSource;
import org.hibernate.query.sqm.tree.SqmCopyContext; import org.hibernate.query.sqm.tree.SqmCopyContext;
import org.hibernate.query.sqm.tree.SqmVisitableNode; import org.hibernate.query.sqm.tree.SqmVisitableNode;
@ -35,6 +28,8 @@ import org.hibernate.query.sqm.tree.domain.SqmPath;
import org.hibernate.query.sqm.tree.domain.SqmSetJoin; import org.hibernate.query.sqm.tree.domain.SqmSetJoin;
import org.hibernate.query.sqm.tree.domain.SqmSingularJoin; import org.hibernate.query.sqm.tree.domain.SqmSingularJoin;
import static org.hibernate.internal.util.collections.CollectionHelper.isEmpty;
/** /**
* Models a Bindable's inclusion in the {@code FROM} clause. * Models a Bindable's inclusion in the {@code FROM} clause.
* *
@ -67,6 +62,15 @@ public interface SqmFrom<O,T> extends SqmVisitableNode, SqmPath<T>, JpaFrom<O, T
*/ */
void visitSqmJoins(Consumer<SqmJoin<T, ?>> consumer); void visitSqmJoins(Consumer<SqmJoin<T, ?>> consumer);
/**
* The treats associated with this SqmFrom
*/
List<SqmFrom<?, ?>> getSqmTreats();
default boolean hasTreats() {
return !isEmpty( getSqmTreats() );
}
@Override @Override
<S extends T> SqmFrom<?, S> treatAs(Class<S> treatAsType); <S extends T> SqmFrom<?, S> treatAs(Class<S> treatAsType);
@ -77,14 +81,6 @@ public interface SqmFrom<O,T> extends SqmVisitableNode, SqmPath<T>, JpaFrom<O, T
<S extends T> SqmFrom<?, S> treatAs(EntityDomainType<S> treatTarget, String alias); <S extends T> SqmFrom<?, S> treatAs(EntityDomainType<S> treatTarget, String alias);
boolean hasTreats();
/**
* The treats associated with this SqmFrom
*/
List<SqmFrom<?,?>> getSqmTreats();
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// JPA // JPA

View File

@ -141,7 +141,7 @@ public class SqmFromClause implements Serializable {
final SqmTreatedPath<?, ?> treatedPath = (SqmTreatedPath<?, ?>) sqmFrom; final SqmTreatedPath<?, ?> treatedPath = (SqmTreatedPath<?, ?>) sqmFrom;
sb.append( "treat(" ); sb.append( "treat(" );
sb.append( treatedPath.getWrappedPath().resolveAlias() ); sb.append( treatedPath.getWrappedPath().resolveAlias() );
sb.append( " as " ).append( treatedPath.getTreatTarget().getName() ).append( ')' ); sb.append( " as " ).append( treatedPath.getTreatTarget().getTypeName() ).append( ')' );
} }
else { else {
sb.append( sqmFrom.resolveAlias() ); sb.append( sqmFrom.resolveAlias() );

View File

@ -22,6 +22,7 @@ import org.hibernate.sql.ast.tree.expression.AggregateColumnWriteExpression;
import org.hibernate.sql.ast.tree.expression.Distinct; import org.hibernate.sql.ast.tree.expression.Distinct;
import org.hibernate.sql.ast.tree.expression.Duration; import org.hibernate.sql.ast.tree.expression.Duration;
import org.hibernate.sql.ast.tree.expression.DurationUnit; import org.hibernate.sql.ast.tree.expression.DurationUnit;
import org.hibernate.sql.ast.tree.expression.EmbeddableTypeLiteral;
import org.hibernate.sql.ast.tree.expression.EntityTypeLiteral; import org.hibernate.sql.ast.tree.expression.EntityTypeLiteral;
import org.hibernate.sql.ast.tree.expression.Every; import org.hibernate.sql.ast.tree.expression.Every;
import org.hibernate.sql.ast.tree.expression.ExtractUnit; import org.hibernate.sql.ast.tree.expression.ExtractUnit;
@ -167,6 +168,8 @@ public interface SqlAstWalker {
void visitEntityTypeLiteral(EntityTypeLiteral expression); void visitEntityTypeLiteral(EntityTypeLiteral expression);
void visitEmbeddableTypeLiteral(EmbeddableTypeLiteral expression);
void visitTuple(SqlTuple tuple); void visitTuple(SqlTuple tuple);
void visitCollation(Collation collation); void visitCollation(Collation collation);

View File

@ -115,6 +115,7 @@ import org.hibernate.sql.ast.tree.expression.ColumnReference;
import org.hibernate.sql.ast.tree.expression.Distinct; import org.hibernate.sql.ast.tree.expression.Distinct;
import org.hibernate.sql.ast.tree.expression.Duration; import org.hibernate.sql.ast.tree.expression.Duration;
import org.hibernate.sql.ast.tree.expression.DurationUnit; import org.hibernate.sql.ast.tree.expression.DurationUnit;
import org.hibernate.sql.ast.tree.expression.EmbeddableTypeLiteral;
import org.hibernate.sql.ast.tree.expression.EntityTypeLiteral; import org.hibernate.sql.ast.tree.expression.EntityTypeLiteral;
import org.hibernate.sql.ast.tree.expression.Every; import org.hibernate.sql.ast.tree.expression.Every;
import org.hibernate.sql.ast.tree.expression.Expression; import org.hibernate.sql.ast.tree.expression.Expression;
@ -218,6 +219,7 @@ import org.hibernate.type.BasicType;
import org.hibernate.type.SqlTypes; import org.hibernate.type.SqlTypes;
import org.hibernate.type.StandardBasicTypes; import org.hibernate.type.StandardBasicTypes;
import org.hibernate.type.descriptor.WrapperOptions; import org.hibernate.type.descriptor.WrapperOptions;
import org.hibernate.type.descriptor.converter.spi.BasicValueConverter;
import org.hibernate.type.descriptor.java.JavaType; import org.hibernate.type.descriptor.java.JavaType;
import org.hibernate.type.descriptor.jdbc.JdbcLiteralFormatter; import org.hibernate.type.descriptor.jdbc.JdbcLiteralFormatter;
import org.hibernate.type.descriptor.jdbc.JdbcType; import org.hibernate.type.descriptor.jdbc.JdbcType;
@ -225,6 +227,7 @@ import org.hibernate.type.descriptor.sql.DdlType;
import org.hibernate.type.descriptor.sql.spi.DdlTypeRegistry; import org.hibernate.type.descriptor.sql.spi.DdlTypeRegistry;
import org.hibernate.type.spi.TypeConfiguration; import org.hibernate.type.spi.TypeConfiguration;
import static org.hibernate.persister.entity.DiscriminatorHelper.jdbcLiteral;
import static org.hibernate.query.sqm.BinaryArithmeticOperator.DIVIDE_PORTABLE; import static org.hibernate.query.sqm.BinaryArithmeticOperator.DIVIDE_PORTABLE;
import static org.hibernate.query.sqm.TemporalUnit.NANOSECOND; import static org.hibernate.query.sqm.TemporalUnit.NANOSECOND;
import static org.hibernate.sql.ast.SqlTreePrinter.logSqlAst; import static org.hibernate.sql.ast.SqlTreePrinter.logSqlAst;
@ -7203,6 +7206,19 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
appendSql( expression.getEntityTypeDescriptor().getDiscriminatorSQLValue() ); appendSql( expression.getEntityTypeDescriptor().getDiscriminatorSQLValue() );
} }
@SuppressWarnings( { "rawtypes", "unchecked" } )
@Override
public void visitEmbeddableTypeLiteral(EmbeddableTypeLiteral expression) {
final BasicValueConverter valueConverter = expression.getJdbcMapping().getValueConverter();
appendSql( jdbcLiteral(
valueConverter != null ?
valueConverter.toRelationalValue( expression.getEmbeddableClass() ) :
expression.getEmbeddableClass(),
expression.getExpressionType().getSingleJdbcMapping().getJdbcLiteralFormatter(),
getDialect()
) );
}
@Override @Override
public void visitBinaryArithmeticExpression(BinaryArithmeticExpression arithmeticExpression) { public void visitBinaryArithmeticExpression(BinaryArithmeticExpression arithmeticExpression) {
final BinaryArithmeticOperator operator = arithmeticExpression.getOperator(); final BinaryArithmeticOperator operator = arithmeticExpression.getOperator();

View File

@ -25,6 +25,7 @@ import org.hibernate.sql.ast.tree.expression.ColumnReference;
import org.hibernate.sql.ast.tree.expression.Distinct; import org.hibernate.sql.ast.tree.expression.Distinct;
import org.hibernate.sql.ast.tree.expression.Duration; import org.hibernate.sql.ast.tree.expression.Duration;
import org.hibernate.sql.ast.tree.expression.DurationUnit; import org.hibernate.sql.ast.tree.expression.DurationUnit;
import org.hibernate.sql.ast.tree.expression.EmbeddableTypeLiteral;
import org.hibernate.sql.ast.tree.expression.EntityTypeLiteral; import org.hibernate.sql.ast.tree.expression.EntityTypeLiteral;
import org.hibernate.sql.ast.tree.expression.Every; import org.hibernate.sql.ast.tree.expression.Every;
import org.hibernate.sql.ast.tree.expression.Expression; import org.hibernate.sql.ast.tree.expression.Expression;
@ -529,6 +530,10 @@ public class AbstractSqlAstWalker implements SqlAstWalker {
public void visitEntityTypeLiteral(EntityTypeLiteral expression) { public void visitEntityTypeLiteral(EntityTypeLiteral expression) {
} }
@Override
public void visitEmbeddableTypeLiteral(EmbeddableTypeLiteral expression) {
}
@Override @Override
public void visitNamedTableReference(NamedTableReference tableReference) { public void visitNamedTableReference(NamedTableReference tableReference) {
} }

View File

@ -17,6 +17,7 @@ import org.hibernate.sql.ast.tree.expression.ColumnReference;
import org.hibernate.sql.ast.tree.expression.Distinct; import org.hibernate.sql.ast.tree.expression.Distinct;
import org.hibernate.sql.ast.tree.expression.Duration; import org.hibernate.sql.ast.tree.expression.Duration;
import org.hibernate.sql.ast.tree.expression.DurationUnit; import org.hibernate.sql.ast.tree.expression.DurationUnit;
import org.hibernate.sql.ast.tree.expression.EmbeddableTypeLiteral;
import org.hibernate.sql.ast.tree.expression.EntityTypeLiteral; import org.hibernate.sql.ast.tree.expression.EntityTypeLiteral;
import org.hibernate.sql.ast.tree.expression.Every; import org.hibernate.sql.ast.tree.expression.Every;
import org.hibernate.sql.ast.tree.expression.Expression; import org.hibernate.sql.ast.tree.expression.Expression;
@ -249,6 +250,10 @@ public class AggregateFunctionChecker extends AbstractSqlAstWalker {
public void visitEntityTypeLiteral(EntityTypeLiteral expression) { public void visitEntityTypeLiteral(EntityTypeLiteral expression) {
} }
@Override
public void visitEmbeddableTypeLiteral(EmbeddableTypeLiteral expression) {
}
@Override @Override
public void visitSqlSelectionExpression(SqlSelectionExpression expression) { public void visitSqlSelectionExpression(SqlSelectionExpression expression) {
} }

View File

@ -26,6 +26,7 @@ import org.hibernate.sql.ast.tree.expression.AggregateColumnWriteExpression;
import org.hibernate.sql.ast.tree.expression.Distinct; import org.hibernate.sql.ast.tree.expression.Distinct;
import org.hibernate.sql.ast.tree.expression.Duration; import org.hibernate.sql.ast.tree.expression.Duration;
import org.hibernate.sql.ast.tree.expression.DurationUnit; import org.hibernate.sql.ast.tree.expression.DurationUnit;
import org.hibernate.sql.ast.tree.expression.EmbeddableTypeLiteral;
import org.hibernate.sql.ast.tree.expression.EntityTypeLiteral; import org.hibernate.sql.ast.tree.expression.EntityTypeLiteral;
import org.hibernate.sql.ast.tree.expression.Every; import org.hibernate.sql.ast.tree.expression.Every;
import org.hibernate.sql.ast.tree.expression.Expression; import org.hibernate.sql.ast.tree.expression.Expression;
@ -215,6 +216,11 @@ public class ExpressionReplacementWalker implements SqlAstWalker {
doReplaceExpression( expression ); doReplaceExpression( expression );
} }
@Override
public void visitEmbeddableTypeLiteral(EmbeddableTypeLiteral expression) {
doReplaceExpression( expression );
}
@Override @Override
public void visitTuple(SqlTuple tuple) { public void visitTuple(SqlTuple tuple) {
doReplaceExpression( tuple ); doReplaceExpression( tuple );

View File

@ -0,0 +1,151 @@
/*
* 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.sql.ast.tree.expression;
import org.hibernate.cache.MutableCacheKeyBuilder;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.internal.util.IndexedConsumer;
import org.hibernate.metamodel.mapping.BasicValuedMapping;
import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.mapping.MappingModelExpressible;
import org.hibernate.metamodel.mapping.MappingType;
import org.hibernate.metamodel.model.domain.EmbeddableDomainType;
import org.hibernate.query.sqm.sql.internal.DomainResultProducer;
import org.hibernate.sql.ast.SqlAstWalker;
import org.hibernate.sql.ast.spi.SqlSelection;
import org.hibernate.sql.results.graph.DomainResult;
import org.hibernate.sql.results.graph.DomainResultCreationState;
import org.hibernate.sql.results.graph.basic.BasicResult;
import org.hibernate.type.BasicType;
import org.hibernate.type.descriptor.java.JavaType;
/**
* @author Steve Ebersole
*/
public class EmbeddableTypeLiteral
implements Expression, DomainResultProducer<Object>, BasicValuedMapping {
private final Class<?> embeddableClass;
private final BasicType<?> basicType;
public EmbeddableTypeLiteral(
EmbeddableDomainType<?> embeddableDomainType,
BasicType<?> basicType) {
this.embeddableClass = embeddableDomainType.getJavaType();
this.basicType = basicType;
}
public Object getEmbeddableClass() {
return embeddableClass;
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// BasicValuedMapping
@Override
public MappingModelExpressible<?> getExpressionType() {
return this;
}
@Override
public JdbcMapping getJdbcMapping() {
return basicType;
}
@Override
public MappingType getMappedType() {
return basicType;
}
@Override
public int getJdbcTypeCount() {
return basicType.getJdbcTypeCount();
}
@Override
public JdbcMapping getJdbcMapping(int index) {
return basicType.getJdbcMapping( index );
}
@Override
public JdbcMapping getSingleJdbcMapping() {
return basicType.getSingleJdbcMapping();
}
@Override
public int forEachJdbcType(int offset, IndexedConsumer<JdbcMapping> action) {
return basicType.forEachJdbcType( offset, action );
}
@Override
public Object disassemble(Object value, SharedSessionContractImplementor session) {
return basicType.disassemble( value, session );
}
@Override
public void addToCacheKey(MutableCacheKeyBuilder cacheKey, Object value, SharedSessionContractImplementor session) {
basicType.addToCacheKey( cacheKey, value, session );
}
@Override
public <X, Y> int forEachDisassembledJdbcValue(
Object value,
int offset,
X x,
Y y,
JdbcValuesBiConsumer<X, Y> valuesConsumer,
SharedSessionContractImplementor session) {
return basicType.forEachDisassembledJdbcValue( value, offset, x, y, valuesConsumer, session );
}
@Override
public <X, Y> int forEachJdbcValue(
Object value,
int offset,
X x,
Y y,
JdbcValuesBiConsumer<X, Y> valuesConsumer,
SharedSessionContractImplementor session) {
return basicType.forEachJdbcValue( value, offset, x, y, valuesConsumer, session );
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// DomainResultProducer
@Override
public void applySqlSelections(DomainResultCreationState creationState) {
createSqlSelection( creationState );
}
@Override
public DomainResult<Object> createDomainResult(String resultVariable, DomainResultCreationState creationState) {
return new BasicResult<>(
createSqlSelection( creationState ).getValuesArrayPosition(),
resultVariable,
basicType
);
}
private SqlSelection createSqlSelection(DomainResultCreationState creationState) {
return creationState.getSqlAstCreationState().getSqlExpressionResolver().resolveSqlSelection(
this,
basicType.getJdbcJavaType(),
null,
creationState.getSqlAstCreationState().getCreationContext().getMappingMetamodel().getTypeConfiguration()
);
}
@Override
public void accept(SqlAstWalker sqlTreeWalker) {
sqlTreeWalker.visitEmbeddableTypeLiteral( this );
}
@Override
public JavaType getExpressibleJavaType() {
return basicType.getExpressibleJavaType();
}
}

View File

@ -800,8 +800,8 @@ public class ComponentType extends AbstractType implements CompositeTypeImplemen
final EmbeddableRepresentationStrategy representationStrategy = embeddableTypeDescriptor().getRepresentationStrategy(); final EmbeddableRepresentationStrategy representationStrategy = embeddableTypeDescriptor().getRepresentationStrategy();
final EmbeddableInstantiator instantiator; final EmbeddableInstantiator instantiator;
if ( embeddableTypeDescriptor().isPolymorphic() ) { if ( embeddableTypeDescriptor().isPolymorphic() ) {
// the discriminator here is the composite class name because it gets converted to the domain type when extracted // the discriminator here is the composite class because it gets converted to the domain type when extracted
instantiator = representationStrategy.getInstantiatorForClass( (String) value[value.length - 1] ); instantiator = representationStrategy.getInstantiatorForClass( ( (Class<?>) value[value.length - 1] ).getName() );
} }
else { else {
instantiator = representationStrategy.getInstantiator(); instantiator = representationStrategy.getInstantiator();

View File

@ -6,6 +6,8 @@
*/ */
package org.hibernate.orm.test.inheritance.embeddable; package org.hibernate.orm.test.inheritance.embeddable;
import org.hibernate.annotations.Imported;
import jakarta.persistence.DiscriminatorValue; import jakarta.persistence.DiscriminatorValue;
import jakarta.persistence.Embeddable; import jakarta.persistence.Embeddable;

View File

@ -6,6 +6,8 @@
*/ */
package org.hibernate.orm.test.inheritance.embeddable; package org.hibernate.orm.test.inheritance.embeddable;
import org.hibernate.annotations.Imported;
import jakarta.persistence.Embeddable; import jakarta.persistence.Embeddable;
/** /**

View File

@ -106,6 +106,46 @@ public class ElementCollectionEmbeddableInheritanceTest {
} ); } );
} }
@Test
public void testType(SessionFactoryScope scope) {
scope.inTransaction( session -> {
assertThat( session.createQuery(
"select type(t.embeddables) from TestEntity t where id = 2",
Class.class
).getSingleResult() ).isEqualTo( SubChildOneEmbeddable.class );
assertThat( session.createQuery(
"select t.id from TestEntity t where type(t.embeddables) = SubChildOneEmbeddable",
Long.class
).getSingleResult() ).isEqualTo( 2L );
assertThat( session.createQuery(
"select type(e) from TestEntity t join t.embeddables e where id = 2",
Class.class
).getSingleResult() ).isEqualTo( SubChildOneEmbeddable.class );
assertThat( session.createQuery(
"select t.id from TestEntity t join t.embeddables e where type(e) = SubChildOneEmbeddable",
Long.class
).getSingleResult() ).isEqualTo( 2L );
} );
}
@Test
public void testTreat(SessionFactoryScope scope) {
scope.inTransaction( session -> {
assertThat( session.createQuery(
"select treat(e as SubChildOneEmbeddable) from TestEntity t join t.embeddables e",
SubChildOneEmbeddable.class
).getSingleResult().getSubChildOneProp() ).isEqualTo( 2.0 );
assertThat( session.createQuery(
"select t.id from TestEntity t join t.embeddables e where treat(e as SubChildOneEmbeddable).subChildOneProp = 2.0",
Long.class
).getSingleResult() ).isEqualTo( 2L );
assertThat( session.createQuery(
"select t.id from TestEntity t join treat(t.embeddables as SubChildOneEmbeddable) e where e.subChildOneProp = 2.0",
Long.class
).getSingleResult() ).isEqualTo( 2L );
} );
}
@BeforeAll @BeforeAll
public void setUp(SessionFactoryScope scope) { public void setUp(SessionFactoryScope scope) {
scope.inTransaction( session -> { scope.inTransaction( session -> {

View File

@ -0,0 +1,219 @@
/*
* 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.inheritance.embeddable;
import org.hibernate.testing.jdbc.SQLStatementInspector;
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.BeforeAll;
import org.junit.jupiter.api.Test;
import jakarta.persistence.Embedded;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import static org.assertj.core.api.Assertions.assertThat;
/**
* @author Marco Belladelli
*/
@DomainModel( annotatedClasses = {
EmbeddableTypeAndTreatTest.TestEntity.class,
SimpleEmbeddable.class,
ParentEmbeddable.class,
ChildOneEmbeddable.class,
SubChildOneEmbeddable.class,
ChildTwoEmbeddable.class,
} )
@SessionFactory( useCollectingStatementInspector = true )
public class EmbeddableTypeAndTreatTest {
@Test
public void testType(SessionFactoryScope scope) {
scope.inTransaction( session -> {
assertThat( session.createQuery(
"select type(t.embeddable) from TestEntity t where t.id = 1",
Class.class
).getSingleResult() ).isEqualTo( ChildTwoEmbeddable.class );
assertThat( session.createQuery(
"select type(e) from TestEntity t join t.embeddable e where t.id = 2",
Class.class
).getSingleResult() ).isEqualTo( SubChildOneEmbeddable.class );
assertThat( session.createQuery(
"select t.id from TestEntity t where type(t.embeddable) = SubChildOneEmbeddable",
Long.class
).getSingleResult() ).isEqualTo( 2L );
assertThat( session.createQuery(
"select t.id from TestEntity t join t.embeddable e where type(e) = ChildTwoEmbeddable",
Long.class
).getSingleResult() ).isEqualTo( 1L );
assertThat( session.createQuery(
"select t.id from TestEntity t where type(t.embeddable) = SubChildOneEmbeddable or t.id = 1",
Long.class
).getResultList() ).hasSize( 2 );
assertThat( session.createQuery(
"select t.id from TestEntity t where type(t.embeddable) = SubChildOneEmbeddable and type(t.embeddable) = ChildTwoEmbeddable",
Long.class
).getResultList() ).hasSize( 0 );
} );
}
@Test
public void testTreat(SessionFactoryScope scope) {
scope.inTransaction( session -> {
assertThat( session.createQuery(
"select treat(t.embeddable as SubChildOneEmbeddable) from TestEntity t",
SubChildOneEmbeddable.class
).getSingleResult().getSubChildOneProp() ).isEqualTo( 2.0 );
assertThat( session.createQuery(
"select treat(e as SubChildOneEmbeddable) from TestEntity t join t.embeddable e",
SubChildOneEmbeddable.class
).getSingleResult().getSubChildOneProp() ).isEqualTo( 2.0 );
assertThat( session.createQuery(
"select e from TestEntity t join treat(t.embeddable as SubChildOneEmbeddable) e",
SubChildOneEmbeddable.class
).getSingleResult().getSubChildOneProp() ).isEqualTo( 2.0 );
assertThat( session.createQuery(
"select t.id from TestEntity t where treat(t.embeddable as ChildTwoEmbeddable).childTwoProp = 1",
Long.class
).getSingleResult() ).isEqualTo( 1L );
assertThat( session.createQuery(
"select t.id from TestEntity t join t.embeddable e where treat(e as ChildTwoEmbeddable).childTwoProp = 1",
Long.class
).getSingleResult() ).isEqualTo( 1L );
assertThat( session.createQuery(
"select t.id from TestEntity t join treat(t.embeddable as ChildTwoEmbeddable) e where e.childTwoProp = 1",
Long.class
).getSingleResult() ).isEqualTo( 1L );
} );
}
@Test
public void testTreatJunctions(SessionFactoryScope scope) {
final SQLStatementInspector inspector = scope.getCollectingStatementInspector();
inspector.clear();
scope.inTransaction( session -> {
assertThat( session.createQuery(
"select t.id from TestEntity t where treat(t.embeddable as SubChildOneEmbeddable).subChildOneProp = 2.0 and id = 2",
Long.class
).getSingleResult() ).isEqualTo( 2L );
inspector.assertNumberOfOccurrenceInQueryNoSpace( 0, "embeddable_type", 1 );
inspector.clear();
assertThat( session.createQuery(
"select t.id from TestEntity t where treat(t.embeddable as SubChildOneEmbeddable).subChildOneProp = 2.0 or id = 1",
Long.class
).getResultList() ).hasSize( 2 );
inspector.assertNumberOfOccurrenceInQueryNoSpace( 0, "embeddable_type", 1 );
inspector.clear();
assertThat( session.createQuery(
"select t.id from TestEntity t where treat(t.embeddable as SubChildOneEmbeddable).subChildOneProp = 2.0 and treat(t.embeddable as SubChildOneEmbeddable).childOneProp = 2",
Long.class
).getSingleResult() ).isEqualTo( 2L );
inspector.assertNumberOfOccurrenceInQueryNoSpace( 0, "embeddable_type", 1 );
inspector.clear();
assertThat( session.createQuery(
"select t.id from TestEntity t where treat(t.embeddable as SubChildOneEmbeddable).subChildOneProp = 2.0 and id = 1",
Long.class
).getResultList() ).hasSize( 0 );
inspector.assertNumberOfOccurrenceInQueryNoSpace( 0, "embeddable_type", 1 );
inspector.clear();
assertThat( session.createQuery(
"select t.id from TestEntity t where id = 1 or treat(t.embeddable as SubChildOneEmbeddable).subChildOneProp = 2.0",
Long.class
).getResultList() ).hasSize( 2 );
inspector.assertNumberOfOccurrenceInQueryNoSpace( 0, "embeddable_type", 1 );
inspector.clear();
assertThat( session.createQuery(
"select t.id from TestEntity t where treat(t.embeddable as ChildTwoEmbeddable).childTwoProp = 1 or treat(t.embeddable as SubChildOneEmbeddable).subChildOneProp = 2.0",
Long.class
).getResultList() ).hasSize( 2 );
inspector.assertNumberOfOccurrenceInQueryNoSpace( 0, "embeddable_type", 2 );
inspector.clear();
assertThat( session.createQuery(
"select t.id from TestEntity t where treat(t.embeddable as SubChildOneEmbeddable).childOneProp = 2 or treat(t.embeddable as SubChildOneEmbeddable).subChildOneProp = 2.0",
Long.class
).getSingleResult() ).isEqualTo( 2L );
inspector.assertNumberOfOccurrenceInQueryNoSpace( 0, "embeddable_type", 1 );
inspector.clear();
} );
}
@Test
public void testNonInheritedEmbeddable(SessionFactoryScope scope) {
scope.inTransaction( session -> {
assertThat( session.createQuery(
"select type(t.simpleEmbeddable) from TestEntity t where t.id = 1",
Class.class
).getSingleResult() ).isEqualTo( SimpleEmbeddable.class );
assertThat( session.createQuery(
"select t.id from TestEntity t where type(t.simpleEmbeddable) = SimpleEmbeddable",
Long.class
).getResultList() ).hasSize( 3 );
assertThat( session.createQuery(
"select treat(t.simpleEmbeddable as SimpleEmbeddable) from TestEntity t where t.simpleEmbeddable is not null",
SimpleEmbeddable.class
).getSingleResult().getData() ).isEqualTo( "simple_embeddable_1" );
} );
}
@BeforeAll
public void setUp(SessionFactoryScope scope) {
scope.inTransaction( session -> {
final TestEntity testEntity = new TestEntity( 1L, new ChildTwoEmbeddable( "embeddable_1", 1L ) );
testEntity.setSimpleEmbeddable( new SimpleEmbeddable( "simple_embeddable_1" ) );
session.persist( testEntity );
session.persist( new TestEntity( 2L, new SubChildOneEmbeddable( "embeddable_2", 2, 2.0 ) ) );
session.persist( new TestEntity( 3L, new ChildOneEmbeddable( "embeddable_3", 3 ) ) );
} );
}
@AfterAll
public void tearDown(SessionFactoryScope scope) {
scope.inTransaction( session -> session.createMutationQuery( "delete from TestEntity" ).executeUpdate() );
}
@Entity( name = "TestEntity" )
static class TestEntity {
@Id
private Long id;
@Embedded
private ParentEmbeddable embeddable;
@Embedded
private SimpleEmbeddable simpleEmbeddable;
public TestEntity() {
}
public TestEntity(Long id, ParentEmbeddable embeddable) {
this.id = id;
this.embeddable = embeddable;
}
public Long getId() {
return id;
}
public ParentEmbeddable getEmbeddable() {
return embeddable;
}
public void setEmbeddable(ParentEmbeddable embeddable) {
this.embeddable = embeddable;
}
public SimpleEmbeddable getSimpleEmbeddable() {
return simpleEmbeddable;
}
public void setSimpleEmbeddable(SimpleEmbeddable simpleEmbeddable) {
this.simpleEmbeddable = simpleEmbeddable;
}
}
}

View File

@ -0,0 +1,30 @@
/*
* 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.inheritance.embeddable;
import org.hibernate.annotations.Imported;
import jakarta.persistence.Embeddable;
/**
* @author Marco Belladelli
*/
@Embeddable
public class SimpleEmbeddable {
private String data;
public SimpleEmbeddable() {
}
public SimpleEmbeddable(String data) {
this.data = data;
}
public String getData() {
return data;
}
}

View File

@ -6,6 +6,8 @@
*/ */
package org.hibernate.orm.test.inheritance.embeddable; package org.hibernate.orm.test.inheritance.embeddable;
import org.hibernate.annotations.Imported;
import jakarta.persistence.DiscriminatorValue; import jakarta.persistence.DiscriminatorValue;
import jakarta.persistence.Embeddable; import jakarta.persistence.Embeddable;

View File

@ -26,6 +26,7 @@ public class MetadataCopyingTest {
existingInstance.getEntityBindingMap(), existingInstance.getEntityBindingMap(),
existingInstance.getComposites(), existingInstance.getComposites(),
existingInstance.getGenericComponentsMap(), existingInstance.getGenericComponentsMap(),
existingInstance.getEmbeddableDiscriminatorTypesMap(),
existingInstance.getMappedSuperclassMap(), existingInstance.getMappedSuperclassMap(),
existingInstance.getCollectionBindingMap(), existingInstance.getCollectionBindingMap(),
existingInstance.getTypeDefinitionMap(), existingInstance.getTypeDefinitionMap(),

View File

@ -57,7 +57,6 @@ Support for `array_contains()` to accept an array as element argument is depreca
To check if an array is a subset of another array, use the `array_includes()` function, To check if an array is a subset of another array, use the `array_includes()` function,
or the new `INCLUDES` predicate i.e. `array INCLUDES subarray`. or the new `INCLUDES` predicate i.e. `array INCLUDES subarray`.
[[merge-versioned-deleted]] [[merge-versioned-deleted]]
=== Merge versioned entity when row is deleted === Merge versioned entity when row is deleted
Previously, merging a detached entity resulted in a SQL `insert` whenever there was no matching row in the database (for example, if the object had been deleted in another transaction). Previously, merging a detached entity resulted in a SQL `insert` whenever there was no matching row in the database (for example, if the object had been deleted in another transaction).
@ -70,3 +69,11 @@ For this determination to be possible, the entity must have either:
- a non-primitive `@Version` field. - a non-primitive `@Version` field.
For entities which have neither, it's impossible to distinguish a new instance from a deleted detached instance, and there is no change from the previous behavior. For entities which have neither, it's impossible to distinguish a new instance from a deleted detached instance, and there is no change from the previous behavior.
[[embeddable-treated-paths]]
== Changes to the `SqmTreatedPath` interface
ORM 6.6 introduced support for `@Embeddable` type inheritance.
With it, we also enabled the `type()` and `treat()` functions to work with embeddable-typed paths.
As a consequence, the `SqmTreatedPath#getTreatTarget()` method will now return a generic `ManagedDomainType` object,
which could in turn be an `EntityDomainType` (as it was before) or also an `EmbeddableDomainType` instance.

View File

@ -58,6 +58,7 @@ import org.hibernate.metamodel.internal.MetadataContext;
import org.hibernate.metamodel.internal.RuntimeMetamodelsImpl; import org.hibernate.metamodel.internal.RuntimeMetamodelsImpl;
import org.hibernate.metamodel.mapping.JdbcMapping; import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.model.domain.DomainType; import org.hibernate.metamodel.model.domain.DomainType;
import org.hibernate.metamodel.model.domain.EmbeddableDomainType;
import org.hibernate.metamodel.model.domain.EntityDomainType; import org.hibernate.metamodel.model.domain.EntityDomainType;
import org.hibernate.metamodel.model.domain.ManagedDomainType; import org.hibernate.metamodel.model.domain.ManagedDomainType;
import org.hibernate.metamodel.model.domain.PersistentAttribute; import org.hibernate.metamodel.model.domain.PersistentAttribute;
@ -201,6 +202,7 @@ public abstract class MockSessionFactory
emptyMap(), emptyMap(),
emptyMap(), emptyMap(),
emptyMap(), emptyMap(),
emptyMap(),
new Database(this, MockJdbcServicesInitiator.jdbcServices.getJdbcEnvironment()), new Database(this, MockJdbcServicesInitiator.jdbcServices.getJdbcEnvironment()),
this this
); );