HHH-18125 Support for `type()` and `treat()` operators for Embeddables
This commit is contained in:
parent
11384ab917
commit
2e9acf1ded
|
@ -543,8 +543,8 @@ The following special functions make it possible to discover or narrow expressio
|
|||
|===
|
||||
| Special function | Purpose | Signature | JPA standard
|
||||
|
||||
| `type()` | The (concrete) entity type | `type(e)` | ✔
|
||||
| `treat()` | Narrow an entity type | `treat(e as Entity)` | ✔
|
||||
| `type()` | The (concrete) entity or embeddable type | `type(e)` | ✔
|
||||
| `treat()` | Narrow an entity or embeddable type | `treat(e as Entity)` | ✔
|
||||
| `cast()` | Narrow a basic type | `cast(x as Type)` | ✖
|
||||
| `str()` | Cast to a string | `str(x)` | ✖
|
||||
|===
|
||||
|
@ -555,7 +555,7 @@ Let's see what these functions do.
|
|||
[discrete]
|
||||
===== 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.
|
||||
|
||||
[[entity-type-exp-example]]
|
||||
|
@ -571,7 +571,7 @@ where type(payment) = CreditCardPayment
|
|||
===== Narrowing an entity type
|
||||
|
||||
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]]
|
||||
[source, hql]
|
||||
|
|
|
@ -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
|
||||
(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);
|
||||
* 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
|
||||
classes with `@DiscriminatorValue`.
|
||||
|
@ -407,6 +407,8 @@ Embeddable inheritance is *NOT* supported for `@EmbeddedId`, embeddable types us
|
|||
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]]
|
||||
.Example mapping of an embeddable inheritance hierarchy
|
||||
[source,java]
|
||||
|
|
|
@ -750,8 +750,8 @@ The following special functions make it possible to discover or narrow expressio
|
|||
|===
|
||||
| Special function | Purpose | Signature | JPA standard
|
||||
|
||||
| `type()` | The (concrete) entity name | `type(e)` | ✓
|
||||
| `treat()` | Narrow an entity type | `treat(e as Entity)` | ✓
|
||||
| `type()` | The (concrete) entity or embeddable type | `type(e)` | ✓
|
||||
| `treat()` | Narrow an entity or embeddable type | `treat(e as Entity)` | ✓
|
||||
| `cast()` | Narrow a basic type | `cast(x as Type)` | ✗
|
||||
| `str()` | Cast to a string | `str(x)` | ✗
|
||||
|===
|
||||
|
@ -761,7 +761,7 @@ Let's see what these functions do.
|
|||
[[hql-function-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.
|
||||
|
||||
[[hql-entity-type-exp-example]]
|
||||
|
@ -777,7 +777,7 @@ include::{example-dir-hql}/HQLTest.java[tags=hql-entity-type-exp-example]
|
|||
===== `treat()`
|
||||
|
||||
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]]
|
||||
====
|
||||
|
|
|
@ -18,6 +18,7 @@ import java.util.UUID;
|
|||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.hibernate.AssertionFailure;
|
||||
import org.hibernate.DuplicateMappingException;
|
||||
|
@ -95,6 +96,7 @@ import org.hibernate.mapping.RootClass;
|
|||
import org.hibernate.mapping.SimpleValue;
|
||||
import org.hibernate.mapping.Table;
|
||||
import org.hibernate.metamodel.CollectionClassification;
|
||||
import org.hibernate.metamodel.mapping.DiscriminatorType;
|
||||
import org.hibernate.metamodel.spi.EmbeddableInstantiator;
|
||||
import org.hibernate.query.named.NamedObjectRepository;
|
||||
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 Map<Class<?>, Component> genericComponentsMap = 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, FilterDefinition> filterDefinitionMap = new HashMap<>();
|
||||
|
@ -296,6 +299,13 @@ public class InFlightMetadataCollectorImpl implements InFlightMetadataCollector,
|
|||
return subclasses != null ? subclasses : List.of();
|
||||
}
|
||||
|
||||
@Override
|
||||
public DiscriminatorType<?> resolveEmbeddableDiscriminatorType(
|
||||
Class<?> embeddableClass,
|
||||
Supplier<DiscriminatorType<?>> supplier) {
|
||||
return embeddableDiscriminatorTypesMap.computeIfAbsent( embeddableClass, k -> supplier.get() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public SessionFactoryBuilder getSessionFactoryBuilder() {
|
||||
throw new UnsupportedOperationException(
|
||||
|
@ -2072,6 +2082,7 @@ public class InFlightMetadataCollectorImpl implements InFlightMetadataCollector,
|
|||
entityBindingMap,
|
||||
composites,
|
||||
genericComponentsMap,
|
||||
embeddableDiscriminatorTypesMap,
|
||||
mappedSuperClasses,
|
||||
collectionBindingMap,
|
||||
typeDefRegistry.copyRegistrationMap(),
|
||||
|
|
|
@ -16,6 +16,7 @@ import java.util.Map;
|
|||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.hibernate.HibernateException;
|
||||
|
@ -60,6 +61,7 @@ import org.hibernate.mapping.Property;
|
|||
import org.hibernate.mapping.Table;
|
||||
import org.hibernate.mapping.UserDefinedObjectType;
|
||||
import org.hibernate.mapping.UserDefinedType;
|
||||
import org.hibernate.metamodel.mapping.DiscriminatorType;
|
||||
import org.hibernate.procedure.spi.NamedCallableQueryMemento;
|
||||
import org.hibernate.query.internal.NamedObjectRepositoryImpl;
|
||||
import org.hibernate.query.named.NamedObjectRepository;
|
||||
|
@ -91,6 +93,7 @@ public class MetadataImpl implements MetadataImplementor, Serializable {
|
|||
private final Map<String,PersistentClass> entityBindingMap;
|
||||
private final List<Component> composites;
|
||||
private final Map<Class<?>, Component> genericComponentsMap;
|
||||
private final Map<Class<?>, DiscriminatorType<?>> embeddableDiscriminatorTypesMap;
|
||||
private final Map<Class<?>, MappedSuperclass> mappedSuperclassMap;
|
||||
private final Map<String,Collection> collectionBindingMap;
|
||||
private final Map<String, TypeDefinition> typeDefinitionMap;
|
||||
|
@ -112,6 +115,7 @@ public class MetadataImpl implements MetadataImplementor, Serializable {
|
|||
Map<String, PersistentClass> entityBindingMap,
|
||||
List<Component> composites,
|
||||
Map<Class<?>, Component> genericComponentsMap,
|
||||
Map<Class<?>, DiscriminatorType<?>> embeddableDiscriminatorTypesMap,
|
||||
Map<Class<?>, MappedSuperclass> mappedSuperclassMap,
|
||||
Map<String, Collection> collectionBindingMap,
|
||||
Map<String, TypeDefinition> typeDefinitionMap,
|
||||
|
@ -132,6 +136,7 @@ public class MetadataImpl implements MetadataImplementor, Serializable {
|
|||
this.entityBindingMap = entityBindingMap;
|
||||
this.composites = composites;
|
||||
this.genericComponentsMap = genericComponentsMap;
|
||||
this.embeddableDiscriminatorTypesMap = embeddableDiscriminatorTypesMap;
|
||||
this.mappedSuperclassMap = mappedSuperclassMap;
|
||||
this.collectionBindingMap = collectionBindingMap;
|
||||
this.typeDefinitionMap = typeDefinitionMap;
|
||||
|
@ -569,6 +574,13 @@ public class MetadataImpl implements MetadataImplementor, Serializable {
|
|||
return genericComponentsMap.get( componentClass );
|
||||
}
|
||||
|
||||
@Override
|
||||
public DiscriminatorType<?> resolveEmbeddableDiscriminatorType(
|
||||
Class<?> embeddableClass,
|
||||
Supplier<DiscriminatorType<?>> supplier) {
|
||||
return embeddableDiscriminatorTypesMap.computeIfAbsent( embeddableClass, k -> supplier.get() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public org.hibernate.type.Type getIdentifierType(String entityName) throws MappingException {
|
||||
final PersistentClass pc = entityBindingMap.get( entityName );
|
||||
|
@ -664,4 +676,7 @@ public class MetadataImpl implements MetadataImplementor, Serializable {
|
|||
return genericComponentsMap;
|
||||
}
|
||||
|
||||
public Map<Class<?>, DiscriminatorType<?>> getEmbeddableDiscriminatorTypesMap() {
|
||||
return embeddableDiscriminatorTypesMap;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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.getSuperclassInheritanceState;
|
||||
import static org.hibernate.internal.CoreLogging.messageLogger;
|
||||
import static org.hibernate.internal.util.StringHelper.unqualify;
|
||||
import static org.hibernate.mapping.MetadataSource.ANNOTATIONS;
|
||||
|
||||
/**
|
||||
|
@ -404,7 +405,7 @@ public final class AnnotationBinder {
|
|||
private static void handleImport(XClass annotatedClass, MetadataBuildingContext context) {
|
||||
if ( annotatedClass.isAnnotationPresent( Imported.class ) ) {
|
||||
String qualifiedName = annotatedClass.getName();
|
||||
String name = StringHelper.unqualify( qualifiedName );
|
||||
String name = unqualify( qualifiedName );
|
||||
String rename = annotatedClass.getAnnotation( Imported.class ).rename();
|
||||
context.getMetadataCollector().addImport( rename.isEmpty() ? name : rename, qualifiedName );
|
||||
}
|
||||
|
@ -693,6 +694,11 @@ public final class AnnotationBinder {
|
|||
getSuperclassInheritanceState( clazz, inheritanceStatePerClass );
|
||||
final InheritanceState state =
|
||||
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 ) {
|
||||
//the classes are ordered thus preventing an NPE
|
||||
superclassState.setHasSiblings( true );
|
||||
|
@ -700,7 +706,7 @@ public final class AnnotationBinder {
|
|||
getInheritanceStateOfSuperEntity( clazz, inheritanceStatePerClass );
|
||||
if ( superEntityState != null ) {
|
||||
state.setHasParents( true );
|
||||
if ( buildingContext.getMetadataCollector().getClassType( clazz ) == EMBEDDABLE ) {
|
||||
if ( classType == EMBEDDABLE ) {
|
||||
buildingContext.getMetadataCollector().registerEmbeddableSubclass(
|
||||
superEntityState.getClazz(),
|
||||
clazz
|
||||
|
@ -712,7 +718,7 @@ public final class AnnotationBinder {
|
|||
state.setType( superclassState.getType() );
|
||||
}
|
||||
}
|
||||
switch ( buildingContext.getMetadataCollector().getClassType( clazz ) ) {
|
||||
switch ( classType ) {
|
||||
case ENTITY:
|
||||
case MAPPED_SUPERCLASS:
|
||||
case EMBEDDABLE:
|
||||
|
|
|
@ -11,6 +11,7 @@ import java.util.Map;
|
|||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.hibernate.MappingException;
|
||||
import org.hibernate.SessionFactory;
|
||||
|
@ -30,6 +31,7 @@ import org.hibernate.mapping.FetchProfile;
|
|||
import org.hibernate.mapping.MappedSuperclass;
|
||||
import org.hibernate.mapping.PersistentClass;
|
||||
import org.hibernate.mapping.Table;
|
||||
import org.hibernate.metamodel.mapping.DiscriminatorType;
|
||||
import org.hibernate.query.named.NamedObjectRepository;
|
||||
import org.hibernate.query.sqm.function.SqmFunctionDescriptor;
|
||||
import org.hibernate.query.sqm.function.SqmFunctionRegistry;
|
||||
|
@ -249,6 +251,13 @@ public abstract class AbstractDelegatingMetadata implements MetadataImplementor
|
|||
return delegate().getGenericComponent( componentClass );
|
||||
}
|
||||
|
||||
@Override
|
||||
public DiscriminatorType<?> resolveEmbeddableDiscriminatorType(
|
||||
Class<?> embeddableClass,
|
||||
Supplier<DiscriminatorType<?>> supplier) {
|
||||
return delegate().resolveEmbeddableDiscriminatorType( embeddableClass, supplier );
|
||||
}
|
||||
|
||||
@Override
|
||||
public NamedObjectRepository buildNamedQueryRepository(SessionFactoryImplementor sessionFactory) {
|
||||
return delegate().buildNamedQueryRepository( sessionFactory );
|
||||
|
|
|
@ -8,6 +8,7 @@ package org.hibernate.boot.spi;
|
|||
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import org.hibernate.Incubating;
|
||||
import org.hibernate.MappingException;
|
||||
|
@ -15,6 +16,7 @@ import org.hibernate.boot.Metadata;
|
|||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.mapping.Component;
|
||||
import org.hibernate.mapping.MappedSuperclass;
|
||||
import org.hibernate.metamodel.mapping.DiscriminatorType;
|
||||
import org.hibernate.query.named.NamedObjectRepository;
|
||||
import org.hibernate.query.sqm.function.SqmFunctionRegistry;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
|
@ -58,4 +60,6 @@ public interface MetadataImplementor extends Metadata {
|
|||
void visitRegisteredComponents(Consumer<Component> consumer);
|
||||
|
||||
Component getGenericComponent(Class<?> componentClass);
|
||||
|
||||
DiscriminatorType<?> resolveEmbeddableDiscriminatorType(Class<?> embeddableClass, Supplier<DiscriminatorType<?>> supplier);
|
||||
}
|
||||
|
|
|
@ -136,8 +136,8 @@ public class StructHelper {
|
|||
instantiator = representationStrategy.getInstantiator();
|
||||
}
|
||||
else {
|
||||
// the discriminator here is the composite class name because it gets converted to the domain type when extracted
|
||||
instantiator = representationStrategy.getInstantiatorForClass( (String) attributeValues.getDiscriminator() );
|
||||
// the discriminator here is the composite class because it gets converted to the domain type when extracted
|
||||
instantiator = representationStrategy.getInstantiatorForClass( ( (Class<?>) attributeValues.getDiscriminator() ).getName() );
|
||||
}
|
||||
return instantiator.instantiate( attributeValues, sessionFactory );
|
||||
}
|
||||
|
|
|
@ -35,6 +35,7 @@ import org.hibernate.metamodel.UnsupportedMappingException;
|
|||
import org.hibernate.metamodel.ValueClassification;
|
||||
import org.hibernate.metamodel.mapping.AttributeMapping;
|
||||
import org.hibernate.metamodel.mapping.CompositeIdentifierMapping;
|
||||
import org.hibernate.metamodel.mapping.DiscriminatorType;
|
||||
import org.hibernate.metamodel.mapping.EmbeddableMappingType;
|
||||
import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart;
|
||||
import org.hibernate.metamodel.mapping.EntityIdentifierMapping;
|
||||
|
@ -268,7 +269,7 @@ public class AttributeFactory {
|
|||
false,
|
||||
context.getJpaMetamodel()
|
||||
);
|
||||
context.registerEmbeddableType( embeddableType, component);
|
||||
context.registerEmbeddableType( embeddableType, component );
|
||||
|
||||
if ( component.isPolymorphic() ) {
|
||||
final java.util.Collection<String> embeddableSubclasses = component.getDiscriminatorValues().values();
|
||||
|
@ -283,12 +284,14 @@ public class AttributeFactory {
|
|||
continue;
|
||||
}
|
||||
final Class<?> subclass = cls.classForName( subclassName );
|
||||
context.registerEmbeddableType( new EmbeddableTypeImpl<>(
|
||||
final EmbeddableTypeImpl<?> subType = new EmbeddableTypeImpl<>(
|
||||
context.getJavaTypeRegistry().resolveManagedTypeDescriptor( subclass ),
|
||||
domainTypes.get( component.getSuperclass( subclassName ) ),
|
||||
false,
|
||||
context.getJpaMetamodel()
|
||||
), component );
|
||||
);
|
||||
domainTypes.put( subclassName, subType );
|
||||
context.registerEmbeddableType( subType, component );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
package org.hibernate.metamodel.internal;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Locale;
|
||||
|
|
|
@ -47,7 +47,7 @@ public class DefaultDiscriminatorConverter<O,R> extends DiscriminatorConverter<O
|
|||
JavaType<O> domainJavaType,
|
||||
JavaType<R> relationalJavaType,
|
||||
MappingMetamodelImplementor mappingMetamodel) {
|
||||
super( discriminatorRole, domainJavaType, relationalJavaType );
|
||||
super( discriminatorRole.getFullPath(), domainJavaType, relationalJavaType );
|
||||
this.mappingMetamodel = mappingMetamodel;
|
||||
}
|
||||
|
||||
|
|
|
@ -7,7 +7,6 @@
|
|||
package org.hibernate.metamodel.mapping;
|
||||
|
||||
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.java.JavaType;
|
||||
|
||||
|
@ -20,21 +19,21 @@ import java.util.function.Function;
|
|||
*/
|
||||
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<R> relationalJavaType;
|
||||
|
||||
public DiscriminatorConverter(
|
||||
NavigableRole discriminatorRole,
|
||||
String discriminatorName,
|
||||
JavaType<O> domainJavaType,
|
||||
JavaType<R> relationalJavaType) {
|
||||
this.discriminatorRole = discriminatorRole;
|
||||
this.discriminatorName = discriminatorName;
|
||||
this.domainJavaType = domainJavaType;
|
||||
this.relationalJavaType = relationalJavaType;
|
||||
}
|
||||
|
||||
public NavigableRole getNavigableRole() {
|
||||
return discriminatorRole;
|
||||
public String getDiscriminatorName() {
|
||||
return discriminatorName;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -95,7 +94,7 @@ public abstract class DiscriminatorConverter<O,R> implements BasicValueConverter
|
|||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "DiscriminatorConverter(" + discriminatorRole.getFullPath() + ")";
|
||||
return "DiscriminatorConverter(" + discriminatorName + ")";
|
||||
}
|
||||
|
||||
public abstract void forEachValueDetail(Consumer<DiscriminatorValueDetails> consumer);
|
||||
|
|
|
@ -15,6 +15,8 @@ import java.util.function.Function;
|
|||
|
||||
import org.hibernate.AssertionFailure;
|
||||
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.model.domain.NavigableRole;
|
||||
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 static <O, R> EmbeddableDiscriminatorConverter<O, R> fromValueMappings(
|
||||
NavigableRole role,
|
||||
String discriminatedType,
|
||||
JavaType<O> domainJavaType,
|
||||
BasicType<R> underlyingJdbcMapping,
|
||||
Map<Object, String> valueMappings) {
|
||||
final List<DiscriminatorValueDetails> valueDetailsList = new ArrayList<>( valueMappings.size() );
|
||||
Map<Object, String> valueMappings,
|
||||
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(
|
||||
value,
|
||||
embeddableClassName
|
||||
cls.classForName( embeddableClassName )
|
||||
) ) );
|
||||
return new EmbeddableDiscriminatorConverter<>(
|
||||
role,
|
||||
discriminatedType,
|
||||
domainJavaType,
|
||||
underlyingJdbcMapping.getJavaTypeDescriptor(),
|
||||
valueDetailsList
|
||||
);
|
||||
}
|
||||
|
||||
private final Map<Object, DiscriminatorValueDetails> discriminatorValueToDetailsMap;
|
||||
private final Map<String, DiscriminatorValueDetails> embeddableClassNameToDetailsMap;
|
||||
private final Map<Object, EmbeddableDiscriminatorValueDetailsImpl> discriminatorValueToDetailsMap;
|
||||
private final Map<String, EmbeddableDiscriminatorValueDetailsImpl> embeddableClassNameToDetailsMap;
|
||||
|
||||
public EmbeddableDiscriminatorConverter(
|
||||
NavigableRole discriminatorRole,
|
||||
String discriminatorName,
|
||||
JavaType<O> domainJavaType,
|
||||
JavaType<R> relationalJavaType,
|
||||
List<DiscriminatorValueDetails> valueMappings) {
|
||||
super( discriminatorRole, domainJavaType, relationalJavaType );
|
||||
List<EmbeddableDiscriminatorValueDetailsImpl> valueMappings) {
|
||||
super( discriminatorName, domainJavaType, relationalJavaType );
|
||||
|
||||
this.discriminatorValueToDetailsMap = 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) {
|
||||
assert relationalForm == null || getRelationalJavaType().isInstance( relationalForm );
|
||||
|
||||
final DiscriminatorValueDetails matchingValueDetails = getDetailsForDiscriminatorValue( relationalForm );
|
||||
final EmbeddableDiscriminatorValueDetailsImpl matchingValueDetails = getDetailsForDiscriminatorValue( relationalForm );
|
||||
if ( matchingValueDetails == null ) {
|
||||
throw new IllegalStateException( "Could not resolve discriminator value" );
|
||||
}
|
||||
|
||||
//noinspection unchecked
|
||||
return (O) matchingValueDetails.getIndicatedEntityName();
|
||||
return (O) matchingValueDetails.getEmbeddableClass();
|
||||
}
|
||||
|
||||
@Override
|
||||
public R toRelationalValue(O domainForm) {
|
||||
assert domainForm == null || domainForm instanceof String;
|
||||
|
||||
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 );
|
||||
public EmbeddableDiscriminatorValueDetailsImpl getDetailsForDiscriminatorValue(Object value) {
|
||||
final EmbeddableDiscriminatorValueDetailsImpl valueMatch = discriminatorValueToDetailsMap.get( value );
|
||||
if ( valueMatch != null ) {
|
||||
return valueMatch;
|
||||
}
|
||||
|
|
|
@ -72,7 +72,7 @@ public class MappedDiscriminatorConverter<O,R> extends DiscriminatorConverter<O,
|
|||
JavaType<O> domainJavaType,
|
||||
JavaType<R> relationalJavaType,
|
||||
List<DiscriminatorValueDetails> valueMappings) {
|
||||
super( discriminatorRole, domainJavaType, relationalJavaType );
|
||||
super( discriminatorRole.getFullPath(), domainJavaType, relationalJavaType );
|
||||
|
||||
this.discriminatorValueToEntityNameMap = CollectionHelper.concurrentMap( valueMappings.size() );
|
||||
this.entityNameToDiscriminatorValueMap = CollectionHelper.concurrentMap( valueMappings.size() );
|
||||
|
|
|
@ -27,8 +27,8 @@ public class DiscriminatorTypeImpl<O> extends ConvertedBasicTypeImpl<O> implemen
|
|||
BasicType<?> underlyingJdbcMapping,
|
||||
DiscriminatorConverter<O,?> discriminatorValueConverter) {
|
||||
super(
|
||||
discriminatorValueConverter.getNavigableRole().getFullPath(),
|
||||
"Discriminator type " + discriminatorValueConverter.getNavigableRole().getFullPath(),
|
||||
discriminatorValueConverter.getDiscriminatorName(),
|
||||
"Discriminator type " + discriminatorValueConverter.getDiscriminatorName(),
|
||||
underlyingJdbcMapping.getJdbcType(),
|
||||
discriminatorValueConverter
|
||||
);
|
||||
|
|
|
@ -20,11 +20,15 @@ import org.hibernate.metamodel.mapping.EntityMappingType;
|
|||
*/
|
||||
public class EmbeddableDiscriminatorValueDetailsImpl implements DiscriminatorValueDetails {
|
||||
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.embeddableClassName = embeddableClassName;
|
||||
this.embeddableClass = embeddableClass;
|
||||
}
|
||||
|
||||
public Class<?> getEmbeddableClass() {
|
||||
return embeddableClass;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -34,7 +38,7 @@ public class EmbeddableDiscriminatorValueDetailsImpl implements DiscriminatorVal
|
|||
|
||||
@Override
|
||||
public String getIndicatedEntityName() {
|
||||
return embeddableClassName;
|
||||
return embeddableClass.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -16,7 +16,6 @@ import java.util.function.Function;
|
|||
|
||||
import org.hibernate.MappingException;
|
||||
import org.hibernate.SharedSessionContract;
|
||||
import org.hibernate.WrongClassException;
|
||||
import org.hibernate.cfg.Environment;
|
||||
import org.hibernate.dialect.Dialect;
|
||||
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.EntityMappingType;
|
||||
import org.hibernate.metamodel.mapping.JdbcMapping;
|
||||
import org.hibernate.metamodel.mapping.ModelPart;
|
||||
import org.hibernate.metamodel.mapping.SelectableConsumer;
|
||||
import org.hibernate.metamodel.mapping.SelectableMapping;
|
||||
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.spi.EmbeddableRepresentationStrategy;
|
||||
import org.hibernate.metamodel.spi.RuntimeModelCreationContext;
|
||||
import org.hibernate.persister.entity.DiscriminatorHelper;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
import org.hibernate.property.access.spi.Getter;
|
||||
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.TypeConfiguration;
|
||||
|
||||
import static org.hibernate.internal.util.StringHelper.qualify;
|
||||
import static org.hibernate.persister.entity.DiscriminatorHelper.getDiscriminatorType;
|
||||
|
||||
import static org.hibernate.type.SqlTypes.JSON;
|
||||
|
@ -736,9 +736,12 @@ public class EmbeddableMappingTypeImpl extends AbstractEmbeddableMapping impleme
|
|||
scale = column.getScale();
|
||||
}
|
||||
|
||||
final DiscriminatorType<?> discriminatorType = buildDiscriminatorType(
|
||||
bootDescriptor,
|
||||
creationContext
|
||||
final DiscriminatorType<?> discriminatorType = creationContext.getMetadata().resolveEmbeddableDiscriminatorType(
|
||||
bootDescriptor.getComponentClass(),
|
||||
() -> buildDiscriminatorType(
|
||||
bootDescriptor,
|
||||
creationContext
|
||||
)
|
||||
);
|
||||
|
||||
return new ExplicitColumnDiscriminatorMappingImpl(
|
||||
|
@ -758,17 +761,18 @@ public class EmbeddableMappingTypeImpl extends AbstractEmbeddableMapping impleme
|
|||
);
|
||||
}
|
||||
|
||||
private DiscriminatorType<?> buildDiscriminatorType(
|
||||
private static DiscriminatorType<?> buildDiscriminatorType(
|
||||
Component bootDescriptor,
|
||||
RuntimeModelCreationContext creationContext) {
|
||||
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 DiscriminatorConverter<String, ?> converter = EmbeddableDiscriminatorConverter.fromValueMappings(
|
||||
getNavigableRole().append( EntityDiscriminatorMapping.DISCRIMINATOR_ROLE_NAME ),
|
||||
qualify( bootDescriptor.getComponentClassName(), EntityDiscriminatorMapping.DISCRIMINATOR_ROLE_NAME ),
|
||||
domainJavaType,
|
||||
discriminatorType,
|
||||
bootDescriptor.getDiscriminatorValues()
|
||||
bootDescriptor.getDiscriminatorValues(),
|
||||
creationContext.getSessionFactory()
|
||||
);
|
||||
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
|
||||
public <X, Y> int breakDownJdbcValues(
|
||||
Object domainValue,
|
||||
|
|
|
@ -6,8 +6,10 @@
|
|||
*/
|
||||
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.SqmPathSource;
|
||||
|
||||
import jakarta.persistence.metamodel.EmbeddableType;
|
||||
|
||||
|
@ -20,5 +22,16 @@ import jakarta.persistence.metamodel.EmbeddableType;
|
|||
* @author Steve Ebersole
|
||||
*/
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -17,14 +17,14 @@ import org.hibernate.query.sqm.SqmPathSource;
|
|||
*
|
||||
* @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();
|
||||
|
||||
@Override
|
||||
Collection<? extends EntityDomainType<? extends J>> getSubTypes();
|
||||
|
||||
@Override
|
||||
default DomainType<J> getSqmType() {
|
||||
default EntityDomainType<J> getSqmType() {
|
||||
return this;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -47,11 +47,21 @@ public interface JpaMetamodel extends Metamodel {
|
|||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// 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
|
||||
*/
|
||||
<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
|
||||
* an HQL query
|
||||
|
|
|
@ -37,9 +37,6 @@ public interface ManagedDomainType<J> extends SqmExpressible<J>, DomainType<J>,
|
|||
|
||||
/**
|
||||
* The descriptor of the supertype of this type.
|
||||
*
|
||||
* @apiNote we define this here in anticipation of eventually supporting
|
||||
* embeddable inheritance
|
||||
*/
|
||||
ManagedDomainType<? super J> getSuperType();
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -7,12 +7,17 @@
|
|||
package org.hibernate.metamodel.model.domain.internal;
|
||||
|
||||
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.DomainType;
|
||||
import org.hibernate.metamodel.model.domain.EmbeddableDomainType;
|
||||
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.query.sqm.SqmPathSource;
|
||||
import org.hibernate.query.sqm.tree.domain.SqmPath;
|
||||
import org.hibernate.type.descriptor.java.JavaType;
|
||||
|
||||
import jakarta.persistence.metamodel.SingularAttribute;
|
||||
|
@ -56,4 +61,40 @@ public class EmbeddableTypeImpl<J>
|
|||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
}
|
|
@ -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()
|
||||
);
|
||||
}
|
||||
}
|
|
@ -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.SqmPath;
|
||||
|
||||
import static org.hibernate.metamodel.mapping.EntityDiscriminatorMapping.DISCRIMINATOR_ROLE_NAME;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
|
@ -21,6 +23,7 @@ public class EmbeddedSqmPathSource<J>
|
|||
extends AbstractSqmPathSource<J>
|
||||
implements CompositeSqmPathSource<J> {
|
||||
private final boolean isGeneric;
|
||||
private final EmbeddedDiscriminatorSqmPathSource<?> discriminatorPathSource;
|
||||
|
||||
public EmbeddedSqmPathSource(
|
||||
String localPathName,
|
||||
|
@ -30,6 +33,12 @@ public class EmbeddedSqmPathSource<J>
|
|||
boolean isGeneric) {
|
||||
super( localPathName, pathModel, domainType, jpaBindableType );
|
||||
this.isGeneric = isGeneric;
|
||||
if ( domainType.isPolymorphic() ) {
|
||||
discriminatorPathSource = new EmbeddedDiscriminatorSqmPathSource<>( domainType );
|
||||
}
|
||||
else {
|
||||
discriminatorPathSource = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -38,18 +47,17 @@ public class EmbeddedSqmPathSource<J>
|
|||
}
|
||||
|
||||
@Override
|
||||
public SqmPathSource<?> findSubPathSource(String name, JpaMetamodelImplementor metamodel) {
|
||||
final PersistentAttribute<? super J, ?> attribute = getSqmPathType().findAttribute( name );
|
||||
if ( attribute != null ) {
|
||||
return (SqmPathSource<?>) attribute;
|
||||
public SqmPathSource<?> findSubPathSource(String name) {
|
||||
final SqmPathSource<?> subPathSource = getSqmPathType().findSubPathSource( name );
|
||||
if ( subPathSource != null ) {
|
||||
return subPathSource;
|
||||
}
|
||||
|
||||
return (SqmPathSource<?>) getSqmPathType().findSubTypesAttribute( name );
|
||||
}
|
||||
if ( name.equals( DISCRIMINATOR_ROLE_NAME ) && discriminatorPathSource != null ) {
|
||||
return discriminatorPathSource;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SqmPathSource<?> findSubPathSource(String name) {
|
||||
return (SqmPathSource<?>) getSqmPathType().findAttribute( name );
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -49,8 +49,8 @@ public class EntityDiscriminatorSqmPath<T> extends AbstractSqmPath<T> implements
|
|||
}
|
||||
|
||||
@Override
|
||||
public DiscriminatorSqmPathSource getExpressible() {
|
||||
return (DiscriminatorSqmPathSource) getNodeType();
|
||||
public EntityDiscriminatorSqmPathSource getExpressible() {
|
||||
return (EntityDiscriminatorSqmPathSource) getNodeType();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -9,28 +9,23 @@ package org.hibernate.metamodel.model.domain.internal;
|
|||
import org.hibernate.metamodel.mapping.EntityMappingType;
|
||||
import org.hibernate.metamodel.model.domain.DomainType;
|
||||
import org.hibernate.metamodel.model.domain.EntityDomainType;
|
||||
import org.hibernate.query.ReturnableType;
|
||||
import org.hibernate.query.sqm.SqmPathSource;
|
||||
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
|
||||
*
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class DiscriminatorSqmPathSource<D> extends AbstractSqmPathSource<D>
|
||||
implements ReturnableType<D> {
|
||||
public class EntityDiscriminatorSqmPathSource<D> extends AbstractDiscriminatorSqmPathSource<D> {
|
||||
private final EntityDomainType<?> entityDomainType;
|
||||
private final EntityMappingType entityMapping;
|
||||
|
||||
public DiscriminatorSqmPathSource(
|
||||
public EntityDiscriminatorSqmPathSource(
|
||||
DomainType<D> discriminatorValueType,
|
||||
EntityDomainType<?> entityDomainType,
|
||||
EntityMappingType entityMapping) {
|
||||
super( DISCRIMINATOR_ROLE_NAME, null, discriminatorValueType, SINGULAR_ATTRIBUTE );
|
||||
super( discriminatorValueType );
|
||||
this.entityDomainType = entityDomainType;
|
||||
this.entityMapping = entityMapping;
|
||||
}
|
||||
|
@ -54,24 +49,4 @@ public class DiscriminatorSqmPathSource<D> extends AbstractSqmPathSource<D>
|
|||
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;
|
||||
}
|
||||
}
|
|
@ -85,7 +85,7 @@ public class EntityTypeImpl<J>
|
|||
.resolve( StandardBasicTypes.STRING );
|
||||
}
|
||||
|
||||
this.discriminatorPathSource = discriminatorType == null ? null : new DiscriminatorSqmPathSource(
|
||||
this.discriminatorPathSource = discriminatorType == null ? null : new EntityDiscriminatorSqmPathSource(
|
||||
discriminatorType,
|
||||
this,
|
||||
entityDescriptor
|
||||
|
|
|
@ -10,6 +10,7 @@ import java.io.ObjectStreamException;
|
|||
import java.io.Serializable;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
@ -17,6 +18,7 @@ import java.util.Map;
|
|||
import java.util.Set;
|
||||
import java.util.TreeMap;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import org.hibernate.boot.model.NamedEntityGraphDefinition;
|
||||
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
|
||||
|
@ -88,10 +90,9 @@ public class JpaMetamodelImpl implements JpaMetamodelImplementor, Serializable {
|
|||
private final MappingMetamodel mappingMetamodel;
|
||||
private final ServiceRegistry serviceRegistry;
|
||||
|
||||
private final Map<String, EntityDomainType<?>> jpaEntityTypeMap = new TreeMap<>(); // Need ordering for deterministic implementers list in SqmPolymorphicRootDescriptor
|
||||
private final Map<Class<?>, ManagedDomainType<?>> jpaManagedTypeMap = new HashMap<>();
|
||||
private final Set<ManagedDomainType<?>> jpaManagedTypes = new HashSet<>();
|
||||
private final Set<EmbeddableDomainType<?>> jpaEmbeddables = new HashSet<>();
|
||||
private final Map<String, ManagedDomainType<?>> managedTypeByName = new TreeMap<>();
|
||||
private final Map<Class<?>, ManagedDomainType<?>> managedTypeByClass = new HashMap<>();
|
||||
private JpaMetaModelPopulationSetting jpaMetaModelPopulationSetting;
|
||||
private final Map<String, Set<String>> allowedEnumLiteralTexts = new HashMap<>();
|
||||
|
||||
private final transient Map<String, RootGraphImplementor<?>> entityGraphMap = new ConcurrentHashMap<>();
|
||||
|
@ -129,9 +130,35 @@ public class JpaMetamodelImpl implements JpaMetamodelImplementor, Serializable {
|
|||
}
|
||||
|
||||
@Override
|
||||
public <X> EntityDomainType<X> entity(String entityName) {
|
||||
public <X> ManagedDomainType<X> managedType(String typeName) {
|
||||
//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
|
||||
|
@ -173,13 +200,13 @@ public class JpaMetamodelImpl implements JpaMetamodelImplementor, Serializable {
|
|||
@Override
|
||||
public <X> ManagedDomainType<X> findManagedType(Class<X> cls) {
|
||||
//noinspection unchecked
|
||||
return (ManagedDomainType<X>) jpaManagedTypeMap.get( cls );
|
||||
return (ManagedDomainType<X>) managedTypeByClass.get( cls );
|
||||
}
|
||||
|
||||
@Override
|
||||
public <X> EntityDomainType<X> findEntityType(Class<X> cls) {
|
||||
final ManagedType<?> type = jpaManagedTypeMap.get( cls );
|
||||
if ( !( type instanceof EntityType<?> ) ) {
|
||||
final ManagedType<?> type = managedTypeByClass.get( cls );
|
||||
if ( !( type instanceof EntityDomainType<?> ) ) {
|
||||
return null;
|
||||
}
|
||||
//noinspection unchecked
|
||||
|
@ -188,7 +215,7 @@ public class JpaMetamodelImpl implements JpaMetamodelImplementor, Serializable {
|
|||
|
||||
@Override
|
||||
public <X> ManagedDomainType<X> managedType(Class<X> cls) {
|
||||
final ManagedType<?> type = jpaManagedTypeMap.get( cls );
|
||||
final ManagedType<?> type = managedTypeByClass.get( cls );
|
||||
if ( type == null ) {
|
||||
// per JPA
|
||||
throw new IllegalArgumentException( "Not a managed type: " + cls );
|
||||
|
@ -200,7 +227,7 @@ public class JpaMetamodelImpl implements JpaMetamodelImplementor, Serializable {
|
|||
|
||||
@Override
|
||||
public <X> EntityDomainType<X> entity(Class<X> cls) {
|
||||
final ManagedType<?> type = jpaManagedTypeMap.get( cls );
|
||||
final ManagedType<?> type = managedTypeByClass.get( cls );
|
||||
if ( !( type instanceof EntityDomainType<?> ) ) {
|
||||
throw new IllegalArgumentException( "Not an entity: " + cls.getName() );
|
||||
}
|
||||
|
@ -210,7 +237,7 @@ public class JpaMetamodelImpl implements JpaMetamodelImplementor, Serializable {
|
|||
|
||||
@Override
|
||||
public <X> EmbeddableDomainType<X> embeddable(Class<X> cls) {
|
||||
final ManagedType<?> type = jpaManagedTypeMap.get( cls );
|
||||
final ManagedType<?> type = managedTypeByClass.get( cls );
|
||||
if ( !( type instanceof EmbeddableDomainType<?> ) ) {
|
||||
throw new IllegalArgumentException( "Not an embeddable: " + cls.getName() );
|
||||
}
|
||||
|
@ -218,25 +245,39 @@ public class JpaMetamodelImpl implements JpaMetamodelImplementor, Serializable {
|
|||
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
|
||||
public Set<ManagedType<?>> getManagedTypes() {
|
||||
return new HashSet<>( jpaManagedTypes );
|
||||
return new HashSet<>( getAllManagedTypes() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<EntityType<?>> getEntities() {
|
||||
final Set<EntityType<?>> entityTypes = new HashSet<>( jpaEntityTypeMap.size() );
|
||||
for ( ManagedDomainType<?> value : jpaManagedTypes ) {
|
||||
if ( value instanceof EntityType<?> ) {
|
||||
entityTypes.add( (EntityType<?>) value );
|
||||
}
|
||||
}
|
||||
return entityTypes;
|
||||
return getAllManagedTypes().stream()
|
||||
.filter( EntityType.class::isInstance )
|
||||
.map( t -> (EntityType<?>) t )
|
||||
.collect( Collectors.toSet() );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Set<EmbeddableType<?>> getEmbeddables() {
|
||||
return new HashSet<>( jpaEmbeddables );
|
||||
return getAllManagedTypes().stream()
|
||||
.filter( EmbeddableType.class::isInstance )
|
||||
.map( t -> (EmbeddableType<?>) t )
|
||||
.collect( Collectors.toSet() );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -454,9 +495,9 @@ public class JpaMetamodelImpl implements JpaMetamodelImplementor, Serializable {
|
|||
public <T> EntityDomainType<T> resolveEntityReference(Class<T> javaType) {
|
||||
// try the incoming Java type as a "strict" entity reference
|
||||
{
|
||||
final EntityDomainType<?> descriptor = jpaEntityTypeMap.get( javaType.getName() );
|
||||
if ( descriptor != null ) {
|
||||
return (EntityDomainType<T>) descriptor;
|
||||
final ManagedDomainType<?> managedType = managedTypeByClass.get( javaType );
|
||||
if ( managedType instanceof EntityDomainType<?> ) {
|
||||
return (EntityDomainType<T>) managedType;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -464,7 +505,7 @@ public class JpaMetamodelImpl implements JpaMetamodelImplementor, Serializable {
|
|||
{
|
||||
final String proxyEntityName = entityProxyInterfaceMap.get( javaType );
|
||||
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
|
||||
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.
|
||||
if ( javaType.isAssignableFrom( entityDomainType.getJavaType() ) ) {
|
||||
if ( javaType.isAssignableFrom( managedType.getJavaType() ) ) {
|
||||
// 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
|
||||
// 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
|
||||
// explicit-polymorphism. The super itself will get added and the initializers
|
||||
// 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
|
||||
&& superType.getPersistenceType() == Type.PersistenceType.ENTITY
|
||||
&& 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
|
||||
final EntityMappingType entityPersister = getMappingMetamodel()
|
||||
.getEntityDescriptor( entityDomainType.getHibernateEntityName() );
|
||||
.getEntityDescriptor( managedType.getTypeName() );
|
||||
if ( entityPersister.isExplicitPolymorphism() ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// 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();
|
||||
|
||||
for ( Map.Entry<String, IdentifiableDomainType<?>> entry : context.getIdentifiableTypesByName().entrySet() ) {
|
||||
if ( entry.getValue() instanceof EntityDomainType<?> ) {
|
||||
this.jpaEntityTypeMap.put( entry.getKey(), (EntityDomainType<?>) entry.getValue() );
|
||||
}
|
||||
}
|
||||
this.jpaMetaModelPopulationSetting = jpaMetaModelPopulationSetting;
|
||||
|
||||
this.jpaManagedTypeMap.putAll( context.getEntityTypeMap() );
|
||||
this.jpaManagedTypeMap.putAll( context.getMappedSuperclassTypeMap() );
|
||||
switch ( jpaMetaModelPopulationSetting ) {
|
||||
case IGNORE_UNSUPPORTED:
|
||||
this.jpaManagedTypes.addAll( context.getEntityTypeMap().values() );
|
||||
this.jpaManagedTypes.addAll( context.getMappedSuperclassTypeMap().values() );
|
||||
break;
|
||||
case ENABLED:
|
||||
this.jpaManagedTypes.addAll( context.getIdentifiableTypesByName().values() );
|
||||
break;
|
||||
}
|
||||
// Identifiable types (Entities and MappedSuperclasses)
|
||||
this.managedTypeByName.putAll( context.getIdentifiableTypesByName() );
|
||||
this.managedTypeByClass.putAll( context.getEntityTypeMap() );
|
||||
this.managedTypeByClass.putAll( context.getMappedSuperclassTypeMap() );
|
||||
|
||||
// Embeddable types
|
||||
int mapEmbeddables = 0;
|
||||
for ( EmbeddableDomainType<?> embeddable : context.getEmbeddableTypeSet() ) {
|
||||
// Do not register the embeddable types for id classes
|
||||
if ( embeddable.getExpressibleJavaType() instanceof EntityJavaType<?> ) {
|
||||
continue;
|
||||
}
|
||||
switch ( jpaMetaModelPopulationSetting ) {
|
||||
case IGNORE_UNSUPPORTED:
|
||||
if ( embeddable.getJavaType() != null && embeddable.getJavaType() != Map.class ) {
|
||||
this.jpaEmbeddables.add( embeddable );
|
||||
this.jpaManagedTypes.add( embeddable );
|
||||
if ( !( embeddable.getExpressibleJavaType() instanceof EntityJavaType<?> ) ) {
|
||||
this.jpaManagedTypeMap.put( embeddable.getJavaType(), 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;
|
||||
final Class<?> embeddableClass = embeddable.getJavaType();
|
||||
if ( embeddableClass != Map.class ) {
|
||||
this.managedTypeByClass.put( embeddable.getJavaType(), embeddable );
|
||||
this.managedTypeByName.put( embeddable.getTypeName(), embeddable );
|
||||
}
|
||||
else {
|
||||
this.managedTypeByName.put( "dynamic-embeddable-" + mapEmbeddables++, embeddable );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -489,11 +489,21 @@ public class MappingMetamodelImpl extends QueryParameterBindingTypeResolverImpl
|
|||
return jpaMetamodel.getEmbeddables();
|
||||
}
|
||||
|
||||
@Override
|
||||
public <X> ManagedDomainType<X> managedType(String typeName) {
|
||||
return jpaMetamodel.managedType( typeName );
|
||||
}
|
||||
|
||||
@Override
|
||||
public <X> EntityDomainType<X> entity(String entityName) {
|
||||
return jpaMetamodel.entity( entityName );
|
||||
}
|
||||
|
||||
@Override
|
||||
public <X> EmbeddableDomainType<X> embeddable(String embeddableName) {
|
||||
return jpaMetamodel.embeddable( embeddableName );
|
||||
}
|
||||
|
||||
@Override
|
||||
public <X> EntityDomainType<X> getHqlEntityReference(String entityName) {
|
||||
return jpaMetamodel.getHqlEntityReference( entityName );
|
||||
|
|
|
@ -97,7 +97,7 @@ public class DiscriminatorHelper {
|
|||
);
|
||||
}
|
||||
|
||||
private static <T> String jdbcLiteral(
|
||||
public static <T> String jdbcLiteral(
|
||||
T value,
|
||||
JdbcLiteralFormatter<T> formatter,
|
||||
Dialect dialect) {
|
||||
|
|
|
@ -9,7 +9,9 @@ package org.hibernate.query.hql.internal;
|
|||
import java.lang.reflect.Field;
|
||||
|
||||
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.ManagedDomainType;
|
||||
import org.hibernate.metamodel.model.domain.spi.JpaMetamodelImplementor;
|
||||
import org.hibernate.query.SemanticException;
|
||||
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.SqmExpression;
|
||||
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.from.SqmFrom;
|
||||
import org.hibernate.type.descriptor.java.EnumJavaType;
|
||||
|
@ -93,9 +96,16 @@ public class BasicDotIdentifierConsumer implements DotIdentifierConsumer {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void consumeTreat(String entityName, boolean isTerminal) {
|
||||
final SqmPath<?> path = (SqmPath<?>) currentPart;
|
||||
currentPart = path.treatAs( creationState.getCreationContext().getJpaMetamodel().entity( entityName ) );
|
||||
public void consumeTreat(String importableName, boolean isTerminal) {
|
||||
final SqmPath<?> sqmPath = (SqmPath<?>) currentPart;
|
||||
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() {
|
||||
|
@ -181,9 +191,12 @@ public class BasicDotIdentifierConsumer implements DotIdentifierConsumer {
|
|||
final String importableName = jpaMetamodel.qualifyImportableName( path );
|
||||
final NodeBuilder nodeBuilder = creationContext.getNodeBuilder();
|
||||
if ( importableName != null ) {
|
||||
final EntityDomainType<?> entityDomainType = jpaMetamodel.entity( importableName );
|
||||
if ( entityDomainType != null ) {
|
||||
return new SqmLiteralEntityType<>( entityDomainType, nodeBuilder );
|
||||
final ManagedDomainType<?> managedType = jpaMetamodel.managedType( importableName );
|
||||
if ( managedType instanceof EntityDomainType<?> ) {
|
||||
return new SqmLiteralEntityType<>( ( (EntityDomainType<?>) managedType ), nodeBuilder );
|
||||
}
|
||||
else if ( managedType instanceof EmbeddableDomainType<?> ) {
|
||||
return new SqmLiteralEmbeddableType<>( ( (EmbeddableDomainType<?>) managedType ), nodeBuilder );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
package org.hibernate.query.hql.internal;
|
||||
|
||||
import org.hibernate.metamodel.model.domain.EntityDomainType;
|
||||
import org.hibernate.metamodel.model.domain.ManagedDomainType;
|
||||
import org.hibernate.query.PathException;
|
||||
import org.hibernate.query.SemanticException;
|
||||
import org.hibernate.query.hql.spi.DotIdentifierConsumer;
|
||||
|
@ -239,7 +240,7 @@ public class QualifiedJoinPathConsumer implements DotIdentifierConsumer {
|
|||
|
||||
private interface ConsumerDelegate {
|
||||
void consumeIdentifier(String identifier, boolean isTerminal, boolean allowReuse);
|
||||
void consumeTreat(String entityName, boolean isTerminal);
|
||||
void consumeTreat(String typeName, boolean isTerminal);
|
||||
SemanticPathPart getConsumedPart();
|
||||
}
|
||||
|
||||
|
@ -280,20 +281,23 @@ public class QualifiedJoinPathConsumer implements DotIdentifierConsumer {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void consumeTreat(String entityName, boolean isTerminal) {
|
||||
public void consumeTreat(String typeName, boolean isTerminal) {
|
||||
if ( isTerminal ) {
|
||||
currentPath = fetch
|
||||
? ( (SqmAttributeJoin<?, ?>) currentPath ).treatAs( treatTarget( entityName ), alias, true )
|
||||
: currentPath.treatAs( treatTarget( entityName ), alias );
|
||||
? ( (SqmAttributeJoin<?, ?>) currentPath ).treatAs( treatTarget( typeName ), alias, true )
|
||||
: currentPath.treatAs( treatTarget( typeName ), alias );
|
||||
}
|
||||
else {
|
||||
currentPath = currentPath.treatAs( treatTarget( entityName ) );
|
||||
currentPath = currentPath.treatAs( treatTarget( typeName ) );
|
||||
}
|
||||
creationState.getCurrentProcessingState().getPathRegistry().register( currentPath );
|
||||
}
|
||||
|
||||
private <T> EntityDomainType<T> treatTarget(String entityName) {
|
||||
return creationState.getCreationContext().getJpaMetamodel().entity(entityName);
|
||||
private <T> Class<T> treatTarget(String typeName) {
|
||||
final ManagedDomainType<T> managedType = creationState.getCreationContext()
|
||||
.getJpaMetamodel()
|
||||
.managedType( typeName );
|
||||
return managedType.getJavaType();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -364,7 +368,7 @@ public class QualifiedJoinPathConsumer implements DotIdentifierConsumer {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void consumeTreat(String entityName, boolean isTerminal) {
|
||||
public void consumeTreat(String typeName, boolean isTerminal) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
|
|
|
@ -5481,14 +5481,13 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
|
|||
consumeManagedTypeReference( ctx.path() );
|
||||
|
||||
final String treatTargetName = ctx.simplePath().getText();
|
||||
final String treatTargetEntityName =
|
||||
getCreationContext().getJpaMetamodel().qualifyImportableName( treatTargetName );
|
||||
if ( treatTargetEntityName == null ) {
|
||||
final String importableName = getCreationContext().getJpaMetamodel().qualifyImportableName( treatTargetName );
|
||||
if ( importableName == null ) {
|
||||
throw new SemanticException( "Could not resolve treat target type '" + treatTargetName + "'", query );
|
||||
}
|
||||
|
||||
final boolean hasContinuation = ctx.getChildCount() == 7;
|
||||
consumer.consumeTreat( treatTargetEntityName, !hasContinuation );
|
||||
consumer.consumeTreat( importableName, !hasContinuation );
|
||||
SqmPath<?> result = (SqmPath<?>) consumer.getConsumedPart();
|
||||
|
||||
if ( hasContinuation ) {
|
||||
|
|
|
@ -8,8 +8,8 @@ package org.hibernate.query.sqm;
|
|||
|
||||
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.EntityDiscriminatorSqmPath;
|
||||
import org.hibernate.query.sqm.tree.cte.SqmCteContainer;
|
||||
import org.hibernate.query.sqm.tree.cte.SqmCteStatement;
|
||||
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.SqmHqlNumericLiteral;
|
||||
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.SqmModifiedSubQueryExpression;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmNamedParameter;
|
||||
|
@ -238,7 +239,7 @@ public interface SemanticQueryWalker<T> {
|
|||
|
||||
T visitFkExpression(SqmFkExpression<?> fkExpression);
|
||||
|
||||
T visitDiscriminatorPath(EntityDiscriminatorSqmPath sqmPath);
|
||||
T visitDiscriminatorPath(DiscriminatorSqmPath<?> sqmPath);
|
||||
|
||||
T visitIndexedPluralAccessPath(SqmIndexedCollectionAccessPath<?> path);
|
||||
|
||||
|
@ -320,6 +321,8 @@ public interface SemanticQueryWalker<T> {
|
|||
|
||||
T visitEntityTypeLiteralExpression(SqmLiteralEntityType<?> expression);
|
||||
|
||||
T visitEmbeddableTypeLiteralExpression(SqmLiteralEmbeddableType<?> expression);
|
||||
|
||||
T visitAnyDiscriminatorTypeExpression(AnyDiscriminatorSqmPath<?> expression);
|
||||
|
||||
T visitAnyDiscriminatorTypeValueExpression(SqmAnyDiscriminatorValue<?> expression);
|
||||
|
|
|
@ -21,6 +21,7 @@ import org.hibernate.metamodel.model.domain.BasicDomainType;
|
|||
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.ManagedDomainType;
|
||||
import org.hibernate.metamodel.model.domain.MappedSuperclassDomainType;
|
||||
import org.hibernate.metamodel.model.domain.internal.AnyMappingSqmPathSource;
|
||||
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.domain.AbstractSqmSpecificPluralPartPath;
|
||||
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.spi.NavigablePath;
|
||||
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 jakarta.persistence.metamodel.Bindable;
|
||||
import jakarta.persistence.metamodel.Type;
|
||||
|
||||
/**
|
||||
* 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<?, ?> ) {
|
||||
final SqmTreatedPath<?, ?> treatedPath = (SqmTreatedPath<?, ?>) sqmPath;
|
||||
final EntityDomainType<?> treatTargetType = treatedPath.getTreatTarget();
|
||||
return domainModel.findEntityDescriptor( treatTargetType.getHibernateEntityName() );
|
||||
final ManagedDomainType<?> treatTarget = treatedPath.getTreatTarget();
|
||||
if ( treatTarget.getPersistenceType() == Type.PersistenceType.ENTITY ) {
|
||||
final EntityDomainType<?> treatTargetType = (EntityDomainType<?>) treatTarget;
|
||||
return domainModel.findEntityDescriptor( treatTargetType.getHibernateEntityName() );
|
||||
}
|
||||
}
|
||||
|
||||
// see if the LHS is treated
|
||||
if ( sqmPath.getLhs() instanceof SqmTreatedPath<?, ?> ) {
|
||||
final SqmTreatedPath<?, ?> treatedPath = (SqmTreatedPath<?, ?>) sqmPath.getLhs();
|
||||
final EntityDomainType<?> treatTargetType = treatedPath.getTreatTarget();
|
||||
final EntityPersister container = domainModel.findEntityDescriptor( treatTargetType.getHibernateEntityName() );
|
||||
|
||||
return container.findSubPart( sqmPath.getNavigablePath().getLocalName(), container );
|
||||
final ManagedDomainType<?> treatTarget = treatedPath.getTreatTarget();
|
||||
if ( treatTarget.getPersistenceType() == Type.PersistenceType.ENTITY ) {
|
||||
final EntityPersister container = domainModel.findEntityDescriptor( treatTarget.getTypeName() );
|
||||
return container.findSubPart( sqmPath.getNavigablePath().getLocalName(), container );
|
||||
}
|
||||
}
|
||||
|
||||
// Plural path parts are not joined and thus also have no table group
|
||||
|
@ -253,9 +258,15 @@ public class SqmMappingModelHelper {
|
|||
SqmPath<?> sqmPath,
|
||||
SqmToSqlAstConverter converter) {
|
||||
final SqmPath<?> parentPath = sqmPath.getLhs();
|
||||
if ( parentPath instanceof SqmTreatedPath ) {
|
||||
if ( parentPath instanceof SqmTreatedPath<?, ?> ) {
|
||||
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;
|
||||
|
|
|
@ -9,8 +9,8 @@ package org.hibernate.query.sqm.internal;
|
|||
import java.util.List;
|
||||
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.EntityDiscriminatorSqmPath;
|
||||
import org.hibernate.query.QueryLogging;
|
||||
import org.hibernate.query.sqm.SemanticQueryWalker;
|
||||
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.SqmHqlNumericLiteral;
|
||||
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.SqmModifiedSubQueryExpression;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmNamedParameter;
|
||||
|
@ -723,7 +724,7 @@ public class SqmTreePrinter implements SemanticQueryWalker<Object> {
|
|||
}
|
||||
|
||||
@Override
|
||||
public Object visitDiscriminatorPath(EntityDiscriminatorSqmPath sqmPath) {
|
||||
public Object visitDiscriminatorPath(DiscriminatorSqmPath<?> sqmPath) {
|
||||
logWithIndentation( "-> [discriminator-path] - `%s`", sqmPath.getNavigablePath() );
|
||||
|
||||
return null;
|
||||
|
@ -807,6 +808,11 @@ public class SqmTreePrinter implements SemanticQueryWalker<Object> {
|
|||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitEmbeddableTypeLiteralExpression(SqmLiteralEmbeddableType<?> expression) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitParameterizedEntityTypeExpression(SqmParameterizedEntityType expression) {
|
||||
return null;
|
||||
|
|
|
@ -7,13 +7,14 @@
|
|||
package org.hibernate.query.sqm.internal;
|
||||
|
||||
import jakarta.persistence.criteria.Expression;
|
||||
import jakarta.persistence.metamodel.EmbeddableType;
|
||||
import jakarta.persistence.metamodel.EntityType;
|
||||
import org.hibernate.engine.spi.SessionFactoryImplementor;
|
||||
import org.hibernate.metamodel.mapping.JdbcMapping;
|
||||
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.internal.DiscriminatorSqmPathSource;
|
||||
import org.hibernate.metamodel.model.domain.internal.EntityDiscriminatorSqmPathSource;
|
||||
import org.hibernate.persister.entity.EntityPersister;
|
||||
import org.hibernate.query.SemanticException;
|
||||
import org.hibernate.query.sqm.BinaryArithmeticOperator;
|
||||
|
@ -128,8 +129,8 @@ public class TypecheckUtil {
|
|||
|
||||
// for embeddables, the embeddable class must match exactly
|
||||
|
||||
final EmbeddableType<?> lhsEmbeddable = getEmbeddableType( lhsDomainType );
|
||||
final EmbeddableType<?> rhsEmbeddable = getEmbeddableType( rhsDomainType );
|
||||
final EmbeddableDomainType<?> lhsEmbeddable = getEmbeddableType( lhsDomainType );
|
||||
final EmbeddableDomainType<?> rhsEmbeddable = getEmbeddableType( rhsDomainType );
|
||||
if ( lhsEmbeddable != null && rhsEmbeddable != null ) {
|
||||
return areEmbeddableTypesComparable( lhsEmbeddable, rhsEmbeddable );
|
||||
}
|
||||
|
@ -157,11 +158,11 @@ public class TypecheckUtil {
|
|||
// entities can be compared to discriminators if they belong to
|
||||
// the same inheritance hierarchy
|
||||
|
||||
if ( lhsDomainType instanceof DiscriminatorSqmPathSource ) {
|
||||
return isDiscriminatorTypeComparable( (DiscriminatorSqmPathSource<?>) lhsDomainType, rhsDomainType, factory );
|
||||
if ( lhsDomainType instanceof EntityDiscriminatorSqmPathSource ) {
|
||||
return isDiscriminatorTypeComparable( (EntityDiscriminatorSqmPathSource<?>) lhsDomainType, rhsDomainType, factory );
|
||||
}
|
||||
if ( rhsDomainType instanceof DiscriminatorSqmPathSource ) {
|
||||
return isDiscriminatorTypeComparable( (DiscriminatorSqmPathSource<?>) rhsDomainType, lhsDomainType, factory );
|
||||
if ( rhsDomainType instanceof EntityDiscriminatorSqmPathSource ) {
|
||||
return isDiscriminatorTypeComparable( (EntityDiscriminatorSqmPathSource<?>) rhsDomainType, lhsDomainType, factory );
|
||||
}
|
||||
|
||||
// Treat the expressions as comparable if they belong to the same
|
||||
|
@ -197,15 +198,26 @@ public class TypecheckUtil {
|
|||
return false;
|
||||
}
|
||||
|
||||
private static EmbeddableType<?> getEmbeddableType(SqmExpressible<?> expressible) {
|
||||
return expressible instanceof EmbeddableType<?> ? (EmbeddableType<?>) expressible : null;
|
||||
private static EmbeddableDomainType<?> getEmbeddableType(SqmExpressible<?> expressible) {
|
||||
return expressible instanceof EmbeddableDomainType<?> ? (EmbeddableDomainType<?>) expressible : null;
|
||||
}
|
||||
|
||||
private static boolean areEmbeddableTypesComparable(
|
||||
EmbeddableType<?> lhsType,
|
||||
EmbeddableType<?> rhsType) {
|
||||
// no polymorphism for embeddable types
|
||||
return rhsType.getJavaType() == lhsType.getJavaType();
|
||||
EmbeddableDomainType<?> lhsType,
|
||||
EmbeddableDomainType<?> rhsType) {
|
||||
if ( 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(
|
||||
|
@ -234,7 +246,7 @@ public class TypecheckUtil {
|
|||
}
|
||||
|
||||
private static boolean isDiscriminatorTypeComparable(
|
||||
DiscriminatorSqmPathSource<?> lhsDiscriminator, SqmExpressible<?> rhsType,
|
||||
EntityDiscriminatorSqmPathSource<?> lhsDiscriminator, SqmExpressible<?> rhsType,
|
||||
SessionFactoryImplementor factory) {
|
||||
String entityName = lhsDiscriminator.getEntityDomainType().getHibernateEntityName();
|
||||
EntityPersister lhsEntity = factory.getMappingMetamodel().getEntityDescriptor( entityName );
|
||||
|
@ -243,8 +255,8 @@ public class TypecheckUtil {
|
|||
EntityPersister rhsEntity = getEntityDescriptor( factory, rhsEntityName );
|
||||
return lhsEntity.getRootEntityName().equals( rhsEntity.getRootEntityName() );
|
||||
}
|
||||
else if ( rhsType instanceof DiscriminatorSqmPathSource ) {
|
||||
DiscriminatorSqmPathSource<?> discriminator = (DiscriminatorSqmPathSource<?>) rhsType;
|
||||
else if ( rhsType instanceof EntityDiscriminatorSqmPathSource ) {
|
||||
EntityDiscriminatorSqmPathSource<?> discriminator = (EntityDiscriminatorSqmPathSource<?>) rhsType;
|
||||
String rhsEntityName = discriminator.getEntityDomainType().getHibernateEntityName();
|
||||
EntityPersister rhsEntity = factory.getMappingMetamodel().getEntityDescriptor( rhsEntityName );
|
||||
return rhsEntity.getRootEntityName().equals( lhsEntity.getRootEntityName() );
|
||||
|
|
|
@ -8,8 +8,8 @@ package org.hibernate.query.sqm.spi;
|
|||
|
||||
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.EntityDiscriminatorSqmPath;
|
||||
import org.hibernate.query.sqm.InterpretationException;
|
||||
import org.hibernate.query.sqm.SemanticQueryWalker;
|
||||
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.SqmHqlNumericLiteral;
|
||||
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.SqmModifiedSubQueryExpression;
|
||||
import org.hibernate.query.sqm.tree.expression.SqmNamedParameter;
|
||||
|
@ -468,7 +469,7 @@ public abstract class BaseSemanticQueryWalker implements SemanticQueryWalker<Obj
|
|||
}
|
||||
|
||||
@Override
|
||||
public Object visitDiscriminatorPath(EntityDiscriminatorSqmPath path) {
|
||||
public Object visitDiscriminatorPath(DiscriminatorSqmPath<?> path) {
|
||||
return path;
|
||||
}
|
||||
|
||||
|
@ -719,6 +720,11 @@ public abstract class BaseSemanticQueryWalker implements SemanticQueryWalker<Obj
|
|||
return expression;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitEmbeddableTypeLiteralExpression(SqmLiteralEmbeddableType<?> expression) {
|
||||
return expression;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object visitAnyDiscriminatorTypeExpression(AnyDiscriminatorSqmPath<?> expression) {
|
||||
return expression;
|
||||
|
|
|
@ -74,8 +74,10 @@ import org.hibernate.metamodel.mapping.internal.SqlTypedMappingImpl;
|
|||
import org.hibernate.metamodel.mapping.internal.ToOneAttributeMapping;
|
||||
import org.hibernate.metamodel.mapping.ordering.OrderByFragment;
|
||||
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.EntityDomainType;
|
||||
import org.hibernate.metamodel.model.domain.ManagedDomainType;
|
||||
import org.hibernate.metamodel.model.domain.PersistentAttribute;
|
||||
import org.hibernate.metamodel.model.domain.PluralPersistentAttribute;
|
||||
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.SqmJpaCriteriaParameterWrapper;
|
||||
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.SqmLiteralNull;
|
||||
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.Duration;
|
||||
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.Every;
|
||||
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.Supplier;
|
||||
|
||||
import static jakarta.persistence.metamodel.Type.PersistenceType.ENTITY;
|
||||
import static java.util.Collections.singletonList;
|
||||
import static org.hibernate.boot.model.internal.SoftDeleteHelper.createNonSoftDeletedRestriction;
|
||||
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) {
|
||||
if ( sqmPredicate == null ) {
|
||||
return null;
|
||||
}
|
||||
currentClauseStack.push( Clause.WHERE );
|
||||
inferrableTypeAccessStack.push( () -> null );
|
||||
try {
|
||||
return combinePredicates(
|
||||
(Predicate) sqmPredicate.accept( this ),
|
||||
sqmPredicate != null ? (Predicate) sqmPredicate.accept( this ) : null,
|
||||
consumeConjunctTreatTypeRestrictions()
|
||||
);
|
||||
}
|
||||
|
@ -2494,14 +2496,11 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
|||
|
||||
@Override
|
||||
public Predicate visitHavingClause(SqmPredicate sqmPredicate) {
|
||||
if ( sqmPredicate == null ) {
|
||||
return null;
|
||||
}
|
||||
currentClauseStack.push( Clause.HAVING );
|
||||
inferrableTypeAccessStack.push( () -> null );
|
||||
try {
|
||||
return combinePredicates(
|
||||
(Predicate) sqmPredicate.accept( this ),
|
||||
sqmPredicate != null ? (Predicate) sqmPredicate.accept( this ) : null,
|
||||
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.
|
||||
*/
|
||||
private void registerEntityNameProjectionUsage(SqmPath<?> projectedPath, TableGroup tableGroup) {
|
||||
final EntityDomainType<?> treatedType;
|
||||
final ManagedDomainType<?> treatedType;
|
||||
if ( projectedPath instanceof SqmTreatedPath<?, ?> ) {
|
||||
treatedType = ( (SqmTreatedPath<?, ?>) projectedPath ).getTreatTarget();
|
||||
registerEntityNameUsage( tableGroup, EntityNameUse.TREAT, treatedType.getHibernateEntityName(), true );
|
||||
registerEntityNameUsage( tableGroup, EntityNameUse.TREAT, treatedType.getTypeName(), true );
|
||||
|
||||
if ( projectedPath instanceof SqmFrom<?, ?> ) {
|
||||
// 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<?> ) {
|
||||
treatedType = (EntityDomainType<?>) projectedPath.getNodeType().getSqmPathType();
|
||||
registerEntityNameUsage( tableGroup, EntityNameUse.PROJECTION, treatedType.getHibernateEntityName(), true );
|
||||
registerEntityNameUsage( tableGroup, EntityNameUse.PROJECTION, treatedType.getTypeName(), true );
|
||||
|
||||
if ( projectedPath instanceof SqmFrom<?, ?> ) {
|
||||
// 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;
|
||||
if ( parentPath instanceof SqmTreatedPath<?, ?> ) {
|
||||
// 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()
|
||||
.getEntityDescriptor( treatTarget.getHibernateEntityName() );
|
||||
|
||||
// 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.
|
||||
|
||||
final ModelPart subPart = parentType.findSubPart( attributeName );
|
||||
final EntityNameUse entityNameUse;
|
||||
// We only apply this optimization for basic valued model parts for now
|
||||
if ( subPart.asBasicValuedModelPart() != null ) {
|
||||
entityNameUse = EntityNameUse.OPTIONAL_TREAT;
|
||||
final ModelPart subPart = parentType.findSubPart( attributeName );
|
||||
final EntityNameUse entityNameUse;
|
||||
// We only apply this optimization for basic valued model parts for now
|
||||
if ( subPart.asBasicValuedModelPart() != null ) {
|
||||
entityNameUse = EntityNameUse.OPTIONAL_TREAT;
|
||||
}
|
||||
else {
|
||||
entityNameUse = EntityNameUse.BASE_TREAT;
|
||||
}
|
||||
registerEntityNameUsage(
|
||||
tableGroup,
|
||||
entityNameUse,
|
||||
treatTarget.getTypeName()
|
||||
);
|
||||
}
|
||||
else {
|
||||
entityNameUse = EntityNameUse.BASE_TREAT;
|
||||
parentType = entityType;
|
||||
}
|
||||
registerEntityNameUsage(
|
||||
tableGroup,
|
||||
entityNameUse,
|
||||
treatTarget.getHibernateEntityName()
|
||||
);
|
||||
}
|
||||
else {
|
||||
// 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(
|
||||
TableGroup tableGroup,
|
||||
EntityNameUse entityNameUse,
|
||||
String hibernateEntityName) {
|
||||
String treatTargetTypeName) {
|
||||
registerEntityNameUsage(
|
||||
tableGroup,
|
||||
entityNameUse,
|
||||
hibernateEntityName,
|
||||
treatTargetTypeName,
|
||||
entityNameUse.getKind() == EntityNameUse.UseKind.PROJECTION
|
||||
);
|
||||
}
|
||||
|
@ -3059,14 +3060,27 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
|||
private void registerEntityNameUsage(
|
||||
TableGroup tableGroup,
|
||||
EntityNameUse entityNameUse,
|
||||
String hibernateEntityName,
|
||||
String treatTargetTypeName,
|
||||
boolean projection) {
|
||||
final AbstractEntityPersister persister = (AbstractEntityPersister) creationContext.getSessionFactory()
|
||||
.getRuntimeMetamodels()
|
||||
.getMappingMetamodel()
|
||||
.findEntityDescriptor( hibernateEntityName );
|
||||
if ( persister == null || !persister.isPolymorphic() ) {
|
||||
return;
|
||||
final AbstractEntityPersister persister;
|
||||
if ( tableGroup.getModelPart() instanceof EmbeddableValuedModelPart ) {
|
||||
persister = null;
|
||||
final EmbeddableDomainType<?> embeddableDomainType = creationContext.getSessionFactory()
|
||||
.getRuntimeMetamodels()
|
||||
.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 EntityNameUse finalEntityNameUse;
|
||||
|
@ -3094,10 +3108,15 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
|||
tg -> new HashMap<>( 1 )
|
||||
);
|
||||
entityNameUses.compute(
|
||||
hibernateEntityName,
|
||||
treatTargetTypeName,
|
||||
(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.
|
||||
// Also, force table group initialization for treats when needed to ensure correct cardinality
|
||||
final EntityNameUse.UseKind useKind = finalEntityNameUse.getKind();
|
||||
|
@ -3156,7 +3175,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
|||
return false;
|
||||
}
|
||||
|
||||
protected void registerTypeUsage(EntityDiscriminatorSqmPath path) {
|
||||
protected void registerTypeUsage(DiscriminatorSqmPath<?> path) {
|
||||
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`
|
||||
// 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
|
||||
final EntityMappingType mappingType = (EntityMappingType) tableGroup.getModelPart().getPartMappingType();
|
||||
final AbstractEntityPersister persister = (AbstractEntityPersister) mappingType.getEntityPersister();
|
||||
// Avoid resolving subclass tables for persisters with physical discriminators as we won't need them
|
||||
if ( persister.getDiscriminatorMapping().hasPhysicalColumn() ) {
|
||||
return;
|
||||
}
|
||||
if ( getCurrentClauseStack().getCurrent() != Clause.WHERE && getCurrentClauseStack().getCurrent() != Clause.HAVING ) {
|
||||
// Where and having clauses are handled specially with EntityNameUse.FILTER and pruning
|
||||
registerEntityNameUsage( tableGroup, EntityNameUse.PROJECTION, persister.getEntityName(), true );
|
||||
}
|
||||
else {
|
||||
final int subclassTableSpan = persister.getSubclassTableSpan();
|
||||
for ( int i = 0; i < subclassTableSpan; i++ ) {
|
||||
tableGroup.resolveTableReference( null, persister.getSubclassTableName( i ) );
|
||||
final MappingType partMappingType = tableGroup.getModelPart().getPartMappingType();
|
||||
if ( partMappingType instanceof EntityMappingType ) {
|
||||
final EntityMappingType mappingType = (EntityMappingType) partMappingType;
|
||||
final AbstractEntityPersister persister = (AbstractEntityPersister) mappingType.getEntityPersister();
|
||||
// Avoid resolving subclass tables for persisters with physical discriminators as we won't need them
|
||||
if ( persister.getDiscriminatorMapping().hasPhysicalColumn() ) {
|
||||
return;
|
||||
}
|
||||
if ( getCurrentClauseStack().getCurrent() != Clause.WHERE && getCurrentClauseStack().getCurrent() != Clause.HAVING ) {
|
||||
// Where and having clauses are handled specially with EntityNameUse.FILTER and pruning
|
||||
registerEntityNameUsage( tableGroup, EntityNameUse.PROJECTION, persister.getEntityName(), true );
|
||||
}
|
||||
else {
|
||||
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() ) {
|
||||
final Map<String, EntityNameUse> entityNameUses = entry.getValue();
|
||||
final ModelPartContainer modelPart = tableGroup.getModelPart();
|
||||
final EntityPersister tableGroupPersister;
|
||||
final MappingType partMappingType;
|
||||
if ( modelPart instanceof PluralAttributeMapping ) {
|
||||
tableGroupPersister = (EntityPersister) ( (PluralAttributeMapping) modelPart )
|
||||
partMappingType = ( (PluralAttributeMapping) modelPart )
|
||||
.getElementDescriptor()
|
||||
.getPartMappingType();
|
||||
}
|
||||
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 ) {
|
||||
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
|
||||
registerEntityNameUsage( actualTableGroup, EntityNameUse.BASE_TREAT, ( (SqmTreatedPath<?, ?>) sqmTreat ).getTreatTarget().getHibernateEntityName() );
|
||||
registerEntityNameUsage( actualTableGroup, EntityNameUse.BASE_TREAT, ( (SqmTreatedPath<?, ?>) sqmTreat ).getTreatTarget().getTypeName() );
|
||||
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
|
||||
if ( sqmJoin.getLhs() instanceof SqmTreatedPath<?, ?> ) {
|
||||
final SqmTreatedPath<?, ?> treatedPath = (SqmTreatedPath<?, ?>) sqmJoin.getLhs();
|
||||
joinForPredicate.applyPredicate(
|
||||
createTreatTypeRestriction(
|
||||
treatedPath.getWrappedPath(),
|
||||
treatedPath.getTreatTarget()
|
||||
)
|
||||
);
|
||||
final ManagedDomainType<?> treatTarget = treatedPath.getTreatTarget();
|
||||
if ( treatTarget.getPersistenceType() == ENTITY ) {
|
||||
joinForPredicate.applyPredicate(
|
||||
createTreatTypeRestriction(
|
||||
treatedPath.getWrappedPath(),
|
||||
(EntityDomainType<?>) treatTarget
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
if ( transitive ) {
|
||||
|
@ -3681,11 +3709,14 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
|||
Consumer<TableGroup> implicitJoinChecker) {
|
||||
final SqmPath<?> sqmPath = (SqmPath<?>) path;
|
||||
final SqmPath<?> parentPath;
|
||||
final boolean treated;
|
||||
if ( sqmPath instanceof SqmTreatedPath<?, ?> ) {
|
||||
parentPath = ( (SqmTreatedPath<?, ?>) sqmPath ).getWrappedPath();
|
||||
treated = true;
|
||||
}
|
||||
else {
|
||||
parentPath = sqmPath.getLhs();
|
||||
treated = false;
|
||||
}
|
||||
if ( parentPath == null ) {
|
||||
if ( sqmPath instanceof SqmFunctionPath<?> ) {
|
||||
|
@ -3730,10 +3761,13 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
|||
if ( newTableGroup != null ) {
|
||||
implicitJoinChecker.accept( newTableGroup );
|
||||
registerPathAttributeEntityNameUsage( sqmPath, newTableGroup );
|
||||
if ( treated ) {
|
||||
fromClauseIndex.register( sqmPath, newTableGroup );
|
||||
}
|
||||
}
|
||||
return newTableGroup;
|
||||
}
|
||||
else if ( sqmPath instanceof SqmTreatedPath<?, ?> ) {
|
||||
else if ( treated ) {
|
||||
fromClauseIndex.register( sqmPath, parentTableGroup );
|
||||
}
|
||||
|
||||
|
@ -3827,8 +3861,8 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
|||
final FromClauseIndex fromClauseIndex = getFromClauseIndex();
|
||||
final ModelPart subPart = parentTableGroup.getModelPart().findSubPart(
|
||||
joinedPath.getReferencedPathSource().getPathName(),
|
||||
lhsPath instanceof SqmTreatedPath
|
||||
? resolveEntityPersister( ( (SqmTreatedPath<?, ?>) lhsPath ).getTreatTarget() )
|
||||
lhsPath instanceof SqmTreatedPath<?, ?> && ( (SqmTreatedPath<?, ?>) lhsPath ).getTreatTarget().getPersistenceType() == ENTITY
|
||||
? resolveEntityPersister( (EntityDomainType<?>) ( (SqmTreatedPath<?, ?>) lhsPath ).getTreatTarget() )
|
||||
: null
|
||||
);
|
||||
|
||||
|
@ -4059,7 +4093,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
|||
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 ModelPart actualModelPart;
|
||||
|
@ -4213,11 +4247,12 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
|||
}
|
||||
|
||||
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()
|
||||
.getRuntimeMetamodels()
|
||||
.getMappingMetamodel()
|
||||
.findEntityDescriptor( ( (SqmTreatedPath<?,?>) path ).getTreatTarget().getHibernateEntityName() );
|
||||
.findEntityDescriptor( treatTarget.getTypeName() );
|
||||
}
|
||||
else {
|
||||
treatedMapping = interpretationModelPart.getEntityMappingType();
|
||||
|
@ -4501,7 +4536,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
|||
}
|
||||
|
||||
@Override
|
||||
public Object visitDiscriminatorPath(EntityDiscriminatorSqmPath sqmPath) {
|
||||
public Object visitDiscriminatorPath(DiscriminatorSqmPath<?> sqmPath) {
|
||||
return prepareReusablePath(
|
||||
sqmPath,
|
||||
() -> {
|
||||
|
@ -4574,7 +4609,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
|||
final TableGroup resolved = getFromClauseAccess().findTableGroup( sqmTreatedPath.getNavigablePath() );
|
||||
if ( resolved != null ) {
|
||||
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" );
|
||||
|
@ -5152,13 +5187,20 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
|||
}
|
||||
if ( lhs instanceof SqmTreatedPath<?, ?> ) {
|
||||
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 Class<?> originalJavaType = wrappedPath.getJavaType();
|
||||
if ( treatTargetJavaType.isAssignableFrom( originalJavaType ) ) {
|
||||
// Treating a node to a super type can be ignored
|
||||
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 ) ) {
|
||||
// A case wrapper for non-basic paths is not possible,
|
||||
// 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.
|
||||
// Joins don't need the restriction as it will be embedded into
|
||||
// the joined table group itself by #pruneTableGroupJoins
|
||||
final String treatedName = treatedPath.getTreatTarget().getHibernateEntityName();
|
||||
final TableGroup tableGroup = getFromClauseIndex().findTableGroup( wrappedPath.getNavigablePath() );
|
||||
registerEntityNameUsage( tableGroup, EntityNameUse.TREAT, treatedName );
|
||||
registerEntityNameUsage( tableGroup, EntityNameUse.TREAT, treatTarget.getTypeName(), false );
|
||||
}
|
||||
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
|
||||
// if the column of the basic valued path is shared between subclasses
|
||||
if ( persister.isSharedColumn( basicPath.getColumnReference().getColumnExpression() ) ) {
|
||||
return createCaseExpression( wrappedPath, treatedPath.getTreatTarget(), expression );
|
||||
return createCaseExpression( wrappedPath, (EntityDomainType<?>) treatTarget, expression );
|
||||
}
|
||||
}
|
||||
return expression;
|
||||
|
@ -5219,40 +5260,67 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
|||
Predicate predicate = null;
|
||||
for ( Map.Entry<TableGroup, Map<String, EntityNameUse>> entry : conjunctTreatUsages.entrySet() ) {
|
||||
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 Set<String> typeNames;
|
||||
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();
|
||||
embeddableMapping = null;
|
||||
}
|
||||
else if ( modelPart instanceof EmbeddableValuedModelPart ) {
|
||||
embeddableMapping = ( (EmbeddableValuedModelPart) modelPart ).getEmbeddableTypeDescriptor();
|
||||
entityMapping = null;
|
||||
}
|
||||
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
|
||||
// allow null discriminator values to maintain correct semantics
|
||||
final TableGroupJoin join = getParentTableGroupJoin( tableGroup );
|
||||
final boolean allowNulls = join != null && ( join.getJoinType() == SqlAstJoinType.LEFT || join.getJoinType() == SqlAstJoinType.FULL );
|
||||
registerTypeUsage( tableGroup );
|
||||
predicate = combinePredicates(
|
||||
predicate,
|
||||
createTreatTypeRestriction(
|
||||
typeExpression,
|
||||
entityNames,
|
||||
allowNulls
|
||||
typeNames,
|
||||
allowNulls,
|
||||
entityMapping != null
|
||||
)
|
||||
);
|
||||
}
|
||||
|
@ -5334,6 +5402,22 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
|||
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) {
|
||||
final AbstractEntityPersister entityDescriptor = (AbstractEntityPersister) domainModel.findEntityDescriptor( treatTarget.getHibernateEntityName() );
|
||||
if ( entityDescriptor.isPolymorphic() && lhs.getNodeType() != treatTarget ) {
|
||||
|
@ -5351,26 +5435,28 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
|||
return createTreatTypeRestriction(
|
||||
DiscriminatorPathInterpretation.from( discriminatorSqmPath, this ),
|
||||
subclassEntityNames,
|
||||
false
|
||||
false,
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
private Predicate createTreatTypeRestriction(
|
||||
Expression typeExpression,
|
||||
Set<String> subclassEntityNames,
|
||||
boolean allowNulls) {
|
||||
SqmPathInterpretation<?> typeExpression,
|
||||
Set<String> subtypeNames,
|
||||
boolean allowNulls,
|
||||
boolean entity) {
|
||||
final Predicate discriminatorPredicate;
|
||||
if ( subclassEntityNames.size() == 1 ) {
|
||||
if ( subtypeNames.size() == 1 ) {
|
||||
discriminatorPredicate = new ComparisonPredicate(
|
||||
typeExpression,
|
||||
ComparisonOperator.EQUAL,
|
||||
new EntityTypeLiteral( domainModel.findEntityDescriptor( subclassEntityNames.iterator().next() ) )
|
||||
getTypeLiteral( typeExpression, subtypeNames.iterator().next(), entity )
|
||||
);
|
||||
}
|
||||
else {
|
||||
final List<Expression> typeLiterals = new ArrayList<>( subclassEntityNames.size() );
|
||||
for ( String subclassEntityName : subclassEntityNames ) {
|
||||
typeLiterals.add( new EntityTypeLiteral( domainModel.findEntityDescriptor( subclassEntityName ) ) );
|
||||
final List<Expression> typeLiterals = new ArrayList<>( subtypeNames.size() );
|
||||
for ( String subtypeName : subtypeNames ) {
|
||||
typeLiterals.add( getTypeLiteral( typeExpression, subtypeName, entity ) );
|
||||
}
|
||||
discriminatorPredicate = new InListPredicate( typeExpression, typeLiterals );
|
||||
}
|
||||
|
@ -5384,6 +5470,22 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
|||
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() {
|
||||
final Supplier<MappingModelExpressible<?>> inferableTypeAccess = inferrableTypeAccessStack.getCurrent();
|
||||
if ( inTypeInference || inferableTypeAccess == null ) {
|
||||
|
@ -7130,6 +7232,16 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
|||
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
|
||||
public Expression visitAnyDiscriminatorTypeValueExpression(SqmAnyDiscriminatorValue<?> expression) {
|
||||
|
@ -7278,7 +7390,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
|||
disjunctEntityNameUsesArray = new Map[predicate.getPredicates().size()];
|
||||
entityNameUsesToPropagate = previousTableGroupEntityNameUses == null
|
||||
? new IdentityHashMap<>()
|
||||
: previousTableGroupEntityNameUses;
|
||||
: new IdentityHashMap<>( previousTableGroupEntityNameUses );
|
||||
}
|
||||
if ( i == 0 ) {
|
||||
// Collect the table groups for which filters are registered
|
||||
|
@ -7420,48 +7532,56 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
|||
return disjunction;
|
||||
}
|
||||
|
||||
// Build the intersection of the conjunct treat usages,
|
||||
// so that we can push that up and infer during pruning, which entity subclasses can be omitted
|
||||
final Iterator<Map.Entry<TableGroup, Map<String, EntityNameUse>>> iterator = tableGroupEntityNameUses.entrySet().iterator();
|
||||
while ( iterator.hasNext() ) {
|
||||
final Map.Entry<TableGroup, Map<String, EntityNameUse>> entry = iterator.next();
|
||||
final Map<String, EntityNameUse> intersected = new HashMap<>( entry.getValue() );
|
||||
entry.setValue( intersected );
|
||||
boolean remove = false;
|
||||
for ( Map<TableGroup, Map<String, EntityNameUse>> conjunctTreatUsages : disjunctEntityNameUsesArray ) {
|
||||
final Map<String, EntityNameUse> entityNames;
|
||||
if ( conjunctTreatUsages == null || ( entityNames = conjunctTreatUsages.get( entry.getKey() ) ) == null ) {
|
||||
remove = true;
|
||||
continue;
|
||||
}
|
||||
// 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();
|
||||
if ( !tableGroupEntityNameUses.isEmpty() ) {
|
||||
// Build the intersection of the conjunct treat usages,
|
||||
// so that we can push that up and infer during pruning, which entity subclasses can be omitted
|
||||
final Iterator<Map.Entry<TableGroup, Map<String, EntityNameUse>>> iterator = tableGroupEntityNameUses.entrySet().iterator();
|
||||
while ( iterator.hasNext() ) {
|
||||
final Map.Entry<TableGroup, Map<String, EntityNameUse>> entry = iterator.next();
|
||||
final Map<String, EntityNameUse> intersected = new HashMap<>( entry.getValue() );
|
||||
entry.setValue( intersected );
|
||||
boolean remove = false;
|
||||
for ( Map<TableGroup, Map<String, EntityNameUse>> conjunctTreatUsages : disjunctEntityNameUsesArray ) {
|
||||
final Map<String, EntityNameUse> entityNames;
|
||||
if ( conjunctTreatUsages == null || ( entityNames = conjunctTreatUsages.get( entry.getKey() ) ) == null ) {
|
||||
remove = true;
|
||||
break;
|
||||
}
|
||||
else {
|
||||
// Possibly downgrade a FILTER use to EXPRESSION if one of the disjunctions does not use FILTER
|
||||
intersectedEntry.setValue( intersectedUseKind.weaker( useKind ) );
|
||||
// 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 {
|
||||
// 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 ) {
|
||||
iterator.remove();
|
||||
if ( 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
|
||||
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
|
||||
for ( Map.Entry<TableGroup, Map<String, EntityNameUse>> entry : entityNameUsesToPropagate.entrySet() ) {
|
||||
final Map<String, EntityNameUse> entityNameUses = tableGroupEntityNameUses.putIfAbsent(
|
||||
|
@ -7638,7 +7764,11 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
|
|||
List<EntityTypeLiteral> literalExpressions,
|
||||
boolean inclusive) {
|
||||
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 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
|
||||
|
|
|
@ -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.update.Assignable;
|
||||
|
||||
import static jakarta.persistence.metamodel.Type.PersistenceType.ENTITY;
|
||||
import static org.hibernate.internal.util.NullnessUtil.castNonNull;
|
||||
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() );
|
||||
EntityMappingType treatTarget = null;
|
||||
final ModelPartContainer modelPartContainer;
|
||||
if ( lhs instanceof SqmTreatedPath<?, ?> ) {
|
||||
final EntityDomainType<?> treatTargetDomainType = ( (SqmTreatedPath<?, ?>) lhs ).getTreatTarget();
|
||||
if ( lhs instanceof SqmTreatedPath<?, ?> && ( (SqmTreatedPath<?, ?>) lhs ).getTreatTarget().getPersistenceType() == ENTITY ) {
|
||||
final EntityDomainType<?> treatTargetDomainType = (EntityDomainType<?>) ( (SqmTreatedPath<?, ?>) lhs ).getTreatTarget();
|
||||
|
||||
final MappingMetamodel mappingMetamodel = sqlAstCreationState.getCreationContext()
|
||||
.getSessionFactory()
|
||||
|
|
|
@ -13,6 +13,8 @@ import org.hibernate.metamodel.mapping.EntityValuedModelPart;
|
|||
import org.hibernate.metamodel.mapping.JdbcMapping;
|
||||
import org.hibernate.metamodel.mapping.ModelPartContainer;
|
||||
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.query.results.ResultSetMappingSqlSelection;
|
||||
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.spi.TypeConfiguration;
|
||||
|
||||
import static org.hibernate.query.sqm.internal.SqmMappingModelHelper.resolveMappingModelExpressible;
|
||||
|
||||
/**
|
||||
* SqmPathInterpretation and DomainResultProducer implementation for entity discriminator
|
||||
*
|
||||
|
@ -58,22 +62,38 @@ public class DiscriminatorPathInterpretation<T> extends AbstractSqmPathInterpret
|
|||
}
|
||||
|
||||
public static SqmPathInterpretation<?> from(
|
||||
EntityDiscriminatorSqmPath path,
|
||||
DiscriminatorSqmPath<?> path,
|
||||
SqmToSqlAstConverter converter) {
|
||||
assert path.getEntityDescriptor().hasSubclasses();
|
||||
|
||||
final NavigablePath navigablePath = path.getNavigablePath();
|
||||
final TableGroup tableGroup = converter.getFromClauseAccess().getTableGroup( navigablePath.getParent() );
|
||||
final ModelPartContainer modelPart = tableGroup.getModelPart();
|
||||
final EntityMappingType entityMapping;
|
||||
if ( modelPart instanceof EntityValuedModelPart ) {
|
||||
entityMapping = ( (EntityValuedModelPart) modelPart ).getEntityMappingType();
|
||||
|
||||
if ( path instanceof EntityDiscriminatorSqmPath<?> ) {
|
||||
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 {
|
||||
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() {
|
||||
|
|
|
@ -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.update.Assignable;
|
||||
|
||||
import static jakarta.persistence.metamodel.Type.PersistenceType.ENTITY;
|
||||
import static org.hibernate.query.sqm.internal.SqmUtil.getTargetMappingIfNeeded;
|
||||
|
||||
/**
|
||||
|
@ -50,16 +51,14 @@ public class EmbeddableValuedPathInterpretation<T> extends AbstractSqmPathInterp
|
|||
.getSessionFactory()
|
||||
.getRuntimeMetamodels()
|
||||
.getMappingMetamodel();
|
||||
if ( lhs instanceof SqmTreatedPath ) {
|
||||
//noinspection rawtypes
|
||||
final EntityDomainType<?> treatTargetDomainType = ( (SqmTreatedPath) lhs ).getTreatTarget();
|
||||
if ( lhs instanceof SqmTreatedPath<?, ?> && ( (SqmTreatedPath<?, ?>) lhs ).getTreatTarget().getPersistenceType() == ENTITY ) {
|
||||
final EntityDomainType<?> treatTargetDomainType = (EntityDomainType<?>) ( (SqmTreatedPath<?, ?>) lhs ).getTreatTarget();
|
||||
treatTarget = mappingMetamodel.findEntityDescriptor( treatTargetDomainType.getHibernateEntityName() );
|
||||
}
|
||||
else if ( lhs.getNodeType() instanceof EntityDomainType ) {
|
||||
//noinspection rawtypes
|
||||
final EntityDomainType<?> entityDomainType = (EntityDomainType) lhs.getNodeType();
|
||||
treatTarget = mappingMetamodel.findEntityDescriptor( entityDomainType.getHibernateEntityName() );
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -286,22 +286,16 @@ public abstract class AbstractSqmFrom<O,T> extends AbstractSqmPath<T> implements
|
|||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasTreats() {
|
||||
return treats != null && !treats.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<SqmFrom<?, ?>> getSqmTreats() {
|
||||
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 ) {
|
||||
for ( SqmFrom<?, ?> treat : treats ) {
|
||||
if ( treat.getModel() == targetType ) {
|
||||
if ( treat.getExplicitAlias() == null && alias == null
|
||||
|| Objects.equals( treat.getExplicitAlias(), alias ) ) {
|
||||
if ( Objects.equals( treat.getExplicitAlias(), alias ) ) {
|
||||
//noinspection unchecked
|
||||
return (X) treat;
|
||||
}
|
||||
|
|
|
@ -17,6 +17,7 @@ import org.hibernate.internal.util.NullnessUtil;
|
|||
import org.hibernate.metamodel.mapping.CollectionPart;
|
||||
import org.hibernate.metamodel.mapping.EntityDiscriminatorMapping;
|
||||
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.ManagedDomainType;
|
||||
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) {
|
||||
final NavigablePath treat = getNavigablePath().treatAs( treatTarget.getHibernateEntityName() );
|
||||
protected <S extends T> SqmTreatedPath<T, S> getTreatedPath(ManagedDomainType<S> treatTarget) {
|
||||
final NavigablePath treat = getNavigablePath().treatAs( treatTarget.getTypeName() );
|
||||
//noinspection unchecked
|
||||
SqmTreatedPath<T, S> path = (SqmTreatedPath<T, S>) getLhs().getReusablePath( treat.getLocalName() );
|
||||
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 );
|
||||
}
|
||||
return path;
|
||||
|
|
|
@ -10,6 +10,8 @@ import java.util.Collection;
|
|||
|
||||
import org.hibernate.metamodel.model.domain.BagPersistentAttribute;
|
||||
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.spi.NavigablePath;
|
||||
import org.hibernate.query.criteria.JpaCollectionJoin;
|
||||
|
@ -116,8 +118,8 @@ public class SqmBagJoin<O, E> extends AbstractSqmPluralJoin<O,Collection<E>, E>
|
|||
}
|
||||
|
||||
@Override
|
||||
public <S extends E> SqmTreatedBagJoin<O, E, S> treatAs(Class<S> treatAsType) {
|
||||
return treatAs( nodeBuilder().getDomainModel().entity( treatAsType ) );
|
||||
public <S extends E> SqmTreatedBagJoin<O, E, S> treatAs(Class<S> treatJavaType) {
|
||||
return treatAs( treatJavaType, null );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -127,7 +129,7 @@ public class SqmBagJoin<O, E> extends AbstractSqmPluralJoin<O,Collection<E>, E>
|
|||
|
||||
@Override
|
||||
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
|
||||
|
@ -136,8 +138,18 @@ public class SqmBagJoin<O, E> extends AbstractSqmPluralJoin<O,Collection<E>, E>
|
|||
}
|
||||
|
||||
@Override
|
||||
public <S extends E> SqmTreatedBagJoin<O,E,S> treatAs(Class<S> treatJavaType, String alias, boolean fetch) {
|
||||
return treatAs( nodeBuilder().getDomainModel().entity( treatJavaType ), alias, fetch );
|
||||
public <S extends E> SqmTreatedBagJoin<O, E, S> treatAs(Class<S> treatJavaType, String alias, boolean 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
|
||||
|
|
|
@ -99,12 +99,12 @@ public class SqmEmbeddedValuedSimplePath<T>
|
|||
|
||||
@Override
|
||||
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
|
||||
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
|
||||
|
|
|
@ -78,8 +78,8 @@ public class SqmEntityValuedSimplePath<T> extends AbstractSqmSimplePath<T> {
|
|||
// }
|
||||
|
||||
@Override
|
||||
public <S extends T> SqmTreatedSimplePath<T,S> treatAs(Class<S> treatJavaType) throws PathException {
|
||||
return (SqmTreatedSimplePath<T, S>) treatAs( nodeBuilder().getDomainModel().entity( treatJavaType ) );
|
||||
public <S extends T> SqmTreatedEntityValuedSimplePath<T,S> treatAs(Class<S> treatJavaType) throws PathException {
|
||||
return (SqmTreatedEntityValuedSimplePath<T, S>) treatAs( nodeBuilder().getDomainModel().entity( treatJavaType ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -10,6 +10,8 @@ import java.util.List;
|
|||
|
||||
import org.hibernate.metamodel.model.domain.EntityDomainType;
|
||||
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.spi.NavigablePath;
|
||||
import org.hibernate.query.criteria.JpaExpression;
|
||||
|
@ -123,8 +125,8 @@ public class SqmListJoin<O,E>
|
|||
}
|
||||
|
||||
@Override
|
||||
public <S extends E> SqmTreatedListJoin<O,E,S> treatAs(Class<S> treatAsType) {
|
||||
return treatAs( nodeBuilder().getDomainModel().entity( treatAsType ), null );
|
||||
public <S extends E> SqmTreatedListJoin<O,E,S> treatAs(Class<S> treatJavaType) {
|
||||
return treatAs( treatJavaType, null );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -134,7 +136,7 @@ public class SqmListJoin<O,E>
|
|||
|
||||
@Override
|
||||
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
|
||||
|
@ -143,8 +145,18 @@ public class SqmListJoin<O,E>
|
|||
}
|
||||
|
||||
@Override
|
||||
public <S extends E> SqmTreatedListJoin<O,E,S> treatAs(Class<S> treatJavaType, String alias, boolean fetch) {
|
||||
return treatAs( nodeBuilder().getDomainModel().entity( treatJavaType ), alias, fetch );
|
||||
public <S extends E> SqmTreatedListJoin<O, E, S> treatAs(Class<S> treatJavaType, String alias, boolean 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
|
||||
|
|
|
@ -11,7 +11,9 @@ import jakarta.persistence.criteria.Expression;
|
|||
import jakarta.persistence.criteria.Predicate;
|
||||
|
||||
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.TreatableDomainType;
|
||||
import org.hibernate.query.sqm.SemanticQueryWalker;
|
||||
import org.hibernate.spi.NavigablePath;
|
||||
import org.hibernate.query.criteria.JpaExpression;
|
||||
|
@ -136,7 +138,7 @@ public class SqmMapJoin<O, K, V>
|
|||
|
||||
@Override
|
||||
public <S extends V> SqmTreatedMapJoin<O, K, V, S> treatAs(Class<S> treatJavaType) {
|
||||
return treatAs( nodeBuilder().getDomainModel().entity( treatJavaType ) );
|
||||
return treatAs( treatJavaType, null );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -146,7 +148,7 @@ public class SqmMapJoin<O, K, V>
|
|||
|
||||
@Override
|
||||
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
|
||||
|
@ -156,7 +158,17 @@ public class SqmMapJoin<O, K, V>
|
|||
|
||||
@Override
|
||||
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
|
||||
|
|
|
@ -171,13 +171,13 @@ public class SqmPluralValuedSimplePath<E> extends AbstractSqmSimplePath<E> {
|
|||
}
|
||||
|
||||
@Override
|
||||
public <S extends E> SqmTreatedSimplePath<E,S> treatAs(Class<S> treatJavaType) throws PathException {
|
||||
return (SqmTreatedSimplePath<E, S>) treatAs( nodeBuilder().getDomainModel().entity( treatJavaType ) );
|
||||
public <S extends E> SqmTreatedPath<E, S> treatAs(Class<S> treatJavaType) throws PathException {
|
||||
throw new UnsupportedOperationException( "Cannot treat plural valued simple paths" );
|
||||
}
|
||||
|
||||
@Override
|
||||
public <S extends E> SqmTreatedPath<E, S> treatAs(EntityDomainType<S> treatTarget) throws PathException {
|
||||
return getTreatedPath( treatTarget );
|
||||
public <S extends E> SqmTreatedEntityValuedSimplePath<E, S> treatAs(EntityDomainType<S> treatTarget) throws PathException {
|
||||
throw new UnsupportedOperationException( "Cannot treat plural valued simple paths" );
|
||||
}
|
||||
|
||||
// @Override
|
||||
|
|
|
@ -9,7 +9,9 @@ package org.hibernate.query.sqm.tree.domain;
|
|||
import java.util.Set;
|
||||
|
||||
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.TreatableDomainType;
|
||||
import org.hibernate.query.sqm.SemanticQueryWalker;
|
||||
import org.hibernate.spi.NavigablePath;
|
||||
import org.hibernate.query.criteria.JpaExpression;
|
||||
|
@ -116,8 +118,8 @@ public class SqmSetJoin<O, E>
|
|||
}
|
||||
|
||||
@Override
|
||||
public <S extends E> SqmTreatedSetJoin<O,E,S> treatAs(Class<S> treatAsType) {
|
||||
return treatAs( nodeBuilder().getDomainModel().entity( treatAsType ) );
|
||||
public <S extends E> SqmTreatedSetJoin<O,E,S> treatAs(Class<S> treatJavaType) {
|
||||
return treatAs( treatJavaType, null );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -127,7 +129,7 @@ public class SqmSetJoin<O, E>
|
|||
|
||||
@Override
|
||||
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
|
||||
|
@ -136,8 +138,18 @@ public class SqmSetJoin<O, E>
|
|||
}
|
||||
|
||||
@Override
|
||||
public <S extends E> SqmTreatedSetJoin<O,E,S> treatAs(Class<S> treatJavaType, String alias, boolean fetch) {
|
||||
return treatAs( nodeBuilder().getDomainModel().entity( treatJavaType ), alias, fetch );
|
||||
public <S extends E> SqmTreatedSetJoin<O, E, S> treatAs(Class<S> treatJavaType, String alias, boolean 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
|
||||
|
|
|
@ -8,8 +8,11 @@ package org.hibernate.query.sqm.tree.domain;
|
|||
|
||||
import java.util.Locale;
|
||||
|
||||
import org.hibernate.metamodel.model.domain.EmbeddableDomainType;
|
||||
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.TreatableDomainType;
|
||||
import org.hibernate.query.sqm.SemanticQueryWalker;
|
||||
import org.hibernate.spi.NavigablePath;
|
||||
import org.hibernate.query.hql.spi.SqmCreationProcessingState;
|
||||
|
@ -95,7 +98,7 @@ public class SqmSingularJoin<O,T> extends AbstractSqmAttributeJoin<O,T> {
|
|||
|
||||
@Override
|
||||
public <S extends T> SqmTreatedSingularJoin<O,T,S> treatAs(Class<S> treatJavaType) {
|
||||
return treatAs( nodeBuilder().getDomainModel().entity( treatJavaType ) );
|
||||
return treatAs( treatJavaType, null );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -105,7 +108,7 @@ public class SqmSingularJoin<O,T> extends AbstractSqmAttributeJoin<O,T> {
|
|||
|
||||
@Override
|
||||
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
|
||||
|
@ -115,7 +118,17 @@ public class SqmSingularJoin<O,T> extends AbstractSqmAttributeJoin<O,T> {
|
|||
|
||||
@Override
|
||||
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
|
||||
|
|
|
@ -8,7 +8,7 @@ package org.hibernate.query.sqm.tree.domain;
|
|||
|
||||
import org.hibernate.metamodel.mapping.CollectionPart;
|
||||
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.sqm.SqmPathSource;
|
||||
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> {
|
||||
private final SqmBagJoin<O, T> wrappedPath;
|
||||
private final EntityDomainType<S> treatTarget;
|
||||
private final TreatableDomainType<S> treatTarget;
|
||||
|
||||
public SqmTreatedBagJoin(
|
||||
SqmBagJoin<O, T> wrappedPath,
|
||||
EntityDomainType<S> treatTarget,
|
||||
TreatableDomainType<S> treatTarget,
|
||||
String alias) {
|
||||
this( wrappedPath, treatTarget, alias, false );
|
||||
}
|
||||
|
||||
public SqmTreatedBagJoin(
|
||||
SqmBagJoin<O, T> wrappedPath,
|
||||
EntityDomainType<S> treatTarget,
|
||||
TreatableDomainType<S> treatTarget,
|
||||
String alias,
|
||||
boolean fetched) {
|
||||
//noinspection unchecked
|
||||
|
@ -39,7 +39,7 @@ public class SqmTreatedBagJoin<O,T, S extends T> extends SqmBagJoin<O,S> impleme
|
|||
wrappedPath.getLhs(),
|
||||
wrappedPath.getNavigablePath()
|
||||
.append( CollectionPart.Nature.ELEMENT.getName() )
|
||||
.treatAs( treatTarget.getHibernateEntityName(), alias ),
|
||||
.treatAs( treatTarget.getTypeName(), alias ),
|
||||
(BagPersistentAttribute<O, S>) wrappedPath.getAttribute(),
|
||||
alias,
|
||||
wrappedPath.getSqmJoinType(),
|
||||
|
@ -53,16 +53,13 @@ public class SqmTreatedBagJoin<O,T, S extends T> extends SqmBagJoin<O,S> impleme
|
|||
private SqmTreatedBagJoin(
|
||||
NavigablePath navigablePath,
|
||||
SqmBagJoin<O, T> wrappedPath,
|
||||
EntityDomainType<S> treatTarget,
|
||||
TreatableDomainType<S> treatTarget,
|
||||
String alias,
|
||||
boolean fetched) {
|
||||
//noinspection unchecked
|
||||
super(
|
||||
wrappedPath.getLhs(),
|
||||
wrappedPath.getNavigablePath().treatAs(
|
||||
treatTarget.getHibernateEntityName(),
|
||||
alias
|
||||
),
|
||||
navigablePath,
|
||||
(BagPersistentAttribute<O, S>) wrappedPath.getAttribute(),
|
||||
alias,
|
||||
wrappedPath.getSqmJoinType(),
|
||||
|
@ -99,7 +96,7 @@ public class SqmTreatedBagJoin<O,T, S extends T> extends SqmBagJoin<O,S> impleme
|
|||
}
|
||||
|
||||
@Override
|
||||
public EntityDomainType<S> getTreatTarget() {
|
||||
public TreatableDomainType<S> getTreatTarget() {
|
||||
return treatTarget;
|
||||
}
|
||||
|
||||
|
@ -109,7 +106,7 @@ public class SqmTreatedBagJoin<O,T, S extends T> extends SqmBagJoin<O,S> impleme
|
|||
}
|
||||
|
||||
@Override
|
||||
public EntityDomainType<S> getReferencedPathSource() {
|
||||
public TreatableDomainType<S> getReferencedPathSource() {
|
||||
return treatTarget;
|
||||
}
|
||||
|
||||
|
@ -128,7 +125,7 @@ public class SqmTreatedBagJoin<O,T, S extends T> extends SqmBagJoin<O,S> impleme
|
|||
sb.append( "treat(" );
|
||||
wrappedPath.appendHqlString( sb );
|
||||
sb.append( " as " );
|
||||
sb.append( treatTarget.getName() );
|
||||
sb.append( treatTarget.getTypeName() );
|
||||
sb.append( ')' );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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( ')' );
|
||||
}
|
||||
}
|
|
@ -17,14 +17,14 @@ import org.hibernate.spi.NavigablePath;
|
|||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public class SqmTreatedSimplePath<T, S extends T>
|
||||
public class SqmTreatedEntityValuedSimplePath<T, S extends T>
|
||||
extends SqmEntityValuedSimplePath<S>
|
||||
implements SqmSimplePath<S>, SqmTreatedPath<T,S> {
|
||||
|
||||
private final EntityDomainType<S> treatTarget;
|
||||
private final SqmPath<T> wrappedPath;
|
||||
|
||||
public SqmTreatedSimplePath(
|
||||
public SqmTreatedEntityValuedSimplePath(
|
||||
SqmPluralValuedSimplePath<T> wrappedPath,
|
||||
EntityDomainType<S> treatTarget,
|
||||
NodeBuilder nodeBuilder) {
|
||||
|
@ -41,7 +41,7 @@ public class SqmTreatedSimplePath<T, S extends T>
|
|||
this.wrappedPath = wrappedPath;
|
||||
}
|
||||
|
||||
public SqmTreatedSimplePath(
|
||||
public SqmTreatedEntityValuedSimplePath(
|
||||
SqmPath<T> wrappedPath,
|
||||
EntityDomainType<S> treatTarget,
|
||||
NodeBuilder nodeBuilder) {
|
||||
|
@ -58,7 +58,7 @@ public class SqmTreatedSimplePath<T, S extends T>
|
|||
this.wrappedPath = wrappedPath;
|
||||
}
|
||||
|
||||
private SqmTreatedSimplePath(
|
||||
private SqmTreatedEntityValuedSimplePath(
|
||||
NavigablePath navigablePath,
|
||||
SqmPath<T> wrappedPath,
|
||||
EntityDomainType<S> treatTarget,
|
||||
|
@ -75,15 +75,15 @@ public class SqmTreatedSimplePath<T, S extends T>
|
|||
}
|
||||
|
||||
@Override
|
||||
public SqmTreatedSimplePath<T, S> copy(SqmCopyContext context) {
|
||||
final SqmTreatedSimplePath<T, S> existing = context.getCopy( this );
|
||||
public SqmTreatedEntityValuedSimplePath<T, S> copy(SqmCopyContext context) {
|
||||
final SqmTreatedEntityValuedSimplePath<T, S> existing = context.getCopy( this );
|
||||
if ( existing != null ) {
|
||||
return existing;
|
||||
}
|
||||
|
||||
final SqmTreatedSimplePath<T, S> path = context.registerCopy(
|
||||
final SqmTreatedEntityValuedSimplePath<T, S> path = context.registerCopy(
|
||||
this,
|
||||
new SqmTreatedSimplePath<>(
|
||||
new SqmTreatedEntityValuedSimplePath<>(
|
||||
getNavigablePath(),
|
||||
wrappedPath.copy( context ),
|
||||
getTreatTarget(),
|
||||
|
@ -120,7 +120,7 @@ public class SqmTreatedSimplePath<T, S extends T>
|
|||
}
|
||||
|
||||
@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 );
|
||||
}
|
||||
|
|
@ -7,8 +7,8 @@
|
|||
package org.hibernate.query.sqm.tree.domain;
|
||||
|
||||
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.TreatableDomainType;
|
||||
import org.hibernate.query.hql.spi.SqmCreationProcessingState;
|
||||
import org.hibernate.query.hql.spi.SqmCreationState;
|
||||
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> {
|
||||
private final SqmListJoin<O,T> wrappedPath;
|
||||
private final EntityDomainType<S> treatTarget;
|
||||
private final TreatableDomainType<S> treatTarget;
|
||||
|
||||
public SqmTreatedListJoin(
|
||||
SqmListJoin<O, T> wrappedPath,
|
||||
EntityDomainType<S> treatTarget,
|
||||
TreatableDomainType<S> treatTarget,
|
||||
String alias) {
|
||||
this( wrappedPath, treatTarget, alias, false );
|
||||
}
|
||||
|
||||
public SqmTreatedListJoin(
|
||||
SqmListJoin<O, T> wrappedPath,
|
||||
EntityDomainType<S> treatTarget,
|
||||
TreatableDomainType<S> treatTarget,
|
||||
String alias,
|
||||
boolean fetched) {
|
||||
//noinspection unchecked
|
||||
|
@ -41,7 +41,7 @@ public class SqmTreatedListJoin<O,T, S extends T> extends SqmListJoin<O,S> imple
|
|||
wrappedPath.getLhs(),
|
||||
wrappedPath.getNavigablePath()
|
||||
.append( CollectionPart.Nature.ELEMENT.getName() )
|
||||
.treatAs( treatTarget.getHibernateEntityName(), alias ),
|
||||
.treatAs( treatTarget.getTypeName(), alias ),
|
||||
(ListPersistentAttribute<O, S>) wrappedPath.getAttribute(),
|
||||
alias,
|
||||
wrappedPath.getSqmJoinType(),
|
||||
|
@ -55,7 +55,7 @@ public class SqmTreatedListJoin<O,T, S extends T> extends SqmListJoin<O,S> imple
|
|||
private SqmTreatedListJoin(
|
||||
NavigablePath navigablePath,
|
||||
SqmListJoin<O, T> wrappedPath,
|
||||
EntityDomainType<S> treatTarget,
|
||||
TreatableDomainType<S> treatTarget,
|
||||
String alias,
|
||||
boolean fetched) {
|
||||
//noinspection unchecked
|
||||
|
@ -98,7 +98,7 @@ public class SqmTreatedListJoin<O,T, S extends T> extends SqmListJoin<O,S> imple
|
|||
}
|
||||
|
||||
@Override
|
||||
public EntityDomainType<S> getTreatTarget() {
|
||||
public TreatableDomainType<S> getTreatTarget() {
|
||||
return treatTarget;
|
||||
}
|
||||
|
||||
|
@ -108,7 +108,7 @@ public class SqmTreatedListJoin<O,T, S extends T> extends SqmListJoin<O,S> imple
|
|||
}
|
||||
|
||||
@Override
|
||||
public EntityDomainType<S> getReferencedPathSource() {
|
||||
public TreatableDomainType<S> getReferencedPathSource() {
|
||||
return treatTarget;
|
||||
}
|
||||
|
||||
|
@ -135,7 +135,7 @@ public class SqmTreatedListJoin<O,T, S extends T> extends SqmListJoin<O,S> imple
|
|||
sb.append( "treat(" );
|
||||
wrappedPath.appendHqlString( sb );
|
||||
sb.append( " as " );
|
||||
sb.append( treatTarget.getName() );
|
||||
sb.append( treatTarget.getTypeName() );
|
||||
sb.append( ')' );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
package org.hibernate.query.sqm.tree.domain;
|
||||
|
||||
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.sqm.SqmPathSource;
|
||||
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> {
|
||||
private final SqmMapJoin<O, K, V> wrappedPath;
|
||||
private final EntityDomainType<S> treatTarget;
|
||||
private final TreatableDomainType<S> treatTarget;
|
||||
|
||||
public SqmTreatedMapJoin(
|
||||
SqmMapJoin<O, K, V> wrappedPath,
|
||||
EntityDomainType<S> treatTarget,
|
||||
TreatableDomainType<S> treatTarget,
|
||||
String alias) {
|
||||
this( wrappedPath, treatTarget, alias, false );
|
||||
}
|
||||
|
||||
public SqmTreatedMapJoin(
|
||||
SqmMapJoin<O, K, V> wrappedPath,
|
||||
EntityDomainType<S> treatTarget,
|
||||
TreatableDomainType<S> treatTarget,
|
||||
String alias,
|
||||
boolean fetched) {
|
||||
//noinspection unchecked
|
||||
|
@ -37,7 +37,7 @@ public class SqmTreatedMapJoin<O, K, V, S extends V> extends SqmMapJoin<O, K, S>
|
|||
wrappedPath.getLhs(),
|
||||
wrappedPath.getNavigablePath()
|
||||
.append( CollectionPart.Nature.ELEMENT.getName() )
|
||||
.treatAs( treatTarget.getHibernateEntityName(), alias ),
|
||||
.treatAs( treatTarget.getTypeName(), alias ),
|
||||
( (SqmMapJoin<O, K, S>) wrappedPath ).getModel(),
|
||||
alias,
|
||||
wrappedPath.getSqmJoinType(),
|
||||
|
@ -51,7 +51,7 @@ public class SqmTreatedMapJoin<O, K, V, S extends V> extends SqmMapJoin<O, K, S>
|
|||
private SqmTreatedMapJoin(
|
||||
NavigablePath navigablePath,
|
||||
SqmMapJoin<O, K, V> wrappedPath,
|
||||
EntityDomainType<S> treatTarget,
|
||||
TreatableDomainType<S> treatTarget,
|
||||
String alias,
|
||||
boolean fetched) {
|
||||
//noinspection unchecked
|
||||
|
@ -94,7 +94,7 @@ public class SqmTreatedMapJoin<O, K, V, S extends V> extends SqmMapJoin<O, K, S>
|
|||
}
|
||||
|
||||
@Override
|
||||
public EntityDomainType<S> getTreatTarget() {
|
||||
public TreatableDomainType<S> getTreatTarget() {
|
||||
return treatTarget;
|
||||
}
|
||||
|
||||
|
@ -104,7 +104,7 @@ public class SqmTreatedMapJoin<O, K, V, S extends V> extends SqmMapJoin<O, K, S>
|
|||
}
|
||||
|
||||
@Override
|
||||
public EntityDomainType<S> getReferencedPathSource() {
|
||||
public TreatableDomainType<S> getReferencedPathSource() {
|
||||
return treatTarget;
|
||||
}
|
||||
|
||||
|
@ -127,7 +127,7 @@ public class SqmTreatedMapJoin<O, K, V, S extends V> extends SqmMapJoin<O, K, S>
|
|||
sb.append( "treat(" );
|
||||
wrappedPath.appendHqlString( sb );
|
||||
sb.append( " as " );
|
||||
sb.append( treatTarget.getName() );
|
||||
sb.append( treatTarget.getTypeName() );
|
||||
sb.append( ')' );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,14 +6,13 @@
|
|||
*/
|
||||
package org.hibernate.query.sqm.tree.domain;
|
||||
|
||||
import org.hibernate.metamodel.model.domain.EntityDomainType;
|
||||
import org.hibernate.query.sqm.SqmPathSource;
|
||||
import org.hibernate.metamodel.model.domain.ManagedDomainType;
|
||||
|
||||
/**
|
||||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface SqmTreatedPath<T, S extends T> extends SqmPathWrapper<T, S> {
|
||||
EntityDomainType<S> getTreatTarget();
|
||||
ManagedDomainType<S> getTreatTarget();
|
||||
|
||||
@Override
|
||||
SqmPath<T> getWrappedPath();
|
||||
|
|
|
@ -7,7 +7,7 @@
|
|||
package org.hibernate.query.sqm.tree.domain;
|
||||
|
||||
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.query.hql.spi.SqmCreationProcessingState;
|
||||
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> {
|
||||
private final SqmSetJoin<O,T> wrappedPath;
|
||||
private final EntityDomainType<S> treatTarget;
|
||||
private final TreatableDomainType<S> treatTarget;
|
||||
|
||||
public SqmTreatedSetJoin(
|
||||
SqmSetJoin<O, T> wrappedPath,
|
||||
EntityDomainType<S> treatTarget,
|
||||
TreatableDomainType<S> treatTarget,
|
||||
String alias) {
|
||||
this( wrappedPath, treatTarget, alias, false );
|
||||
}
|
||||
|
||||
public SqmTreatedSetJoin(
|
||||
SqmSetJoin<O, T> wrappedPath,
|
||||
EntityDomainType<S> treatTarget,
|
||||
TreatableDomainType<S> treatTarget,
|
||||
String alias,
|
||||
boolean fetched) {
|
||||
//noinspection unchecked
|
||||
|
@ -39,7 +39,7 @@ public class SqmTreatedSetJoin<O,T, S extends T> extends SqmSetJoin<O,S> impleme
|
|||
wrappedPath.getLhs(),
|
||||
wrappedPath.getNavigablePath()
|
||||
.append( CollectionPart.Nature.ELEMENT.getName() )
|
||||
.treatAs( treatTarget.getHibernateEntityName(), alias ),
|
||||
.treatAs( treatTarget.getTypeName(), alias ),
|
||||
(SetPersistentAttribute<O, S>) wrappedPath.getAttribute(),
|
||||
alias,
|
||||
wrappedPath.getSqmJoinType(),
|
||||
|
@ -53,7 +53,7 @@ public class SqmTreatedSetJoin<O,T, S extends T> extends SqmSetJoin<O,S> impleme
|
|||
private SqmTreatedSetJoin(
|
||||
NavigablePath navigablePath,
|
||||
SqmSetJoin<O, T> wrappedPath,
|
||||
EntityDomainType<S> treatTarget,
|
||||
TreatableDomainType<S> treatTarget,
|
||||
String alias,
|
||||
boolean fetched) {
|
||||
//noinspection unchecked
|
||||
|
@ -96,7 +96,7 @@ public class SqmTreatedSetJoin<O,T, S extends T> extends SqmSetJoin<O,S> impleme
|
|||
}
|
||||
|
||||
@Override
|
||||
public EntityDomainType<S> getTreatTarget() {
|
||||
public TreatableDomainType<S> getTreatTarget() {
|
||||
return treatTarget;
|
||||
}
|
||||
|
||||
|
@ -106,7 +106,7 @@ public class SqmTreatedSetJoin<O,T, S extends T> extends SqmSetJoin<O,S> impleme
|
|||
}
|
||||
|
||||
@Override
|
||||
public EntityDomainType<S> getReferencedPathSource() {
|
||||
public TreatableDomainType<S> getReferencedPathSource() {
|
||||
return treatTarget;
|
||||
}
|
||||
|
||||
|
@ -125,7 +125,7 @@ public class SqmTreatedSetJoin<O,T, S extends T> extends SqmSetJoin<O,S> impleme
|
|||
sb.append( "treat(" );
|
||||
wrappedPath.appendHqlString( sb );
|
||||
sb.append( " as " );
|
||||
sb.append( treatTarget.getName() );
|
||||
sb.append( treatTarget.getTypeName() );
|
||||
sb.append( ')' );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,8 +6,8 @@
|
|||
*/
|
||||
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.TreatableDomainType;
|
||||
import org.hibernate.query.hql.spi.SqmCreationProcessingState;
|
||||
import org.hibernate.query.sqm.SqmPathSource;
|
||||
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> {
|
||||
private final SqmSingularJoin<O,T> wrappedPath;
|
||||
private final EntityDomainType<S> treatTarget;
|
||||
private final TreatableDomainType<S> treatTarget;
|
||||
|
||||
public SqmTreatedSingularJoin(
|
||||
SqmSingularJoin<O,T> wrappedPath,
|
||||
EntityDomainType<S> treatTarget,
|
||||
TreatableDomainType<S> treatTarget,
|
||||
String alias) {
|
||||
this( wrappedPath, treatTarget, alias, false );
|
||||
}
|
||||
|
||||
public SqmTreatedSingularJoin(
|
||||
SqmSingularJoin<O,T> wrappedPath,
|
||||
EntityDomainType<S> treatTarget,
|
||||
TreatableDomainType<S> treatTarget,
|
||||
String alias,
|
||||
boolean fetched) {
|
||||
//noinspection unchecked
|
||||
super(
|
||||
wrappedPath.getLhs(),
|
||||
wrappedPath.getNavigablePath().treatAs(
|
||||
treatTarget.getHibernateEntityName(),
|
||||
treatTarget.getTypeName(),
|
||||
alias
|
||||
),
|
||||
(SingularPersistentAttribute<O, S>) wrappedPath.getAttribute(),
|
||||
|
@ -53,7 +53,7 @@ public class SqmTreatedSingularJoin<O,T, S extends T> extends SqmSingularJoin<O,
|
|||
private SqmTreatedSingularJoin(
|
||||
NavigablePath navigablePath,
|
||||
SqmSingularJoin<O,T> wrappedPath,
|
||||
EntityDomainType<S> treatTarget,
|
||||
TreatableDomainType<S> treatTarget,
|
||||
String alias,
|
||||
boolean fetched) {
|
||||
//noinspection unchecked
|
||||
|
@ -96,7 +96,7 @@ public class SqmTreatedSingularJoin<O,T, S extends T> extends SqmSingularJoin<O,
|
|||
}
|
||||
|
||||
@Override
|
||||
public EntityDomainType<S> getTreatTarget() {
|
||||
public TreatableDomainType<S> getTreatTarget() {
|
||||
return treatTarget;
|
||||
}
|
||||
|
||||
|
@ -106,7 +106,7 @@ public class SqmTreatedSingularJoin<O,T, S extends T> extends SqmSingularJoin<O,
|
|||
}
|
||||
|
||||
@Override
|
||||
public EntityDomainType<S> getReferencedPathSource() {
|
||||
public TreatableDomainType<S> getReferencedPathSource() {
|
||||
return treatTarget;
|
||||
}
|
||||
|
||||
|
@ -125,7 +125,7 @@ public class SqmTreatedSingularJoin<O,T, S extends T> extends SqmSingularJoin<O,
|
|||
sb.append( "treat(" );
|
||||
wrappedPath.appendHqlString( sb );
|
||||
sb.append( " as " );
|
||||
sb.append( treatTarget.getName() );
|
||||
sb.append( treatTarget.getTypeName() );
|
||||
sb.append( ')' );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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() );
|
||||
}
|
||||
}
|
|
@ -8,11 +8,8 @@ package org.hibernate.query.sqm.tree.from;
|
|||
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
import jakarta.persistence.criteria.CollectionJoin;
|
||||
|
||||
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.ListAttribute;
|
||||
import jakarta.persistence.metamodel.MapAttribute;
|
||||
|
@ -20,11 +17,7 @@ import jakarta.persistence.metamodel.SetAttribute;
|
|||
import jakarta.persistence.metamodel.SingularAttribute;
|
||||
|
||||
import org.hibernate.metamodel.model.domain.EntityDomainType;
|
||||
import org.hibernate.query.PathException;
|
||||
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.tree.SqmCopyContext;
|
||||
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.SqmSingularJoin;
|
||||
|
||||
import static org.hibernate.internal.util.collections.CollectionHelper.isEmpty;
|
||||
|
||||
/**
|
||||
* 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);
|
||||
|
||||
/**
|
||||
* The treats associated with this SqmFrom
|
||||
*/
|
||||
List<SqmFrom<?, ?>> getSqmTreats();
|
||||
|
||||
default boolean hasTreats() {
|
||||
return !isEmpty( getSqmTreats() );
|
||||
}
|
||||
|
||||
@Override
|
||||
<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);
|
||||
|
||||
boolean hasTreats();
|
||||
|
||||
/**
|
||||
* The treats associated with this SqmFrom
|
||||
*/
|
||||
List<SqmFrom<?,?>> getSqmTreats();
|
||||
|
||||
|
||||
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
// JPA
|
||||
|
||||
|
|
|
@ -141,7 +141,7 @@ public class SqmFromClause implements Serializable {
|
|||
final SqmTreatedPath<?, ?> treatedPath = (SqmTreatedPath<?, ?>) sqmFrom;
|
||||
sb.append( "treat(" );
|
||||
sb.append( treatedPath.getWrappedPath().resolveAlias() );
|
||||
sb.append( " as " ).append( treatedPath.getTreatTarget().getName() ).append( ')' );
|
||||
sb.append( " as " ).append( treatedPath.getTreatTarget().getTypeName() ).append( ')' );
|
||||
}
|
||||
else {
|
||||
sb.append( sqmFrom.resolveAlias() );
|
||||
|
|
|
@ -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.Duration;
|
||||
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.Every;
|
||||
import org.hibernate.sql.ast.tree.expression.ExtractUnit;
|
||||
|
@ -167,6 +168,8 @@ public interface SqlAstWalker {
|
|||
|
||||
void visitEntityTypeLiteral(EntityTypeLiteral expression);
|
||||
|
||||
void visitEmbeddableTypeLiteral(EmbeddableTypeLiteral expression);
|
||||
|
||||
void visitTuple(SqlTuple tuple);
|
||||
|
||||
void visitCollation(Collation collation);
|
||||
|
|
|
@ -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.Duration;
|
||||
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.Every;
|
||||
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.StandardBasicTypes;
|
||||
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.jdbc.JdbcLiteralFormatter;
|
||||
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.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.TemporalUnit.NANOSECOND;
|
||||
import static org.hibernate.sql.ast.SqlTreePrinter.logSqlAst;
|
||||
|
@ -7203,6 +7206,19 @@ public abstract class AbstractSqlAstTranslator<T extends JdbcOperation> implemen
|
|||
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
|
||||
public void visitBinaryArithmeticExpression(BinaryArithmeticExpression arithmeticExpression) {
|
||||
final BinaryArithmeticOperator operator = arithmeticExpression.getOperator();
|
||||
|
|
|
@ -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.Duration;
|
||||
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.Every;
|
||||
import org.hibernate.sql.ast.tree.expression.Expression;
|
||||
|
@ -529,6 +530,10 @@ public class AbstractSqlAstWalker implements SqlAstWalker {
|
|||
public void visitEntityTypeLiteral(EntityTypeLiteral expression) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitEmbeddableTypeLiteral(EmbeddableTypeLiteral expression) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitNamedTableReference(NamedTableReference tableReference) {
|
||||
}
|
||||
|
|
|
@ -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.Duration;
|
||||
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.Every;
|
||||
import org.hibernate.sql.ast.tree.expression.Expression;
|
||||
|
@ -249,6 +250,10 @@ public class AggregateFunctionChecker extends AbstractSqlAstWalker {
|
|||
public void visitEntityTypeLiteral(EntityTypeLiteral expression) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitEmbeddableTypeLiteral(EmbeddableTypeLiteral expression) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitSqlSelectionExpression(SqlSelectionExpression expression) {
|
||||
}
|
||||
|
|
|
@ -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.Duration;
|
||||
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.Every;
|
||||
import org.hibernate.sql.ast.tree.expression.Expression;
|
||||
|
@ -215,6 +216,11 @@ public class ExpressionReplacementWalker implements SqlAstWalker {
|
|||
doReplaceExpression( expression );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitEmbeddableTypeLiteral(EmbeddableTypeLiteral expression) {
|
||||
doReplaceExpression( expression );
|
||||
}
|
||||
|
||||
@Override
|
||||
public void visitTuple(SqlTuple tuple) {
|
||||
doReplaceExpression( tuple );
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -800,8 +800,8 @@ public class ComponentType extends AbstractType implements CompositeTypeImplemen
|
|||
final EmbeddableRepresentationStrategy representationStrategy = embeddableTypeDescriptor().getRepresentationStrategy();
|
||||
final EmbeddableInstantiator instantiator;
|
||||
if ( embeddableTypeDescriptor().isPolymorphic() ) {
|
||||
// the discriminator here is the composite class name because it gets converted to the domain type when extracted
|
||||
instantiator = representationStrategy.getInstantiatorForClass( (String) value[value.length - 1] );
|
||||
// the discriminator here is the composite class because it gets converted to the domain type when extracted
|
||||
instantiator = representationStrategy.getInstantiatorForClass( ( (Class<?>) value[value.length - 1] ).getName() );
|
||||
}
|
||||
else {
|
||||
instantiator = representationStrategy.getInstantiator();
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
*/
|
||||
package org.hibernate.orm.test.inheritance.embeddable;
|
||||
|
||||
import org.hibernate.annotations.Imported;
|
||||
|
||||
import jakarta.persistence.DiscriminatorValue;
|
||||
import jakarta.persistence.Embeddable;
|
||||
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
*/
|
||||
package org.hibernate.orm.test.inheritance.embeddable;
|
||||
|
||||
import org.hibernate.annotations.Imported;
|
||||
|
||||
import jakarta.persistence.Embeddable;
|
||||
|
||||
/**
|
||||
|
|
|
@ -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
|
||||
public void setUp(SessionFactoryScope scope) {
|
||||
scope.inTransaction( session -> {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -6,6 +6,8 @@
|
|||
*/
|
||||
package org.hibernate.orm.test.inheritance.embeddable;
|
||||
|
||||
import org.hibernate.annotations.Imported;
|
||||
|
||||
import jakarta.persistence.DiscriminatorValue;
|
||||
import jakarta.persistence.Embeddable;
|
||||
|
||||
|
|
|
@ -26,6 +26,7 @@ public class MetadataCopyingTest {
|
|||
existingInstance.getEntityBindingMap(),
|
||||
existingInstance.getComposites(),
|
||||
existingInstance.getGenericComponentsMap(),
|
||||
existingInstance.getEmbeddableDiscriminatorTypesMap(),
|
||||
existingInstance.getMappedSuperclassMap(),
|
||||
existingInstance.getCollectionBindingMap(),
|
||||
existingInstance.getTypeDefinitionMap(),
|
||||
|
|
|
@ -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,
|
||||
or the new `INCLUDES` predicate i.e. `array INCLUDES subarray`.
|
||||
|
||||
|
||||
[[merge-versioned-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).
|
||||
|
@ -70,3 +69,11 @@ For this determination to be possible, the entity must have either:
|
|||
- 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.
|
||||
|
||||
[[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.
|
|
@ -58,6 +58,7 @@ import org.hibernate.metamodel.internal.MetadataContext;
|
|||
import org.hibernate.metamodel.internal.RuntimeMetamodelsImpl;
|
||||
import org.hibernate.metamodel.mapping.JdbcMapping;
|
||||
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.ManagedDomainType;
|
||||
import org.hibernate.metamodel.model.domain.PersistentAttribute;
|
||||
|
@ -201,6 +202,7 @@ public abstract class MockSessionFactory
|
|||
emptyMap(),
|
||||
emptyMap(),
|
||||
emptyMap(),
|
||||
emptyMap(),
|
||||
new Database(this, MockJdbcServicesInitiator.jdbcServices.getJdbcEnvironment()),
|
||||
this
|
||||
);
|
||||
|
|
Loading…
Reference in New Issue