Cleanup the circular handling of fetch building of embeddable FKs. Use the target navigable path for target FK domain results

This commit is contained in:
Christian Beikov 2021-05-06 07:28:39 +02:00
parent 1a24c93155
commit a7ed354af9
9 changed files with 105 additions and 35 deletions

View File

@ -693,15 +693,17 @@ public class LoaderSelectBuilder {
fetchablePath = fetchParent.resolveNavigablePath( fetchable );
}
final Fetch biDirectionalFetch = fetchable.resolveCircularFetch(
fetchablePath,
fetchParent,
creationState
);
if ( !creationState.isResolvingCircularFetch() ) {
final Fetch biDirectionalFetch = fetchable.resolveCircularFetch(
fetchablePath,
fetchParent,
creationState
);
if ( biDirectionalFetch != null ) {
fetches.add( biDirectionalFetch );
return;
if ( biDirectionalFetch != null ) {
fetches.add( biDirectionalFetch );
return;
}
}
final LockMode lockMode = LockMode.READ;

View File

@ -55,6 +55,7 @@ public class LoaderSqlAstCreationState
private final LockOptions lockOptions;
private final FetchProcessor fetchProcessor;
private boolean resolvingCircularFetch;
private Set<AssociationKey> visitedAssociationKeys = new HashSet<>();
public LoaderSqlAstCreationState(
@ -114,6 +115,16 @@ public class LoaderSqlAstCreationState
return fetchProcessor.visitFetches( fetchParent, processingState.getInflightQueryPart().getFirstQuerySpec(), this );
}
@Override
public boolean isResolvingCircularFetch() {
return resolvingCircularFetch;
}
@Override
public void setResolvingCircularFetch(boolean resolvingCircularFetch) {
this.resolvingCircularFetch = resolvingCircularFetch;
}
@Override
public boolean forceIdentifierSelection() {
return forceIdentifierSelection;

View File

@ -25,7 +25,6 @@ import org.hibernate.sql.results.graph.DomainResultCreationState;
*/
public interface ForeignKeyDescriptor extends VirtualModelPart {
String PART_NAME = "{fk}";
String TARGET_PART_NAME = "{fk-target}";
String getKeyTable();

View File

@ -15,12 +15,15 @@ import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.mapping.IndexedConsumer;
import org.hibernate.metamodel.mapping.AssociationKey;
import org.hibernate.metamodel.mapping.AttributeMapping;
import org.hibernate.metamodel.mapping.CollectionPart;
import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart;
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.mapping.ForeignKeyDescriptor;
import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.mapping.MappingType;
import org.hibernate.metamodel.mapping.ModelPart;
import org.hibernate.metamodel.mapping.ModelPartContainer;
import org.hibernate.metamodel.mapping.PluralAttributeMapping;
import org.hibernate.metamodel.mapping.SelectableConsumer;
import org.hibernate.metamodel.mapping.SelectableMapping;
import org.hibernate.metamodel.mapping.SelectableMappings;
@ -239,10 +242,20 @@ public class EmbeddedForeignKeyDescriptor implements ForeignKeyDescriptor {
final NavigablePath fkNavigablePath = navigablePath.append( getPartName() );
final NavigablePath resultNavigablePath;
if ( associationKey.getTable().equals( columnContainingTable ) ) {
// todo (6.0): what if we append the actual model part and maybe prefix with `{element}`
// resultNavigablePath = navigablePath.append( modelPart.getFetchableName() );
// todo (6.0): note that the following is only necessary for detecting circular fetch cycles in ToOneAttributeMapping
resultNavigablePath = navigablePath.append( ForeignKeyDescriptor.TARGET_PART_NAME );
final ModelPartContainer parentModelPart = tableGroup.getModelPart();
if ( parentModelPart instanceof PluralAttributeMapping ) {
if ( ( (PluralAttributeMapping) parentModelPart ).getIndexDescriptor() == null ) {
resultNavigablePath = navigablePath.append( CollectionPart.Nature.ELEMENT.getName() )
.append( getPartName() );
}
else {
resultNavigablePath = navigablePath.append( CollectionPart.Nature.INDEX.getName() )
.append( getPartName() );
}
}
else {
resultNavigablePath = navigablePath.append( getPartName() );
}
}
else {
resultNavigablePath = navigablePath.append( getPartName() );

View File

@ -532,17 +532,25 @@ public class PluralAttributeMappingImpl
NavigablePath fetchablePath,
DomainResultCreationState creationState,
SqlAstCreationState sqlAstCreationState) {
final DomainResult fkResult = getKeyDescriptor().createDomainResult(
fetchablePath,
sqlAstCreationState.getFromClauseAccess().getTableGroup( fetchParent.getNavigablePath() ),
false,
creationState
);
final DomainResult<?> foreignKeyDomainResult;
assert !creationState.isResolvingCircularFetch();
try {
creationState.setResolvingCircularFetch( true );
foreignKeyDomainResult = getKeyDescriptor().createDomainResult(
fetchablePath,
sqlAstCreationState.getFromClauseAccess().getTableGroup( fetchParent.getNavigablePath() ),
false,
creationState
);
}
finally {
creationState.setResolvingCircularFetch( false );
}
return new DelayedCollectionFetch(
fetchablePath,
this,
fetchParent,
fkResult
foreignKeyDomainResult
);
}

View File

@ -380,9 +380,7 @@ public class ToOneAttributeMapping
private Key key;
}
*/
if ( parentNavigablePath.getLocalName()
.equals( ForeignKeyDescriptor.TARGET_PART_NAME ) || parentNavigablePath.getLocalName().equals(
ForeignKeyDescriptor.PART_NAME ) ) {
if ( parentNavigablePath.getLocalName().equals( ForeignKeyDescriptor.PART_NAME ) ) {
// todo (6.0): maybe it's better to have a flag in creation state that marks if we are building a circular fetch domain result already to skip this?
return null;
}
@ -474,6 +472,19 @@ public class ToOneAttributeMapping
.getSqlAstCreationState()
.getFromClauseAccess()
.getTableGroup( fetchParent.getNavigablePath() );
final DomainResult<?> foreignKeyDomainResult;
assert !creationState.isResolvingCircularFetch();
try {
creationState.setResolvingCircularFetch( true );
foreignKeyDomainResult = foreignKeyDescriptor.createDomainResult(
fetchablePath,
parentTableGroup,
creationState
);
}
finally {
creationState.setResolvingCircularFetch( false );
}
return new CircularFetchImpl(
this,
getEntityMappingType(),
@ -482,7 +493,7 @@ public class ToOneAttributeMapping
fetchParent,
this,
fetchablePath,
foreignKeyDescriptor.createDomainResult( fetchablePath, parentTableGroup, creationState )
foreignKeyDomainResult
);
}
}

View File

@ -76,6 +76,7 @@ public class DomainResultCreationStateImpl
private final Stack<Function<String, FetchBuilder>> fetchBuilderResolverStack = new StandardStack<>( fetchableName -> null );
private final Stack<NavigablePath> relativePathStack = new StandardStack<>();
private boolean processingKeyFetches = false;
private boolean resolvingCircularFetch;
public DomainResultCreationStateImpl(
String stateIdentifier,
@ -409,4 +410,14 @@ public class DomainResultCreationStateImpl
return fetches;
}
@Override
public boolean isResolvingCircularFetch() {
return resolvingCircularFetch;
}
@Override
public void setResolvingCircularFetch(boolean resolvingCircularFetch) {
this.resolvingCircularFetch = resolvingCircularFetch;
}
}

View File

@ -338,6 +338,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
private final EntityGraphTraversalState entityGraphTraversalState;
private int fetchDepth;
private boolean resolvingCircularFetch;
private Map<String, FilterPredicate> collectionFilterPredicates;
private OrderByFragmentConsumer orderByFragmentConsumer;
@ -537,9 +538,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
public Stack<Clause> getCurrentClauseStack() {
return currentClauseStack;
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Statements
@Override
@ -4459,15 +4458,17 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
final BiConsumer<Fetchable, Boolean> fetchableBiConsumer = (fetchable, isKeyFetchable) -> {
final NavigablePath fetchablePath = fetchParent.resolveNavigablePath( fetchable );
final Fetch biDirectionalFetch = fetchable.resolveCircularFetch(
fetchablePath,
fetchParent,
this
);
if ( !isResolvingCircularFetch() ) {
final Fetch biDirectionalFetch = fetchable.resolveCircularFetch(
fetchablePath,
fetchParent,
this
);
if ( biDirectionalFetch != null ) {
fetches.add( biDirectionalFetch );
return;
if ( biDirectionalFetch != null ) {
fetches.add( biDirectionalFetch );
return;
}
}
final boolean incrementFetchDepth = fetchable.incrementFetchDepth();
@ -4688,6 +4689,16 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
}
}
@Override
public boolean isResolvingCircularFetch() {
return resolvingCircularFetch;
}
@Override
public void setResolvingCircularFetch(boolean resolvingCircularFetch) {
this.resolvingCircularFetch = resolvingCircularFetch;
}
@Internal
public interface SqmAliasedNodeCollector {
void next();

View File

@ -77,4 +77,8 @@ public interface DomainResultCreationState {
* along FetchStyle?
*/
List<Fetch> visitFetches(FetchParent fetchParent);
boolean isResolvingCircularFetch();
void setResolvingCircularFetch(boolean resolvingCircularFetch);
}