HHH-18569 Don´t implicitly cast when using a subtype attribute name with Criteria API
This commit is contained in:
parent
c1cbbf1fd5
commit
1c87d73d2e
|
@ -12,7 +12,6 @@ import org.hibernate.metamodel.internal.MetadataContext;
|
|||
import org.hibernate.metamodel.mapping.CollectionPart;
|
||||
import org.hibernate.metamodel.model.domain.DomainType;
|
||||
import org.hibernate.metamodel.model.domain.EntityDomainType;
|
||||
import org.hibernate.metamodel.model.domain.JpaMetamodel;
|
||||
import org.hibernate.metamodel.model.domain.PluralPersistentAttribute;
|
||||
import org.hibernate.metamodel.model.domain.SimpleDomainType;
|
||||
import org.hibernate.spi.NavigablePath;
|
||||
|
@ -87,11 +86,11 @@ public abstract class AbstractPluralAttribute<D, C, E>
|
|||
}
|
||||
|
||||
@Override
|
||||
public SqmPathSource<?> findSubPathSource(String name, JpaMetamodel metamodel) {
|
||||
public SqmPathSource<?> findSubPathSource(String name, boolean includeSubtypes) {
|
||||
if ( CollectionPart.Nature.ELEMENT.getName().equals( name ) ) {
|
||||
return elementPathSource;
|
||||
}
|
||||
return elementPathSource.findSubPathSource( name, metamodel );
|
||||
return elementPathSource.findSubPathSource( name, includeSubtypes );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -5,7 +5,6 @@
|
|||
package org.hibernate.metamodel.model.domain.internal;
|
||||
|
||||
import org.hibernate.metamodel.model.domain.EntityDomainType;
|
||||
import org.hibernate.metamodel.model.domain.JpaMetamodel;
|
||||
import org.hibernate.query.hql.spi.SqmCreationState;
|
||||
import org.hibernate.query.sqm.SqmJoinable;
|
||||
import org.hibernate.query.sqm.SqmPathSource;
|
||||
|
@ -42,8 +41,8 @@ public class EntitySqmPathSource<J> extends AbstractSqmPathSource<J> implements
|
|||
}
|
||||
|
||||
@Override
|
||||
public SqmPathSource<?> findSubPathSource(String name, JpaMetamodel metamodel) {
|
||||
return getSqmPathType().findSubPathSource( name, metamodel );
|
||||
public SqmPathSource<?> findSubPathSource(String name, boolean includeSubtypes) {
|
||||
return getSqmPathType().findSubPathSource( name, includeSubtypes );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -139,14 +139,13 @@ public class EntityTypeImpl<J>
|
|||
|
||||
@Override
|
||||
public SqmPathSource<?> findSubPathSource(String name) {
|
||||
final PersistentAttribute<? super J,?> attribute = findAttribute( name );
|
||||
final PersistentAttribute<? super J,?> attribute = super.findAttribute( name );
|
||||
if ( attribute != null ) {
|
||||
return (SqmPathSource<?>) attribute;
|
||||
}
|
||||
else if ( EntityIdentifierMapping.matchesRoleName( name ) ) {
|
||||
return hasSingleIdAttribute() ? findIdAttribute() : getIdentifierDescriptor();
|
||||
}
|
||||
|
||||
else if ( EntityDiscriminatorMapping.matchesRoleName( name ) ) {
|
||||
return discriminatorPathSource;
|
||||
}
|
||||
|
@ -156,18 +155,19 @@ public class EntityTypeImpl<J>
|
|||
}
|
||||
|
||||
@Override
|
||||
public SqmPathSource<?> findSubPathSource(String name, JpaMetamodel metamodel) {
|
||||
public SqmPathSource<?> findSubPathSource(String name, boolean includeSubtypes) {
|
||||
final PersistentAttribute<? super J,?> attribute = super.findAttribute( name );
|
||||
if ( attribute != null ) {
|
||||
return (SqmPathSource<?>) attribute;
|
||||
}
|
||||
else {
|
||||
//TODO: eliminate this cast!
|
||||
final PersistentAttribute<?, ?> subtypeAttribute = findSubtypeAttribute( name );
|
||||
if ( subtypeAttribute != null ) {
|
||||
return (SqmPathSource<?>) subtypeAttribute;
|
||||
if ( includeSubtypes ) {
|
||||
final PersistentAttribute<?, ?> subtypeAttribute = findSubtypeAttribute( name );
|
||||
if ( subtypeAttribute != null ) {
|
||||
return (SqmPathSource<?>) subtypeAttribute;
|
||||
}
|
||||
}
|
||||
else if ( EntityIdentifierMapping.matchesRoleName( name ) ) {
|
||||
if ( EntityIdentifierMapping.matchesRoleName( name ) ) {
|
||||
return hasSingleIdAttribute() ? findIdAttribute() : getIdentifierDescriptor();
|
||||
}
|
||||
else if ( EntityDiscriminatorMapping.matchesRoleName( name ) ) {
|
||||
|
|
|
@ -8,7 +8,6 @@ import java.util.List;
|
|||
|
||||
import org.hibernate.metamodel.internal.MetadataContext;
|
||||
import org.hibernate.metamodel.mapping.CollectionPart;
|
||||
import org.hibernate.metamodel.model.domain.JpaMetamodel;
|
||||
import org.hibernate.metamodel.model.domain.ListPersistentAttribute;
|
||||
import org.hibernate.query.sqm.SqmPathSource;
|
||||
import org.hibernate.query.hql.spi.SqmCreationState;
|
||||
|
@ -60,7 +59,7 @@ public class ListAttributeImpl<X, E> extends AbstractPluralAttribute<X, List<E>,
|
|||
}
|
||||
|
||||
@Override
|
||||
public SqmPathSource<?> findSubPathSource(String name, JpaMetamodel metamodel) {
|
||||
public SqmPathSource<?> findSubPathSource(String name, boolean includeSubtypes) {
|
||||
final CollectionPart.Nature nature = CollectionPart.Nature.fromNameExact( name );
|
||||
if ( nature != null ) {
|
||||
switch ( nature ) {
|
||||
|
@ -70,7 +69,7 @@ public class ListAttributeImpl<X, E> extends AbstractPluralAttribute<X, List<E>,
|
|||
return getElementPathSource();
|
||||
}
|
||||
}
|
||||
return getElementPathSource().findSubPathSource( name, metamodel );
|
||||
return getElementPathSource().findSubPathSource( name, includeSubtypes );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -8,7 +8,6 @@ import java.util.Map;
|
|||
|
||||
import org.hibernate.metamodel.internal.MetadataContext;
|
||||
import org.hibernate.metamodel.mapping.CollectionPart;
|
||||
import org.hibernate.metamodel.model.domain.JpaMetamodel;
|
||||
import org.hibernate.metamodel.model.domain.MapPersistentAttribute;
|
||||
import org.hibernate.metamodel.model.domain.SimpleDomainType;
|
||||
import org.hibernate.query.sqm.SqmPathSource;
|
||||
|
@ -70,7 +69,7 @@ public class MapAttributeImpl<X, K, V> extends AbstractPluralAttribute<X, Map<K,
|
|||
}
|
||||
|
||||
@Override
|
||||
public SqmPathSource<?> findSubPathSource(String name, JpaMetamodel metamodel) {
|
||||
public SqmPathSource<?> findSubPathSource(String name, boolean includeSubtypes) {
|
||||
final CollectionPart.Nature nature = CollectionPart.Nature.fromNameExact( name );
|
||||
if ( nature != null ) {
|
||||
switch ( nature ) {
|
||||
|
@ -80,7 +79,7 @@ public class MapAttributeImpl<X, K, V> extends AbstractPluralAttribute<X, Map<K,
|
|||
return getElementPathSource();
|
||||
}
|
||||
}
|
||||
return getElementPathSource().findSubPathSource( name, metamodel );
|
||||
return getElementPathSource().findSubPathSource( name, includeSubtypes );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -14,7 +14,6 @@ import org.hibernate.metamodel.model.domain.AnyMappingDomainType;
|
|||
import org.hibernate.metamodel.model.domain.DomainType;
|
||||
import org.hibernate.metamodel.model.domain.EntityDomainType;
|
||||
import org.hibernate.metamodel.model.domain.IdentifiableDomainType;
|
||||
import org.hibernate.metamodel.model.domain.JpaMetamodel;
|
||||
import org.hibernate.metamodel.model.domain.ManagedDomainType;
|
||||
import org.hibernate.metamodel.model.domain.PluralPersistentAttribute;
|
||||
import org.hibernate.metamodel.model.domain.SimpleDomainType;
|
||||
|
@ -132,8 +131,8 @@ public class SingularAttributeImpl<D,J>
|
|||
}
|
||||
|
||||
@Override
|
||||
public SqmPathSource<?> findSubPathSource(String name, JpaMetamodel metamodel) {
|
||||
return sqmPathSource.findSubPathSource( name, metamodel );
|
||||
public SqmPathSource<?> findSubPathSource(String name, boolean includeSubtypes) {
|
||||
return sqmPathSource.findSubPathSource( name, includeSubtypes );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -145,7 +145,7 @@ public class BasicDotIdentifierConsumer implements DotIdentifierConsumer {
|
|||
if ( pathRootByExposedNavigable != null ) {
|
||||
// identifier is an "unqualified attribute reference"
|
||||
validateAsRoot( pathRootByExposedNavigable );
|
||||
final SqmPath<?> sqmPath = pathRootByExposedNavigable.get( identifier );
|
||||
final SqmPath<?> sqmPath = pathRootByExposedNavigable.get( identifier, true );
|
||||
return isTerminal ? sqmPath : new DomainPathPart( sqmPath );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -188,10 +188,7 @@ public class QualifiedJoinPathConsumer implements DotIdentifierConsumer {
|
|||
boolean isTerminal,
|
||||
boolean allowReuse,
|
||||
SqmCreationState creationState) {
|
||||
final SqmPathSource<?> subPathSource = lhs.getResolvedModel().getSubPathSource(
|
||||
name,
|
||||
creationState.getCreationContext().getJpaMetamodel()
|
||||
);
|
||||
final SqmPathSource<?> subPathSource = lhs.getResolvedModel().getSubPathSource( name, true );
|
||||
if ( allowReuse ) {
|
||||
if ( !isTerminal ) {
|
||||
for ( SqmJoin<?, ?> sqmJoin : lhs.getSqmJoins() ) {
|
||||
|
|
|
@ -3587,7 +3587,7 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
|
|||
+ "' of 'id()' is a '" + identifiableType.getTypeName()
|
||||
+ "' and does not have a well-defined '@Id' attribute" );
|
||||
}
|
||||
return sqmPath.get( identifierDescriptor.getPathName() );
|
||||
return sqmPath.get( identifierDescriptor.getPathName(), true );
|
||||
}
|
||||
else if ( sqmPath instanceof SqmAnyValuedSimplePath<?> ) {
|
||||
return sqmPath.resolvePathPart( AnyKeyPart.KEY_NAME, true, processingStateStack.getCurrent().getCreationState() );
|
||||
|
|
|
@ -335,7 +335,7 @@ public class SqmPathRegistryImpl implements SqmPathRegistry {
|
|||
|
||||
private boolean definesAttribute(SqmPathSource<?> containerType, String name) {
|
||||
return !( containerType.getSqmType() instanceof BasicDomainType )
|
||||
&& containerType.findSubPathSource( name, getJpaMetamodel() ) != null;
|
||||
&& containerType.findSubPathSource( name, true ) != null;
|
||||
}
|
||||
|
||||
private JpaMetamodel getJpaMetamodel() {
|
||||
|
|
|
@ -42,8 +42,8 @@ public interface SqmPathSource<J> extends SqmExpressible<J>, Bindable<J>, SqmExp
|
|||
/**
|
||||
* Find a {@link SqmPathSource} by name relative to this source.
|
||||
*
|
||||
* @param name the name of the path source to find
|
||||
* @return null if the subPathSource is not found
|
||||
*
|
||||
* @throws IllegalStateException to indicate that this source cannot be de-referenced
|
||||
*/
|
||||
SqmPathSource<?> findSubPathSource(String name);
|
||||
|
@ -52,16 +52,31 @@ public interface SqmPathSource<J> extends SqmExpressible<J>, Bindable<J>, SqmExp
|
|||
* Find a {@link SqmPathSource} by name relative to this source.
|
||||
*
|
||||
* @return null if the subPathSource is not found
|
||||
* @throws IllegalStateException to indicate that this source cannot be de-referenced
|
||||
* @deprecated Use {@link #findSubPathSource(String, boolean)} instead
|
||||
*/
|
||||
@Deprecated(forRemoval = true, since = "7.0")
|
||||
default SqmPathSource<?> findSubPathSource(String name, JpaMetamodel metamodel) {
|
||||
return findSubPathSource( name, true );
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a {@link SqmPathSource} by name relative to this source. If {@code includeSubtypes} is set
|
||||
* to {@code true} and this path source is polymorphic, also try finding subtype attributes.
|
||||
*
|
||||
* @param name the name of the path source to find
|
||||
* @param includeSubtypes flag indicating whether to consider subtype attributes
|
||||
* @return null if the subPathSource is not found
|
||||
* @throws IllegalStateException to indicate that this source cannot be de-referenced
|
||||
*/
|
||||
default SqmPathSource<?> findSubPathSource(String name, JpaMetamodel metamodel) {
|
||||
default SqmPathSource<?> findSubPathSource(String name, boolean includeSubtypes) {
|
||||
return findSubPathSource( name );
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a {@link SqmPathSource} by name relative to this source.
|
||||
*
|
||||
* @param name the name of the path source to find
|
||||
* @throws IllegalStateException to indicate that this source cannot be de-referenced
|
||||
* @throws IllegalArgumentException if the subPathSource is not found
|
||||
*/
|
||||
|
@ -81,13 +96,39 @@ public interface SqmPathSource<J> extends SqmExpressible<J>, Bindable<J>, SqmExp
|
|||
}
|
||||
|
||||
/**
|
||||
* Find a {@link SqmPathSource} by name relative to this source.
|
||||
* Find a {@link SqmPathSource} by name relative to this source and all its subtypes.
|
||||
*
|
||||
* @throws IllegalStateException to indicate that this source cannot be de-referenced
|
||||
* @throws IllegalArgumentException if the subPathSource is not found
|
||||
* @deprecated Use #{@link #getSubPathSource(String, boolean)} instead
|
||||
*/
|
||||
@Deprecated(forRemoval = true, since = "7.0")
|
||||
default SqmPathSource<?> getSubPathSource(String name, JpaMetamodel metamodel) {
|
||||
final SqmPathSource<?> subPathSource = findSubPathSource( name, metamodel );
|
||||
final SqmPathSource<?> subPathSource = findSubPathSource( name, true );
|
||||
if ( subPathSource == null ) {
|
||||
throw new PathElementException(
|
||||
String.format(
|
||||
Locale.ROOT,
|
||||
"Could not resolve attribute '%s' of '%s'",
|
||||
name,
|
||||
getExpressible().getTypeName()
|
||||
)
|
||||
);
|
||||
}
|
||||
return subPathSource;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a {@link SqmPathSource} by name relative to this source. If {@code subtypes} is set
|
||||
* to {@code true} and this path source is polymorphic, also try finding subtype attributes.
|
||||
*
|
||||
* @param name the name of the path source to find
|
||||
* @param subtypes flag indicating whether to consider subtype attributes
|
||||
* @throws IllegalStateException to indicate that this source cannot be de-referenced
|
||||
* @throws IllegalArgumentException if the subPathSource is not found
|
||||
*/
|
||||
default SqmPathSource<?> getSubPathSource(String name, boolean subtypes) {
|
||||
final SqmPathSource<?> subPathSource = findSubPathSource( name, true );
|
||||
if ( subPathSource == null ) {
|
||||
throw new PathElementException(
|
||||
String.format(
|
||||
|
|
|
@ -196,7 +196,7 @@ public abstract class AbstractSqmFrom<O,T> extends AbstractSqmPath<T> implements
|
|||
if ( resolvedPath != null ) {
|
||||
return resolvedPath;
|
||||
}
|
||||
final SqmPath<?> sqmPath = get( name );
|
||||
final SqmPath<?> sqmPath = get( name, true );
|
||||
creationState.getProcessingStateStack().getCurrent().getPathRegistry().register( sqmPath );
|
||||
return sqmPath;
|
||||
}
|
||||
|
@ -417,8 +417,8 @@ public abstract class AbstractSqmFrom<O,T> extends AbstractSqmPath<T> implements
|
|||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <X, Y> SqmAttributeJoin<X, Y> join(String attributeName, JoinType jt) {
|
||||
final SqmPathSource<?> subPathSource =
|
||||
getReferencedPathSource().getSubPathSource( attributeName, nodeBuilder().getJpaMetamodel() );
|
||||
final SqmPathSource<Y> subPathSource = (SqmPathSource<Y>) getReferencedPathSource()
|
||||
.getSubPathSource( attributeName );
|
||||
return (SqmAttributeJoin<X, Y>) buildJoin( subPathSource, SqmJoinType.from( jt ), false );
|
||||
}
|
||||
|
||||
|
@ -430,8 +430,7 @@ public abstract class AbstractSqmFrom<O,T> extends AbstractSqmPath<T> implements
|
|||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <X, Y> SqmBagJoin<X, Y> joinCollection(String attributeName, JoinType jt) {
|
||||
final SqmPathSource<?> joinedPathSource =
|
||||
getReferencedPathSource().getSubPathSource( attributeName, nodeBuilder().getJpaMetamodel() );
|
||||
final SqmPathSource<?> joinedPathSource = getReferencedPathSource().getSubPathSource( attributeName );
|
||||
|
||||
if ( joinedPathSource instanceof BagPersistentAttribute ) {
|
||||
final SqmBagJoin<T, Y> join = buildBagJoin(
|
||||
|
@ -462,8 +461,7 @@ public abstract class AbstractSqmFrom<O,T> extends AbstractSqmPath<T> implements
|
|||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <X, Y> SqmSetJoin<X, Y> joinSet(String attributeName, JoinType jt) {
|
||||
final SqmPathSource<?> joinedPathSource =
|
||||
getReferencedPathSource().getSubPathSource( attributeName, nodeBuilder().getJpaMetamodel() );
|
||||
final SqmPathSource<?> joinedPathSource = getReferencedPathSource().getSubPathSource( attributeName );
|
||||
|
||||
if ( joinedPathSource instanceof SetPersistentAttribute ) {
|
||||
final SqmSetJoin<T, Y> join = buildSetJoin(
|
||||
|
@ -494,8 +492,7 @@ public abstract class AbstractSqmFrom<O,T> extends AbstractSqmPath<T> implements
|
|||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <X, Y> SqmListJoin<X, Y> joinList(String attributeName, JoinType jt) {
|
||||
final SqmPathSource<?> joinedPathSource =
|
||||
getReferencedPathSource().getSubPathSource( attributeName, nodeBuilder().getJpaMetamodel() );
|
||||
final SqmPathSource<?> joinedPathSource = getReferencedPathSource().getSubPathSource( attributeName );
|
||||
|
||||
if ( joinedPathSource instanceof ListPersistentAttribute ) {
|
||||
final SqmListJoin<T, Y> join = buildListJoin(
|
||||
|
@ -526,8 +523,7 @@ public abstract class AbstractSqmFrom<O,T> extends AbstractSqmPath<T> implements
|
|||
@Override
|
||||
@SuppressWarnings("unchecked")
|
||||
public <X, K, V> SqmMapJoin<X, K, V> joinMap(String attributeName, JoinType jt) {
|
||||
final SqmPathSource<?> joinedPathSource =
|
||||
getReferencedPathSource().getSubPathSource( attributeName, nodeBuilder().getJpaMetamodel() );
|
||||
final SqmPathSource<?> joinedPathSource = getReferencedPathSource().getSubPathSource( attributeName );
|
||||
|
||||
if ( joinedPathSource instanceof MapPersistentAttribute<?, ?, ?> ) {
|
||||
final SqmMapJoin<T, K, V> join = buildMapJoin(
|
||||
|
|
|
@ -193,11 +193,18 @@ public abstract class AbstractSqmPath<T> extends AbstractSqmExpression<T> implem
|
|||
@Override
|
||||
public <Y> SqmPath<Y> get(String attributeName) {
|
||||
//noinspection unchecked
|
||||
final SqmPathSource<Y> subNavigable = (SqmPathSource<Y>)
|
||||
getResolvedModel().getSubPathSource( attributeName, nodeBuilder().getJpaMetamodel() );
|
||||
final SqmPathSource<Y> subNavigable = (SqmPathSource<Y>) getResolvedModel().getSubPathSource( attributeName );
|
||||
return resolvePath( attributeName, subNavigable );
|
||||
}
|
||||
|
||||
@Override
|
||||
public <Y> SqmPath<Y> get(String attributeName, boolean includeSubtypes) {
|
||||
//noinspection unchecked
|
||||
final SqmPathSource<Y> subPathSource = (SqmPathSource<Y>)
|
||||
getResolvedModel().getSubPathSource( attributeName, includeSubtypes );
|
||||
return resolvePath( attributeName, subPathSource );
|
||||
}
|
||||
|
||||
protected <X> SqmPath<X> resolvePath(PersistentAttribute<?, X> attribute) {
|
||||
//noinspection unchecked
|
||||
return resolvePath( attribute.getName(), (SqmPathSource<X>) attribute );
|
||||
|
|
|
@ -77,7 +77,7 @@ public class SqmAnyValuedSimplePath<T> extends AbstractSqmSimplePath<T> {
|
|||
String name,
|
||||
boolean isTerminal,
|
||||
SqmCreationState creationState) {
|
||||
final SqmPath<?> sqmPath = get( name );
|
||||
final SqmPath<?> sqmPath = get( name, true );
|
||||
creationState.getProcessingStateStack().getCurrent().getPathRegistry().register( sqmPath );
|
||||
return sqmPath;
|
||||
}
|
||||
|
|
|
@ -100,7 +100,7 @@ public class SqmElementAggregateFunction<T> extends AbstractSqmSpecificPluralPar
|
|||
String name,
|
||||
boolean isTerminal,
|
||||
SqmCreationState creationState) {
|
||||
final SqmPath<?> sqmPath = get( name );
|
||||
final SqmPath<?> sqmPath = get( name, true );
|
||||
creationState.getProcessingStateStack().getCurrent().getPathRegistry().register( sqmPath );
|
||||
return sqmPath;
|
||||
}
|
||||
|
|
|
@ -84,7 +84,7 @@ public class SqmEmbeddedValuedSimplePath<T>
|
|||
String name,
|
||||
boolean isTerminal,
|
||||
SqmCreationState creationState) {
|
||||
final SqmPath<?> sqmPath = get( name );
|
||||
final SqmPath<?> sqmPath = get( name, true );
|
||||
creationState.getProcessingStateStack().getCurrent().getPathRegistry().register( sqmPath );
|
||||
return sqmPath;
|
||||
}
|
||||
|
|
|
@ -51,7 +51,7 @@ public class SqmEntityValuedSimplePath<T> extends AbstractSqmSimplePath<T> {
|
|||
String name,
|
||||
boolean isTerminal,
|
||||
SqmCreationState creationState) {
|
||||
final SqmPath<?> sqmPath = get( name );
|
||||
final SqmPath<?> sqmPath = get( name, true );
|
||||
creationState.getProcessingStateStack().getCurrent().getPathRegistry().register( sqmPath );
|
||||
return sqmPath;
|
||||
}
|
||||
|
|
|
@ -83,7 +83,7 @@ public class SqmFkExpression<T> extends AbstractSqmPath<T> {
|
|||
|
||||
@Override
|
||||
public SqmPath<?> resolvePathPart(String name, boolean isTerminal, SqmCreationState creationState) {
|
||||
final SqmPath<?> sqmPath = get( name );
|
||||
final SqmPath<?> sqmPath = get( name, true );
|
||||
creationState.getProcessingStateStack().getCurrent().getPathRegistry().register( sqmPath );
|
||||
return sqmPath;
|
||||
}
|
||||
|
|
|
@ -105,7 +105,7 @@ public class SqmFunctionPath<T> extends AbstractSqmPath<T> {
|
|||
String name,
|
||||
boolean isTerminal,
|
||||
SqmCreationState creationState) {
|
||||
final SqmPath<?> sqmPath = get( name );
|
||||
final SqmPath<?> sqmPath = get( name, true );
|
||||
creationState.getProcessingStateStack().getCurrent().getPathRegistry().register( sqmPath );
|
||||
return sqmPath;
|
||||
}
|
||||
|
|
|
@ -102,7 +102,7 @@ public class SqmIndexAggregateFunction<T> extends AbstractSqmSpecificPluralPartP
|
|||
String name,
|
||||
boolean isTerminal,
|
||||
SqmCreationState creationState) {
|
||||
final SqmPath<?> sqmPath = get( name );
|
||||
final SqmPath<?> sqmPath = get( name, true );
|
||||
creationState.getProcessingStateStack().getCurrent().getPathRegistry().register( sqmPath );
|
||||
return sqmPath;
|
||||
}
|
||||
|
|
|
@ -66,7 +66,7 @@ public class SqmIndexedCollectionAccessPath<T> extends AbstractSqmPath<T> implem
|
|||
String name,
|
||||
boolean isTerminal,
|
||||
SqmCreationState creationState) {
|
||||
final SqmPath<?> sqmPath = get( name );
|
||||
final SqmPath<?> sqmPath = get( name, true );
|
||||
creationState.getProcessingStateStack().getCurrent().getPathRegistry().register( sqmPath );
|
||||
return sqmPath;
|
||||
}
|
||||
|
|
|
@ -175,6 +175,16 @@ public interface SqmPath<T> extends SqmExpression<T>, SemanticPathPart, JpaPath<
|
|||
@Override
|
||||
<Y> SqmPath<Y> get(String attributeName);
|
||||
|
||||
/**
|
||||
* Same as {@link #get(String)}, but if {@code includeSubtypes} is set to {@code true}
|
||||
* and this path is polymorphic, also try finding subtype attributes.
|
||||
*
|
||||
* @see SqmPathSource#findSubPathSource(String, boolean)
|
||||
*/
|
||||
default <Y> SqmPath<Y> get(String attributeName, boolean includeSubtypes) {
|
||||
return get( attributeName );
|
||||
}
|
||||
|
||||
@Override
|
||||
SqmPath<T> copy(SqmCopyContext context);
|
||||
|
||||
|
|
|
@ -101,7 +101,7 @@ public class SqmPluralValuedSimplePath<E> extends AbstractSqmSimplePath<E> {
|
|||
+ "' refers to a collection and so element attribute '" + name
|
||||
+ "' may not be referenced directly (use element() function)" );
|
||||
}
|
||||
final SqmPath<?> sqmPath = get( name );
|
||||
final SqmPath<?> sqmPath = get( name, true );
|
||||
creationState.getProcessingStateStack().getCurrent().getPathRegistry().register( sqmPath );
|
||||
return sqmPath;
|
||||
}
|
||||
|
|
|
@ -18,11 +18,9 @@ import org.hibernate.query.criteria.JpaSetJoin;
|
|||
import org.hibernate.query.sqm.NodeBuilder;
|
||||
import org.hibernate.query.sqm.tree.SqmCopyContext;
|
||||
import org.hibernate.query.sqm.tree.SqmJoinType;
|
||||
import org.hibernate.query.sqm.tree.from.SqmAttributeJoin;
|
||||
import org.hibernate.query.sqm.tree.from.SqmFrom;
|
||||
|
||||
import jakarta.persistence.criteria.Expression;
|
||||
import jakarta.persistence.criteria.JoinType;
|
||||
import jakarta.persistence.criteria.Predicate;
|
||||
|
||||
/**
|
||||
|
@ -157,11 +155,4 @@ public class SqmSetJoin<O, E>
|
|||
}
|
||||
return treat;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <X, Y> SqmAttributeJoin<X, Y> fetch(String attributeName) {
|
||||
return fetch( attributeName, JoinType.INNER);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -103,7 +103,7 @@ public class SqmTreatedEmbeddedValuedSimplePath<T, S extends T> extends SqmEmbed
|
|||
|
||||
@Override
|
||||
public SqmPath<?> resolvePathPart(String name, boolean isTerminal, SqmCreationState creationState) {
|
||||
final SqmPath<?> sqmPath = get( name );
|
||||
final SqmPath<?> sqmPath = get( name, true );
|
||||
creationState.getProcessingStateStack().getCurrent().getPathRegistry().register( sqmPath );
|
||||
return sqmPath;
|
||||
}
|
||||
|
|
|
@ -110,7 +110,7 @@ public class SqmTreatedRoot extends SqmRoot implements SqmTreatedFrom {
|
|||
String name,
|
||||
boolean isTerminal,
|
||||
SqmCreationState creationState) {
|
||||
final SqmPath<?> sqmPath = get( name );
|
||||
final SqmPath<?> sqmPath = get( name, true );
|
||||
creationState.getProcessingStateStack().getCurrent().getPathRegistry().register( sqmPath );
|
||||
return sqmPath;
|
||||
}
|
||||
|
|
|
@ -494,9 +494,9 @@ public class SqmQuerySpec<T> extends SqmQueryPart<T>
|
|||
}
|
||||
|
||||
for ( SqmRoot<?> root : roots ) {
|
||||
validateFetchOwners( selectedFromSet, root, root );
|
||||
validateFetchOwners( selectedFromSet, root );
|
||||
for ( SqmFrom<?, ?> sqmTreat : root.getSqmTreats() ) {
|
||||
validateFetchOwners( selectedFromSet, root, sqmTreat );
|
||||
validateFetchOwners( selectedFromSet, sqmTreat );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -543,12 +543,12 @@ public class SqmQuerySpec<T> extends SqmQueryPart<T>
|
|||
}
|
||||
}
|
||||
|
||||
private void validateFetchOwners(Set<SqmFrom<?, ?>> selectedFromSet, SqmFrom<?, ?> owner, SqmFrom<?, ?> joinContainer) {
|
||||
private void validateFetchOwners(Set<SqmFrom<?, ?>> selectedFromSet, SqmFrom<?, ?> joinContainer) {
|
||||
for ( SqmJoin<?, ?> sqmJoin : joinContainer.getSqmJoins() ) {
|
||||
if ( sqmJoin instanceof SqmAttributeJoin<?, ?> ) {
|
||||
final SqmAttributeJoin<?, ?> attributeJoin = (SqmAttributeJoin<?, ?>) sqmJoin;
|
||||
if ( attributeJoin.isFetched() ) {
|
||||
assertFetchOwner( selectedFromSet, owner, sqmJoin );
|
||||
assertFetchOwner( selectedFromSet, attributeJoin.getLhs(), sqmJoin );
|
||||
// Only need to check the first level
|
||||
continue;
|
||||
}
|
||||
|
@ -557,14 +557,14 @@ public class SqmQuerySpec<T> extends SqmQueryPart<T>
|
|||
if ( sqmTreat instanceof SqmAttributeJoin<?, ?> ) {
|
||||
final SqmAttributeJoin<?, ?> attributeJoin = (SqmAttributeJoin<?, ?>) sqmTreat;
|
||||
if ( attributeJoin.isFetched() ) {
|
||||
assertFetchOwner( selectedFromSet, owner, attributeJoin );
|
||||
assertFetchOwner( selectedFromSet, attributeJoin.getLhs(), attributeJoin );
|
||||
// Only need to check the first level
|
||||
continue;
|
||||
}
|
||||
}
|
||||
validateFetchOwners( selectedFromSet, sqmJoin, sqmTreat );
|
||||
validateFetchOwners( selectedFromSet, sqmTreat );
|
||||
}
|
||||
validateFetchOwners( selectedFromSet, sqmJoin, sqmJoin );
|
||||
validateFetchOwners( selectedFromSet, sqmJoin );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -61,11 +61,6 @@ public class TreatedSubclassSameTypeTest {
|
|||
executeQuery( scope, criteria -> criteria.from( MyEntity1.class ), true );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testJoin(SessionFactoryScope scope) {
|
||||
executeQuery( scope, criteria -> criteria.from( MyEntity1.class ), false );
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testJoinOnTreatedSubtype(SessionFactoryScope scope) {
|
||||
executeQuery( scope, criteria -> criteria.from( MySubEntity1.class ), true );
|
||||
|
|
|
@ -106,7 +106,7 @@ public class JoinedSubclassTest {
|
|||
|
||||
Root<Person> root = criteria.from( Person.class );
|
||||
|
||||
criteria.where( criteriaBuilder.gt( root.get( "salary" ), new BigDecimal( 100 ) ) );
|
||||
criteria.where( criteriaBuilder.gt( criteriaBuilder.treat( root, Employee.class ).get( "salary" ), new BigDecimal( 100 ) ) );
|
||||
|
||||
result = s.createQuery( criteria ).list();
|
||||
// result = s.createCriteria( Person.class )
|
||||
|
|
|
@ -99,12 +99,15 @@ public class CorrelatedPluralJoinInheritanceTest {
|
|||
}
|
||||
|
||||
@Test
|
||||
public void testImplicitTreat(EntityManagerFactoryScope scope) {
|
||||
public void testExplicitTreat(EntityManagerFactoryScope scope) {
|
||||
scope.inTransaction( entityManager -> {
|
||||
final CriteriaBuilder cb = entityManager.getCriteriaBuilder();
|
||||
final CriteriaQuery<ContinuousData> criteriaQuery = cb.createQuery( ContinuousData.class );
|
||||
final Root<ContinuousData> root = criteriaQuery.from( ContinuousData.class );
|
||||
criteriaQuery.where( createExistsPredicate( root, criteriaQuery, cb, "storedTags" ) );
|
||||
final Subquery<String> subquery = criteriaQuery.subquery( String.class );
|
||||
final Root<ContinuousData> root2 = subquery.correlate( root );
|
||||
subquery.select( root2.get( "id" ) ).where( cb.treat( root2, StoredContinuousData.class ).join( "storedTags" ).get( "id" ).in( "a", "b" ) );
|
||||
criteriaQuery.where( cb.exists( subquery ) );
|
||||
final List<ContinuousData> resultList = entityManager.createQuery( criteriaQuery ).getResultList();
|
||||
assertThat( resultList ).hasSize( 1 );
|
||||
} );
|
||||
|
|
|
@ -177,7 +177,7 @@ public class DiscriminatorTest {
|
|||
CriteriaBuilder criteriaBuilder = s.getCriteriaBuilder();
|
||||
CriteriaQuery<Person> criteria = criteriaBuilder.createQuery( Person.class );
|
||||
Root<Person> root = criteria.from( Person.class );
|
||||
criteria.where( criteriaBuilder.gt( root.get( "salary" ), new BigDecimal( 100 ) ) );
|
||||
criteria.where( criteriaBuilder.gt( criteriaBuilder.treat( root, Employee.class ).get( "salary" ), new BigDecimal( 100 ) ) );
|
||||
result = s.createQuery( criteria ).list();
|
||||
// result = s.createCriteria(Person.class)
|
||||
// .add( Property.forName( "salary").gt( new BigDecimal( 100) ) )
|
||||
|
|
|
@ -182,7 +182,7 @@ public class SimpleInheritanceTest {
|
|||
CriteriaBuilder criteriaBuilder = s.getCriteriaBuilder();
|
||||
CriteriaQuery<Person> criteria = criteriaBuilder.createQuery( Person.class );
|
||||
Root<Person> root = criteria.from( Person.class );
|
||||
criteria.where( criteriaBuilder.gt( root.get( "salary" ), new BigDecimal( 100 ) ) );
|
||||
criteria.where( criteriaBuilder.gt( criteriaBuilder.treat( root, Employee.class ).get( "salary" ), new BigDecimal( 100 ) ) );
|
||||
|
||||
result = s.createQuery( criteria ).list();
|
||||
// result = s.createCriteria( Person.class )
|
||||
|
|
|
@ -92,7 +92,7 @@ public class CriteriaInheritanceJoinTest {
|
|||
final CriteriaBuilder cb = session.getCriteriaBuilder();
|
||||
final CriteriaQuery<Address> cq = cb.createQuery( Address.class );
|
||||
final Root<Address> addressRoot = cq.from( Address.class );
|
||||
final Join<Address, Street> join = addressRoot.join( "street" );
|
||||
final Join<Address, Street> join = cb.treat( addressRoot, StreetAddress.class ).join( "street" );
|
||||
cq.select( addressRoot ).where( cb.equal( join.get( "name" ), "Via Roma" ) );
|
||||
final Address result = session.createQuery( cq ).getSingleResult();
|
||||
assertThat( result ).isInstanceOf( StreetAddress.class );
|
||||
|
|
|
@ -160,7 +160,7 @@ public class UnionSubclassTest {
|
|||
CriteriaBuilder criteriaBuilder = s.getCriteriaBuilder();
|
||||
CriteriaQuery<Person> criteria = criteriaBuilder.createQuery( Person.class );
|
||||
Root<Person> root = criteria.from( Person.class );
|
||||
criteria.where( criteriaBuilder.gt( root.get( "salary" ), new BigDecimal( 100 ) ) );
|
||||
criteria.where( criteriaBuilder.gt( criteriaBuilder.treat( root, Employee.class ).get( "salary" ), new BigDecimal( 100 ) ) );
|
||||
|
||||
result = s.createQuery( criteria ).list();
|
||||
|
||||
|
|
|
@ -376,6 +376,13 @@ In Hibernate 7, the configuration property `hibernate.jdbc.batch_size` now has n
|
|||
Automatic batching may be enabled by explicitly calling `setJdbcBatchSize()`.
|
||||
However, the preferred approach is to explicitly batch operations via `insertMultiple()`, `updateMultiple()`, or `deleteMultiple()`.
|
||||
|
||||
[[criteria-implicit-treat]]
|
||||
== Criteria API and inheritance subtypes attributes
|
||||
|
||||
It was previously possible to use the string version of the `jakarta.persistence.criteria.Path#get` and `jakarta.persistence.criteria.From#join` methods with names of attributes defined in an inheritance subtype of the type represented by the path expression. This was handled internally by implicitly treating the path as the subtype which defines said attribute. Since Hibernate 7.0, aligning with the JPA specification, the Criteria API will no longer allow retrieving subtype attributes this way, and it's going to require an explicit `jakarta.persistence.criteria.CriteriaBuilder#treat` to be called on the path first to downcast it to the subtype which defines the attribute.
|
||||
|
||||
Implicit treats are still going to be applied when an HQL query dereferences a path belonging to an inheritance subtype.
|
||||
|
||||
[[hbm-transform]]
|
||||
== hbm.xml Transformation
|
||||
|
||||
|
|
|
@ -62,7 +62,6 @@ 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.JpaMetamodel;
|
||||
import org.hibernate.metamodel.model.domain.ManagedDomainType;
|
||||
import org.hibernate.metamodel.model.domain.PersistentAttribute;
|
||||
import org.hibernate.metamodel.model.domain.SingularPersistentAttribute;
|
||||
|
@ -973,14 +972,14 @@ public abstract class MockSessionFactory
|
|||
}
|
||||
|
||||
@Override
|
||||
public SqmPathSource<?> findSubPathSource(String name, JpaMetamodel metamodel) {
|
||||
public SqmPathSource<?> findSubPathSource(String name, boolean includeSubtypes) {
|
||||
switch (name) {
|
||||
case EntityIdentifierMapping.ID_ROLE_NAME:
|
||||
return getIdentifierDescriptor();
|
||||
case "{version}":
|
||||
return findVersionAttribute();
|
||||
}
|
||||
final SqmPathSource<?> source = super.findSubPathSource(name, metamodel);
|
||||
final SqmPathSource<?> source = super.findSubPathSource(name, includeSubtypes);
|
||||
if ( source != null ) {
|
||||
return source;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue