Rely on fetch of version attribute mapping instead of creating domain result for version mapping for entity initializers to allow overriding the selection expression

This commit is contained in:
Christian Beikov 2021-08-30 15:01:58 +02:00
parent 58440ed42d
commit c01734adca
13 changed files with 165 additions and 40 deletions

View File

@ -293,8 +293,6 @@ tasks.withType(AsciidoctorTask).all {
test {
include '**/**'
exclude '**/HQLTest**'
exclude '**/SQLTest**' //derby failures
exclude '**/PostgreSQLFunctionWhereClauseTest**'
}
// resources inherently exclude sources

View File

@ -24,16 +24,14 @@ import org.hibernate.boot.spi.MetadataBuildingContext;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.metamodel.RuntimeMetamodels;
import org.hibernate.metamodel.mapping.AttributeMapping;
import org.hibernate.metamodel.mapping.BasicValuedModelPart;
import org.hibernate.metamodel.mapping.EntityDiscriminatorMapping;
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.mapping.EntityValuedModelPart;
import org.hibernate.metamodel.mapping.ModelPart;
import org.hibernate.metamodel.mapping.ModelPartContainer;
import org.hibernate.query.NavigablePath;
import org.hibernate.query.internal.FetchMementoBasicStandard;
import org.hibernate.query.internal.ImplicitAttributeFetchMemento;
import org.hibernate.query.internal.FetchMementoEntityStandard;
import org.hibernate.query.internal.ModelPartResultMementoBasicImpl;
import org.hibernate.query.internal.NamedResultSetMappingMementoImpl;
import org.hibernate.query.internal.ResultMementoBasicStandard;
@ -45,6 +43,7 @@ import org.hibernate.query.named.FetchMementoBasic;
import org.hibernate.query.named.NamedResultSetMappingMemento;
import org.hibernate.query.named.ResultMemento;
import org.hibernate.query.named.ResultMementoInstantiation.ArgumentMemento;
import org.hibernate.sql.results.graph.entity.EntityValuedFetchable;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
/**
@ -421,8 +420,8 @@ public class SqlResultSetMappingDescriptor implements NamedResultSetMappingDescr
return new FetchMementoBasicStandard( navigablePath, basicPart, columnNames.get( 0 ) );
}
else if ( subPart instanceof EntityValuedModelPart ) {
return new ImplicitAttributeFetchMemento( navigablePath, (AttributeMapping) subPart );
else if ( subPart instanceof EntityValuedFetchable ) {
return new FetchMementoEntityStandard( navigablePath, (EntityValuedFetchable) subPart, columnNames );
}
throw new NotYetImplementedFor6Exception(
"Only support for basic-valued model-parts have been implemented : " + propertyPath

View File

@ -0,0 +1,48 @@
/*
* 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.internal;
import java.util.List;
import java.util.function.Consumer;
import org.hibernate.query.NavigablePath;
import org.hibernate.query.named.FetchMemento;
import org.hibernate.query.results.FetchBuilder;
import org.hibernate.query.results.complete.CompleteFetchBuilderEntityValuedModelPart;
import org.hibernate.sql.results.graph.entity.EntityValuedFetchable;
/**
* @author Christian Beikov
*/
public class FetchMementoEntityStandard implements FetchMemento {
private final NavigablePath navigablePath;
private final EntityValuedFetchable attributeMapping;
private final List<String> columnNames;
public FetchMementoEntityStandard(
NavigablePath navigablePath,
EntityValuedFetchable attributeMapping,
List<String> columnNames) {
this.navigablePath = navigablePath;
this.attributeMapping = attributeMapping;
this.columnNames = columnNames;
}
@Override
public FetchBuilder resolve(
Parent parent,
Consumer<String> querySpaceConsumer,
ResultSetMappingResolutionContext context) {
return new CompleteFetchBuilderEntityValuedModelPart( navigablePath, attributeMapping, columnNames );
}
@Override
public NavigablePath getNavigablePath() {
return navigablePath;
}
}

View File

@ -0,0 +1,100 @@
/*
* 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.results.complete;
import java.util.List;
import java.util.function.BiFunction;
import org.hibernate.engine.FetchTiming;
import org.hibernate.query.NavigablePath;
import org.hibernate.query.results.DomainResultCreationStateImpl;
import org.hibernate.query.results.SqlSelectionImpl;
import org.hibernate.query.results.dynamic.DynamicFetchBuilderLegacy;
import org.hibernate.sql.ast.spi.SqlExpressionResolver;
import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.ast.tree.from.TableReference;
import org.hibernate.sql.results.graph.DomainResultCreationState;
import org.hibernate.sql.results.graph.Fetch;
import org.hibernate.sql.results.graph.FetchParent;
import org.hibernate.sql.results.graph.entity.EntityValuedFetchable;
import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata;
import static org.hibernate.query.results.ResultsHelper.impl;
import static org.hibernate.query.results.ResultsHelper.jdbcPositionToValuesArrayPosition;
/**
* CompleteFetchBuilder for entity-valued ModelParts
*
* @author Christian Beikov
*/
public class CompleteFetchBuilderEntityValuedModelPart
implements CompleteFetchBuilder, ModelPartReferenceEntity {
private final NavigablePath navigablePath;
private final EntityValuedFetchable modelPart;
private final List<String> columnAliases;
public CompleteFetchBuilderEntityValuedModelPart(
NavigablePath navigablePath,
EntityValuedFetchable modelPart,
List<String> columnAliases) {
this.navigablePath = navigablePath;
this.modelPart = modelPart;
this.columnAliases = columnAliases;
}
@Override
public NavigablePath getNavigablePath() {
return navigablePath;
}
@Override
public EntityValuedFetchable getReferencedPart() {
return modelPart;
}
@Override
public Fetch buildFetch(
FetchParent parent,
NavigablePath fetchPath,
JdbcValuesMetadata jdbcResultsMetadata,
BiFunction<String, String, DynamicFetchBuilderLegacy> legacyFetchResolver,
DomainResultCreationState domainResultCreationState) {
assert fetchPath.equals( navigablePath );
final DomainResultCreationStateImpl creationStateImpl = impl( domainResultCreationState );
final TableGroup tableGroup = creationStateImpl.getFromClauseAccess().getTableGroup( navigablePath.getParent() );
modelPart.forEachSelectable(
(selectionIndex, selectableMapping) -> {
final TableReference tableReference = tableGroup.getTableReference( navigablePath, selectableMapping.getContainingTableExpression() );
final String mappedColumn = selectableMapping.getSelectionExpression();
final String columnAlias = columnAliases.get( selectionIndex );
creationStateImpl.resolveSqlSelection(
creationStateImpl.resolveSqlExpression(
SqlExpressionResolver.createColumnReferenceKey( tableReference, mappedColumn ),
processingState -> {
final int jdbcPosition = jdbcResultsMetadata.resolveColumnPosition( columnAlias );
final int valuesArrayPosition = jdbcPositionToValuesArrayPosition( jdbcPosition );
return new SqlSelectionImpl( valuesArrayPosition, selectableMapping.getJdbcMapping() );
}
),
modelPart.getJavaTypeDescriptor(),
creationStateImpl.getSessionFactory().getTypeConfiguration()
);
}
);
return parent.generateFetchableFetch(
modelPart,
fetchPath,
FetchTiming.DELAYED,
true,
null,
domainResultCreationState
);
}
}

View File

@ -125,7 +125,7 @@ public class EntityResultImpl implements EntityResult {
@Override
public Fetch findFetch(Fetchable fetchable) {
for ( int i = 0; i < fetches.size(); i++ ) {
if ( fetches.get( i ).getFetchedMapping() == fetchable ) {
if ( fetches.get( i ).getFetchedMapping().getFetchableName().equals( fetchable.getFetchableName() ) ) {
return fetches.get( i );
}
}
@ -145,7 +145,6 @@ public class EntityResultImpl implements EntityResult {
identifierResult,
discriminatorFetch,
null,
null,
creationState
)
);

View File

@ -302,6 +302,7 @@ import org.hibernate.sql.results.graph.instantiation.internal.DynamicInstantiati
import org.hibernate.sql.results.internal.SqlSelectionImpl;
import org.hibernate.sql.results.internal.StandardEntityGraphTraversalStateImpl;
import org.hibernate.type.BasicType;
import org.hibernate.type.JavaObjectType;
import org.hibernate.type.StandardBasicTypes;
import org.hibernate.type.VersionType;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
@ -2725,7 +2726,10 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
if ( inferredMapping instanceof PluralAttributeMapping ) {
return ( (PluralAttributeMapping) inferredMapping ).getElementDescriptor();
}
return inferredMapping;
else if ( !( inferredMapping instanceof JavaObjectType ) ) {
// Never report back the "object type" as inferred type and instead rely on the value type
return inferredMapping;
}
}
}
}

View File

@ -33,6 +33,7 @@ import org.hibernate.internal.util.StringHelper;
import org.hibernate.loader.entity.CacheEntityLoaderHelper;
import org.hibernate.metamodel.mapping.AttributeMapping;
import org.hibernate.metamodel.mapping.EntityValuedModelPart;
import org.hibernate.metamodel.mapping.EntityVersionMapping;
import org.hibernate.metamodel.mapping.ModelPart;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.proxy.HibernateProxy;
@ -99,7 +100,6 @@ public abstract class AbstractEntityInitializer extends AbstractFetchParentAcces
LockMode lockMode,
DomainResult<?> identifierResult,
Fetch discriminatorFetch,
DomainResult<?> versionResult,
DomainResult<Object> rowIdResult,
AssemblerCreationState creationState) {
super();
@ -176,8 +176,12 @@ public abstract class AbstractEntityInitializer extends AbstractFetchParentAcces
discriminatorAssembler = null;
}
if ( versionResult != null ) {
this.versionAssembler = versionResult.createResultAssembler( creationState );
final EntityVersionMapping versionMapping = entityDescriptor.getVersionMapping();
if ( versionMapping != null ) {
final Fetch versionFetch = resultDescriptor.findFetch( versionMapping );
// If there is a version mapping, there must be a fetch for it
assert versionFetch != null;
this.versionAssembler = versionFetch.createAssembler( this, creationState );
}
else {
this.versionAssembler = null;

View File

@ -12,7 +12,6 @@ import org.hibernate.metamodel.mapping.EntityIdentifierMapping;
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.mapping.EntityRowIdMapping;
import org.hibernate.metamodel.mapping.EntityValuedModelPart;
import org.hibernate.metamodel.mapping.EntityVersionMapping;
import org.hibernate.metamodel.mapping.ManagedMappingType;
import org.hibernate.metamodel.mapping.MappingType;
import org.hibernate.metamodel.mapping.internal.ToOneAttributeMapping;
@ -38,7 +37,6 @@ public abstract class AbstractEntityResultGraphNode extends AbstractFetchParent
private final EntityValuedModelPart referencedModelPart;
private final DomainResult<?> identifierResult;
private final BasicFetch<?> discriminatorFetch;
private final DomainResult<?> versionResult;
private final DomainResult<Object> rowIdResult;
private final EntityMappingType targetType;
@ -118,19 +116,6 @@ public abstract class AbstractEntityResultGraphNode extends AbstractFetchParent
discriminatorFetch = null;
}
final EntityVersionMapping versionDescriptor = entityDescriptor.getVersionMapping();
if ( versionDescriptor == null ) {
versionResult = null;
}
else {
versionResult = versionDescriptor.createDomainResult(
navigablePath.append( versionDescriptor.getFetchableName() ),
entityTableGroup,
null,
creationState
);
}
final EntityRowIdMapping rowIdMapping = entityDescriptor.getRowIdMapping();
if ( rowIdMapping == null ) {
rowIdResult = null;
@ -212,10 +197,6 @@ public abstract class AbstractEntityResultGraphNode extends AbstractFetchParent
return discriminatorFetch;
}
public DomainResult getVersionResult() {
return versionResult;
}
public DomainResult<Object> getRowIdResult() {
return rowIdResult;
}

View File

@ -58,7 +58,6 @@ public class EntityFetchJoinedImpl extends AbstractNonLazyEntityFetch {
creationState.determineEffectiveLockMode( sourceAlias ),
entityResult.getIdentifierResult(),
entityResult.getDiscriminatorFetch(),
entityResult.getVersionResult(),
creationState
)
);

