HHH-15442 Allow for setParameter usage with a queries for a specific type in an Any-discriminated relationship

This commit is contained in:
Andrea Boriero 2022-08-08 17:26:23 +02:00 committed by Andrea Boriero
parent bc94357d4a
commit 863f045bf8
12 changed files with 171 additions and 68 deletions

View File

@ -115,6 +115,7 @@ public class DiscriminatedAssociationAttributeMapping
return discriminatorMapping.resolveDiscriminatorValueToEntityMapping( discriminatorValue );
}
@Override
public Object resolveDiscriminatorForEntityType(EntityMappingType entityMappingType) {
return discriminatorMapping.resolveDiscriminatorValueToEntityMapping( entityMappingType );
}

View File

@ -6,6 +6,7 @@
*/
package org.hibernate.metamodel.model.domain;
/**
* Models Hibernate's ANY mapping (reverse discrimination) as a JPA domain model type
*

View File

@ -0,0 +1,102 @@
/*
* 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.engine.spi.SharedSessionContractImplementor;
import org.hibernate.mapping.IndexedConsumer;
import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.mapping.MappingModelExpressible;
import org.hibernate.metamodel.model.convert.spi.BasicValueConverter;
import org.hibernate.metamodel.model.domain.SimpleDomainType;
import org.hibernate.sql.ast.Clause;
import org.hibernate.type.BasicType;
import org.hibernate.type.MetaType;
import org.hibernate.type.descriptor.java.ClassJavaType;
import org.hibernate.type.descriptor.java.JavaType;
public class AnyDiscriminatorDomainTypeImpl<T>
implements SimpleDomainType<T>, MappingModelExpressible<T>, BasicValueConverter<T, Object> {
private final BasicType underlyingType;
private final MetaType modelPart;
public AnyDiscriminatorDomainTypeImpl(BasicType<?> underlyingType, MetaType modelPart) {
this.underlyingType = underlyingType;
this.modelPart = modelPart;
}
@Override
public T toDomainValue(Object discriminatorValue) {
if ( discriminatorValue == null ) {
return null;
}
return (T) modelPart.getDiscriminatorValuesToEntityNameMap().get( discriminatorValue );
}
@Override
public Object toRelationalValue(T domainForm) {
if ( domainForm == null ) {
return null;
}
if ( domainForm instanceof Class ) {
return modelPart.getEntityNameToDiscriminatorValueMap().get( ( (Class) domainForm ).getName() );
}
else {
return modelPart.getEntityNameToDiscriminatorValueMap().get( (String) domainForm );
}
}
@Override
public JavaType<T> getDomainJavaType() {
return getExpressibleJavaType();
}
@Override
public JavaType<Object> getRelationalJavaType() {
return underlyingType.getExpressibleJavaType();
}
@Override
public PersistenceType getPersistenceType() {
return PersistenceType.BASIC;
}
@Override
public Class getJavaType() {
return Class.class;
}
@Override
public Object disassemble(Object value, SharedSessionContractImplementor session) {
return toRelationalValue( (T) value );
}
@Override
public int forEachDisassembledJdbcValue(
Object value,
Clause clause,
int offset,
JdbcValuesConsumer valuesConsumer,
SharedSessionContractImplementor session) {
valuesConsumer.consume( offset, value, underlyingType );
return 1;
}
public JavaType<T> getExpressibleJavaType() {
return (JavaType<T>) ClassJavaType.INSTANCE;
}
@Override
public int forEachJdbcType(int offset, IndexedConsumer<JdbcMapping> action) {
action.accept( 0, underlyingType );
return 1;
}
public BasicType getBasicType() {
return underlyingType;
}
}

View File

@ -12,25 +12,24 @@ import org.hibernate.query.PathException;
import org.hibernate.query.hql.spi.SqmCreationState;
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.query.sqm.tree.domain.SqmTreatedPath;
import org.hibernate.spi.NavigablePath;
public class AnyDiscriminatorSqmPath extends AbstractSqmPath {
public class AnyDiscriminatorSqmPath<T> extends AbstractSqmPath<T> {
protected AnyDiscriminatorSqmPath(
NavigablePath navigablePath,
SqmPathSource referencedPathSource,
AnyDiscriminatorSqmPathSource referencedPathSource,
SqmPath lhs,
NodeBuilder nodeBuilder) {
super( navigablePath, referencedPathSource, lhs, nodeBuilder );
}
@Override
public AnyDiscriminatorSqmPath copy(SqmCopyContext context) {
public AnyDiscriminatorSqmPath<T> copy(SqmCopyContext context) {
final AnyDiscriminatorSqmPath existing = context.getCopy( this );
if ( existing != null ) {
return existing;
@ -67,4 +66,15 @@ public class AnyDiscriminatorSqmPath extends AbstractSqmPath {
public SqmTreatedPath treatAs(EntityDomainType treatTarget) throws PathException {
throw new UnsupportedMappingException( "Cannot apply TREAT operator to discriminator path" );
}
@Override
public SqmPath<T> getLhs() {
return (SqmPath<T>) super.getLhs().getLhs();
}
@Override
public AnyDiscriminatorSqmPathSource<T> getExpressible() {
return (AnyDiscriminatorSqmPathSource<T>) getNodeType();
}
}

View File

@ -6,11 +6,12 @@
*/
package org.hibernate.metamodel.model.domain.internal;
import org.hibernate.metamodel.model.domain.SimpleDomainType;
import org.hibernate.metamodel.mapping.CollectionPart;
import org.hibernate.query.ReturnableType;
import org.hibernate.query.sqm.SqmPathSource;
import org.hibernate.query.sqm.tree.domain.SqmPath;
import org.hibernate.spi.NavigablePath;
import org.hibernate.type.descriptor.java.JavaType;
/**
* SqmPathSource implementation for {@link org.hibernate.annotations.AnyDiscriminator}
@ -19,10 +20,9 @@ import org.hibernate.spi.NavigablePath;
public class AnyDiscriminatorSqmPathSource<D> extends AbstractSqmPathSource<D>
implements ReturnableType<D> {
public AnyDiscriminatorSqmPathSource(
String localPathName,
SimpleDomainType domainType,
AnyDiscriminatorDomainTypeImpl domainType,
BindableType jpaBindableType) {
super( localPathName, domainType, jpaBindableType );
}
@ -30,7 +30,7 @@ public class AnyDiscriminatorSqmPathSource<D> extends AbstractSqmPathSource<D>
@Override
public SqmPath<D> createSqmPath(SqmPath<?> lhs, SqmPathSource<?> intermediatePathSource) {
final NavigablePath navigablePath;
if ( intermediatePathSource == null ) {
if ( intermediatePathSource == null || intermediatePathSource.getPathName().equals( CollectionPart.Nature.ELEMENT.getName() ) ) {
navigablePath = lhs.getNavigablePath();
}
else {
@ -54,4 +54,13 @@ public class AnyDiscriminatorSqmPathSource<D> extends AbstractSqmPathSource<D>
return getExpressibleJavaType().getJavaTypeClass();
}
@Override
public AnyDiscriminatorDomainTypeImpl<D> getSqmPathType() {
return (AnyDiscriminatorDomainTypeImpl<D>) super.getSqmPathType();
}
@Override
public JavaType<D> getExpressibleJavaType() {
return getSqmPathType().getExpressibleJavaType();
}
}

View File

@ -19,10 +19,15 @@ import org.hibernate.type.descriptor.java.JavaType;
public class AnyMappingDomainTypeImpl<T> implements AnyMappingDomainType<T> {
private final AnyType anyType;
private final JavaType<T> baseJtd;
private final AnyDiscriminatorDomainTypeImpl<?> anyDiscriminatorType;
public AnyMappingDomainTypeImpl(AnyType anyType, JavaType<T> baseJtd) {
this.anyType = anyType;
this.baseJtd = baseJtd;
final MetaType discriminatorType = (MetaType) anyType.getDiscriminatorType();
anyDiscriminatorType = new AnyDiscriminatorDomainTypeImpl<>(
(BasicType<?>) discriminatorType.getBaseType(),
discriminatorType);
}
@Override
@ -41,8 +46,8 @@ public class AnyMappingDomainTypeImpl<T> implements AnyMappingDomainType<T> {
}
@Override
public SimpleDomainType<?> getDiscriminatorType() {
return (SimpleDomainType<?>) ((MetaType) anyType.getDiscriminatorType()).getBaseType();
public AnyDiscriminatorDomainTypeImpl<?> getDiscriminatorType() {
return anyDiscriminatorType;
}
@Override

View File

@ -29,7 +29,10 @@ public class AnyMappingSqmPathSource<J> extends AbstractSqmPathSource<J> {
BindableType jpaBindableType) {
super( localPathName, domainType, jpaBindableType );
keyPathSource = new BasicSqmPathSource<>( "id", (BasicDomainType<?>) domainType.getKeyType(), SINGULAR_ATTRIBUTE );
discriminatorPathSource = new AnyDiscriminatorSqmPathSource<>( localPathName, domainType.getDiscriminatorType(), jpaBindableType );
discriminatorPathSource = new AnyDiscriminatorSqmPathSource<>(
localPathName,
(AnyDiscriminatorDomainTypeImpl) domainType.getDiscriminatorType(), jpaBindableType
);
}
@Override @SuppressWarnings("unchecked")

View File

@ -2155,16 +2155,12 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
private <T> SqmExpression<T> createDiscriminatorValue(
AnyDiscriminatorSqmPath anyDiscriminatorTypeSqmPath,
HqlParser.ExpressionContext valueExpressionContext) {
//noinspection unchecked
final SqmPath<T> discriminatorSqmPath = anyDiscriminatorTypeSqmPath.getLhs();
final EntityDomainType<T> entityWithDiscriminator = creationContext.getJpaMetamodel()
.entity( discriminatorSqmPath.findRoot().getNavigablePath().getLocalName() );
final EntityDomainType<Object> entityDiscriminatorValue = creationContext.getJpaMetamodel()
.resolveHqlEntityReference( valueExpressionContext.getText() );
return new SqmAnyDiscriminatorValue<>(
entityWithDiscriminator,
discriminatorSqmPath.getNodeType().getPathName(),
entityDiscriminatorValue,
creationContext.getJpaMetamodel()
.entity( anyDiscriminatorTypeSqmPath.findRoot().getNavigablePath().getLocalName() ),
anyDiscriminatorTypeSqmPath.getNodeType().getPathName(),
creationContext.getJpaMetamodel().resolveHqlEntityReference( valueExpressionContext.getText() ),
anyDiscriminatorTypeSqmPath.getExpressible().getSqmPathType(),
creationContext.getNodeBuilder()
);
}

View File

@ -63,7 +63,6 @@ import org.hibernate.metamodel.mapping.BasicValuedMapping;
import org.hibernate.metamodel.mapping.BasicValuedModelPart;
import org.hibernate.metamodel.mapping.Bindable;
import org.hibernate.metamodel.mapping.CollectionPart;
import org.hibernate.metamodel.mapping.DiscriminatedAssociationModelPart;
import org.hibernate.metamodel.mapping.EmbeddableMappingType;
import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart;
import org.hibernate.metamodel.mapping.EntityAssociationMapping;
@ -84,7 +83,6 @@ import org.hibernate.metamodel.mapping.SelectableMappings;
import org.hibernate.metamodel.mapping.SqlExpressible;
import org.hibernate.metamodel.mapping.SqlTypedMapping;
import org.hibernate.metamodel.mapping.ValueMapping;
import org.hibernate.metamodel.mapping.internal.EmbeddedAttributeMapping;
import org.hibernate.metamodel.mapping.internal.EntityCollectionPart;
import org.hibernate.metamodel.mapping.internal.SqlTypedMappingImpl;
import org.hibernate.metamodel.mapping.internal.ToOneAttributeMapping;
@ -99,6 +97,8 @@ import org.hibernate.metamodel.model.domain.ManagedDomainType;
import org.hibernate.metamodel.model.domain.PluralPersistentAttribute;
import org.hibernate.metamodel.model.domain.SingularPersistentAttribute;
import org.hibernate.metamodel.model.domain.internal.AnyDiscriminatorSqmPath;
import org.hibernate.metamodel.model.domain.internal.AnyDiscriminatorSqmPathSource;
import org.hibernate.metamodel.model.domain.internal.AnyDiscriminatorDomainTypeImpl;
import org.hibernate.query.derived.AnonymousTupleTableGroupProducer;
import org.hibernate.query.derived.AnonymousTupleType;
import org.hibernate.metamodel.model.domain.internal.BasicSqmPathSource;
@ -5170,6 +5170,10 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
throw new NotYetImplementedFor6Exception( "Support for embedded-valued parameters not yet implemented" );
}
if ( paramSqmType instanceof AnyDiscriminatorSqmPathSource ) {
return (MappingModelExpressible<?>) ((AnyDiscriminatorSqmPathSource)paramSqmType).getSqmPathType();
}
if ( paramSqmType instanceof SqmPathSource<?> || paramSqmType instanceof BasicDomainType<?> ) {
// Try to infer the value mapping since the other side apparently is a path source
final MappingModelExpressible<?> inferredValueMapping = getInferredValueMapping();
@ -6233,50 +6237,10 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
@Override
public Expression visitAnyDiscriminatorTypeValueExpression(SqmAnyDiscriminatorValue expression) {
final EntityPersister mappingDescriptor = creationContext.getSessionFactory()
.getRuntimeMetamodels()
.getMappingMetamodel()
.getEntityDescriptor( ((EntityDomainType)expression.getNodeType()).getHibernateEntityName() );
for ( AttributeMapping attributeMapping : mappingDescriptor.getAttributeMappings() ) {
if ( attributeMapping instanceof EmbeddedAttributeMapping ) {
final ModelPart subPart = ( (EmbeddedAttributeMapping) attributeMapping ).findSubPart(
expression.getPathName(),
null
);
if ( subPart != null ) {
return buildQueryLiteral( expression, subPart );
}
}
else if ( attributeMapping.getAttributeName().equals( expression.getPathName() ) ) {
return buildQueryLiteral( expression, attributeMapping );
}
}
throw new HibernateException(String.format(
Locale.ROOT,
"Could not locate attribute mapping : %s -> %s",
mappingDescriptor.getEntityName(),
expression.getPathName()
));
}
private QueryLiteral<Object> buildQueryLiteral(
SqmAnyDiscriminatorValue expression,
ModelPart attributeMapping) {
final DiscriminatedAssociationModelPart discriminatedAssociationModelPart;
if ( attributeMapping instanceof PluralAttributeMapping ) {
discriminatedAssociationModelPart = (DiscriminatedAssociationModelPart) ( (PluralAttributeMapping) attributeMapping ).getElementDescriptor();
}
else {
assert attributeMapping instanceof DiscriminatedAssociationModelPart;
discriminatedAssociationModelPart = (DiscriminatedAssociationModelPart) attributeMapping;
}
final Object value = discriminatedAssociationModelPart.resolveDiscriminatorForEntityType(
creationContext.getMappingMetamodel()
.findEntityDescriptor( expression.getEntityValue().getHibernateEntityName() ) );
final AnyDiscriminatorDomainTypeImpl domainType = expression.getDomainType();
return new QueryLiteral<>(
value,
discriminatedAssociationModelPart.getDiscriminatorPart()
domainType.toRelationalValue( expression.getEntityValue().getHibernateEntityName() ),
domainType.getBasicType()
);
}

View File

@ -32,9 +32,9 @@ public class DiscriminatedAssociationTypePathInterpretation<T> extends AbstractS
AnyDiscriminatorSqmPath sqmPath,
SqmToSqlAstConverter converter) {
final SqmPath lhs = sqmPath.getLhs();
final TableGroup tableGroup = converter.getFromClauseAccess().findTableGroup( lhs.getLhs().getNavigablePath() );
final TableGroup tableGroup = converter.getFromClauseAccess().findTableGroup( lhs.getNavigablePath() );
final ModelPart subPart = tableGroup.getModelPart().findSubPart(
lhs.getNavigablePath().getLocalName(),
sqmPath.getNavigablePath().getLocalName(),
null
);

View File

@ -7,6 +7,7 @@
package org.hibernate.query.sqm.tree.expression;
import org.hibernate.metamodel.model.domain.EntityDomainType;
import org.hibernate.metamodel.model.domain.internal.AnyDiscriminatorDomainTypeImpl;
import org.hibernate.query.hql.HqlInterpretationException;
import org.hibernate.query.hql.spi.SemanticPathPart;
import org.hibernate.query.hql.spi.SqmCreationState;
@ -20,16 +21,23 @@ public class SqmAnyDiscriminatorValue<T> extends AbstractSqmExpression<T>
implements SqmSelectableNode<T>, SemanticPathPart {
private final EntityDomainType value;
private final AnyDiscriminatorDomainTypeImpl domainType;
private final String pathName;
public SqmAnyDiscriminatorValue(
EntityDomainType<T> entityWithDiscriminator,
String pathName,
EntityDomainType entityValue,
AnyDiscriminatorDomainTypeImpl domainType,
NodeBuilder nodeBuilder) {
super( entityWithDiscriminator, nodeBuilder );
this.value = entityValue;
this.pathName = pathName;
this.domainType = domainType;
}
public AnyDiscriminatorDomainTypeImpl getDomainType(){
return domainType;
}
@Override
@ -44,6 +52,7 @@ public class SqmAnyDiscriminatorValue<T> extends AbstractSqmExpression<T>
(EntityDomainType) getNodeType(),
pathName,
value,
domainType,
nodeBuilder()
)
);

View File

@ -49,6 +49,10 @@ public class MetaType extends AbstractType {
return discriminatorValuesToEntityNameMap;
}
public Map<String,Object> getEntityNameToDiscriminatorValueMap(){
return entityNameToDiscriminatorValueMap;
}
public int[] getSqlTypeCodes(Mapping mapping) throws MappingException {
return baseType.getSqlTypeCodes(mapping);
}
@ -131,5 +135,4 @@ public class MetaType extends AbstractType {
public boolean isDirty(Object old, Object current, boolean[] checkable, SharedSessionContractImplementor session) throws HibernateException {
return checkable[0] && isDirty(old, current, session);
}
}