Fix Delaying Basic attribute fetching

This commit is contained in:
Andrea Boriero 2021-09-30 19:31:01 +02:00 committed by Christian Beikov
parent b872d8ad74
commit 18fee9cf5a
5 changed files with 72 additions and 6 deletions

View File

@ -83,6 +83,7 @@ public class ResultMementoEntityJpa implements ResultMementoEntity, FetchMemento
) )
); );
final boolean isEnhancedForLazyLoading = entityDescriptor.getRepresentationStrategy().isBytecodeEnhanced();
// Implicit basic fetches are DELAYED by default, so register fetch builders for the remaining basic fetchables // Implicit basic fetches are DELAYED by default, so register fetch builders for the remaining basic fetchables
entityDescriptor.visitAttributeMappings( entityDescriptor.visitAttributeMappings(
attributeMapping -> { attributeMapping -> {
@ -90,7 +91,8 @@ public class ResultMementoEntityJpa implements ResultMementoEntity, FetchMemento
if ( attributeMapping instanceof BasicValuedModelPart ) { if ( attributeMapping instanceof BasicValuedModelPart ) {
fetchBuilderCreator = k -> new DelayedFetchBuilderBasicPart( fetchBuilderCreator = k -> new DelayedFetchBuilderBasicPart(
navigablePath.append( k ), navigablePath.append( k ),
(BasicValuedModelPart) attributeMapping (BasicValuedModelPart) attributeMapping,
isEnhancedForLazyLoading
); );
explicitFetchBuilderMap.computeIfAbsent( explicitFetchBuilderMap.computeIfAbsent(
attributeMapping.getFetchableName(), attributeMapping.getFetchableName(),

View File

@ -25,12 +25,15 @@ public class DelayedFetchBuilderBasicPart
implements CompleteFetchBuilder, BasicValuedFetchBuilder, ModelPartReferenceBasic { implements CompleteFetchBuilder, BasicValuedFetchBuilder, ModelPartReferenceBasic {
private final NavigablePath navigablePath; private final NavigablePath navigablePath;
private final BasicValuedModelPart referencedModelPart; private final BasicValuedModelPart referencedModelPart;
private final boolean isEnhancedForLazyLoading;
public DelayedFetchBuilderBasicPart( public DelayedFetchBuilderBasicPart(
NavigablePath navigablePath, NavigablePath navigablePath,
BasicValuedModelPart referencedModelPart) { BasicValuedModelPart referencedModelPart,
boolean isEnhancedForLazyLoading) {
this.navigablePath = navigablePath; this.navigablePath = navigablePath;
this.referencedModelPart = referencedModelPart; this.referencedModelPart = referencedModelPart;
this.isEnhancedForLazyLoading = isEnhancedForLazyLoading;
} }
@Override @Override
@ -58,6 +61,7 @@ public class DelayedFetchBuilderBasicPart
true, true,
null, null,
FetchTiming.DELAYED, FetchTiming.DELAYED,
isEnhancedForLazyLoading,
domainResultCreationState domainResultCreationState
); );
} }

View File

@ -0,0 +1,30 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
* See the lgpl.txt file in the root directory or <http://www.gnu.org/licenses/lgpl-2.1.html>.
*/
package org.hibernate.sql.results.graph;
import org.hibernate.sql.results.jdbc.spi.JdbcValuesSourceProcessingOptions;
import org.hibernate.sql.results.jdbc.spi.RowProcessingState;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
public class UnfetchedBasicPartResultAssembler<J> implements DomainResultAssembler<J> {
private final JavaTypeDescriptor<J> javaTypeDescriptor;
public UnfetchedBasicPartResultAssembler(JavaTypeDescriptor<J> javaTypeDescriptor) {
this.javaTypeDescriptor = javaTypeDescriptor;
}
@Override
public J assemble(RowProcessingState rowProcessingState, JdbcValuesSourceProcessingOptions options) {
return null;
}
@Override
public JavaTypeDescriptor<J> getAssembledJavaTypeDescriptor() {
return javaTypeDescriptor;
}
}

View File

@ -12,6 +12,7 @@ import org.hibernate.metamodel.model.convert.spi.BasicValueConverter;
import org.hibernate.query.NavigablePath; import org.hibernate.query.NavigablePath;
import org.hibernate.query.results.ResultsHelper; import org.hibernate.query.results.ResultsHelper;
import org.hibernate.sql.results.graph.AssemblerCreationState; import org.hibernate.sql.results.graph.AssemblerCreationState;
import org.hibernate.sql.results.graph.UnfetchedBasicPartResultAssembler;
import org.hibernate.sql.results.graph.UnfetchedResultAssembler; import org.hibernate.sql.results.graph.UnfetchedResultAssembler;
import org.hibernate.sql.results.graph.DomainResult; import org.hibernate.sql.results.graph.DomainResult;
import org.hibernate.sql.results.graph.DomainResultAssembler; import org.hibernate.sql.results.graph.DomainResultAssembler;
@ -44,17 +45,44 @@ public class BasicFetch<T> implements Fetch, BasicResultGraphNode<T> {
BasicValueConverter<T, ?> valueConverter, BasicValueConverter<T, ?> valueConverter,
FetchTiming fetchTiming, FetchTiming fetchTiming,
DomainResultCreationState creationState) { DomainResultCreationState creationState) {
this(
valuesArrayPosition,
fetchParent,
fetchablePath,
valuedMapping,
nullable,
valueConverter,
fetchTiming,
true,
creationState
);
}
public BasicFetch(
int valuesArrayPosition,
FetchParent fetchParent,
NavigablePath fetchablePath,
BasicValuedModelPart valuedMapping,
boolean nullable,
BasicValueConverter<T, ?> valueConverter,
FetchTiming fetchTiming,
boolean canBasicPartFetchBeDelayed,
DomainResultCreationState creationState) {
this.nullable = nullable; this.nullable = nullable;
this.navigablePath = fetchablePath; this.navigablePath = fetchablePath;
this.fetchParent = fetchParent; this.fetchParent = fetchParent;
this.valuedMapping = valuedMapping; this.valuedMapping = valuedMapping;
this.fetchTiming = fetchTiming; this.fetchTiming = fetchTiming;
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked") final JavaTypeDescriptor<T> javaTypeDescriptor = (JavaTypeDescriptor<T>) valuedMapping.getJavaTypeDescriptor();
final JavaTypeDescriptor<T> javaTypeDescriptor = (JavaTypeDescriptor<T>) valuedMapping.getJavaTypeDescriptor();
// lazy basic attribute // lazy basic attribute
if ( fetchTiming == FetchTiming.DELAYED && valuesArrayPosition == -1 ) { if ( fetchTiming == FetchTiming.DELAYED && valuesArrayPosition == -1 ) {
this.assembler = new UnfetchedResultAssembler<>( javaTypeDescriptor ); if ( canBasicPartFetchBeDelayed ) {
this.assembler = new UnfetchedResultAssembler<>( javaTypeDescriptor );
}
else {
this.assembler = new UnfetchedBasicPartResultAssembler( javaTypeDescriptor );
}
} }
else { else {
this.assembler = new BasicResultAssembler<>( this.assembler = new BasicResultAssembler<>(

View File

@ -20,6 +20,7 @@ import org.junit.jupiter.api.Test;
import static org.hibernate.testing.orm.junit.ExtraAssertions.assertTyping; import static org.hibernate.testing.orm.junit.ExtraAssertions.assertTyping;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;
/** /**
* @author Steve Ebersole * @author Steve Ebersole
@ -86,7 +87,8 @@ public class ResultMappingTest extends BaseSessionFactoryFunctionalTest {
final ResultSetOutput resultSetReturn = assertTyping( ResultSetOutput.class, currentOutput ); final ResultSetOutput resultSetReturn = assertTyping( ResultSetOutput.class, currentOutput );
final Object result = resultSetReturn.getSingleResult(); final Object result = resultSetReturn.getSingleResult();
assertTyping( H2ProcTesting.MyEntity.class, result ); assertTyping( H2ProcTesting.MyEntity.class, result );
assertEquals( "Steve", ( (H2ProcTesting.MyEntity) result ).name ); assertNull( ( (H2ProcTesting.MyEntity) result ).name );
assertNotNull( ( (H2ProcTesting.MyEntity) result ).id );
} }
); );
} }