View File

@ -20,7 +20,6 @@ import org.hibernate.query.NavigablePath;
import org.hibernate.sql.results.graph.AssemblerCreationState;
import org.hibernate.sql.results.graph.DomainResult;
import org.hibernate.sql.results.graph.Fetch;
import org.hibernate.sql.results.graph.basic.BasicFetch;
import org.hibernate.sql.results.graph.entity.AbstractEntityInitializer;
import org.hibernate.sql.results.graph.entity.EntityResultGraphNode;
import org.hibernate.sql.results.jdbc.spi.RowProcessingState;
@ -41,7 +40,6 @@ public class EntityJoinedFetchInitializer extends AbstractEntityInitializer {
LockMode lockMode,
DomainResult<?> identifierResult,
Fetch discriminatorResult,
DomainResult<?> versionResult,
AssemblerCreationState creationState) {
super(
resultDescriptor,
@ -49,7 +47,6 @@ public class EntityJoinedFetchInitializer extends AbstractEntityInitializer {
lockMode,
identifierResult,
discriminatorResult,
versionResult,
null,
creationState
);

View File

@ -104,7 +104,6 @@ public class EntityResultImpl extends AbstractEntityResultGraphNode implements E
getLockMode( creationState ),
getIdentifierResult(),
getDiscriminatorFetch(),
getVersionResult(),
getRowIdResult(),
creationState
)

View File

@ -28,7 +28,6 @@ public class EntityResultInitializer extends AbstractEntityInitializer {
LockMode lockMode,
DomainResult identifierResult,
BasicFetch<?> discriminatorFetch,
DomainResult versionResult,
DomainResult<Object> rowIdResult,
AssemblerCreationState creationState) {
super(
@ -37,7 +36,6 @@ public class EntityResultInitializer extends AbstractEntityInitializer {
lockMode,
identifierResult,
discriminatorFetch,
versionResult,
rowIdResult,
creationState
);

View File

@ -41,7 +41,6 @@ public class EntityResultJoinedSubclassImpl extends EntityResultImpl {
getLockMode( creationState ),
getIdentifierResult(),
getDiscriminatorFetch(),
getVersionResult(),
getRowIdResult(),
creationState
)