Introduce enum for describing KEY and TARGET of FK and use/expose that to describe the FK direction of to-one associations

This commit is contained in:
Christian Beikov 2021-05-07 17:32:50 +02:00
parent a864e25339
commit 3be99c1c73
17 changed files with 219 additions and 192 deletions

View File

@ -17,6 +17,7 @@ import org.hibernate.LockMode;
import org.hibernate.LockOptions;
import org.hibernate.graph.spi.AppliedGraph;
import org.hibernate.metamodel.mapping.AssociationKey;
import org.hibernate.metamodel.mapping.ForeignKeyDescriptor;
import org.hibernate.metamodel.mapping.ModelPart;
import org.hibernate.query.Limit;
import org.hibernate.query.NavigablePath;
@ -56,6 +57,7 @@ public class LoaderSqlAstCreationState
private final FetchProcessor fetchProcessor;
private boolean resolvingCircularFetch;
private ForeignKeyDescriptor.Side currentlyResolvingForeignKeySide;
private Set<AssociationKey> visitedAssociationKeys = new HashSet<>();
public LoaderSqlAstCreationState(
@ -125,6 +127,16 @@ public class LoaderSqlAstCreationState
this.resolvingCircularFetch = resolvingCircularFetch;
}
@Override
public ForeignKeyDescriptor.Side getCurrentlyResolvingForeignKeyPart() {
return currentlyResolvingForeignKeySide;
}
@Override
public void setCurrentlyResolvingForeignKeyPart(ForeignKeyDescriptor.Side currentlyResolvingForeignKeySide) {
this.currentlyResolvingForeignKeySide = currentlyResolvingForeignKeySide;
}
@Override
public boolean forceIdentifierSelection() {
return forceIdentifierSelection;

View File

@ -13,4 +13,5 @@ import org.hibernate.sql.results.graph.Fetchable;
*/
public interface Association extends Fetchable {
ForeignKeyDescriptor getForeignKeyDescriptor();
ForeignKeyDescriptor.Side getSide();
}

View File

@ -24,6 +24,12 @@ import org.hibernate.sql.results.graph.DomainResultCreationState;
* Descriptor for foreign-keys
*/
public interface ForeignKeyDescriptor extends VirtualModelPart {
enum Side {
KEY,
TARGET;
}
String PART_NAME = "{fk}";
String getKeyTable();
@ -38,7 +44,7 @@ public interface ForeignKeyDescriptor extends VirtualModelPart {
* Create a DomainResult for the referring-side of the fk
*/
DomainResult<?> createKeyDomainResult(
NavigablePath collectionPath,
NavigablePath navigablePath,
TableGroup tableGroup,
DomainResultCreationState creationState);
@ -46,24 +52,19 @@ public interface ForeignKeyDescriptor extends VirtualModelPart {
* Create a DomainResult for the target-side of the fk
*/
DomainResult<?> createTargetDomainResult(
NavigablePath collectionPath,
TableGroup tableGroup,
DomainResultCreationState creationState);
DomainResult createCollectionFetchDomainResult(
NavigablePath collectionPath,
TableGroup tableGroup,
DomainResultCreationState creationState);
DomainResult createDomainResult(
NavigablePath navigablePath,
TableGroup tableGroup,
DomainResultCreationState creationState);
DomainResult createDomainResult(
DomainResult<?> createCollectionFetchDomainResult(
NavigablePath collectionPath,
TableGroup tableGroup,
DomainResultCreationState creationState);
DomainResult<?> createDomainResult(
NavigablePath navigablePath,
TableGroup tableGroup,
boolean isKeyReferringSide,
Side side,
DomainResultCreationState creationState);
Predicate generateJoinPredicate(

View File

@ -58,7 +58,7 @@ public class EmbeddedForeignKeyDescriptor implements ForeignKeyDescriptor {
private final SelectableMappings keySelectableMappings;
private final String targetTable;
private final SelectableMappings targetSelectableMappings;
private AssociationKey associationKey;
private final AssociationKey associationKey;
public EmbeddedForeignKeyDescriptor(
EmbeddableValuedModelPart keyMappingType,
@ -74,6 +74,13 @@ public class EmbeddedForeignKeyDescriptor implements ForeignKeyDescriptor {
this.targetSelectableMappings = targetSelectableMappings;
this.targetMappingType = targetMappingType;
this.keyMappingType = keyMappingType;
final List<String> columns = new ArrayList<>( keySelectableMappings.getJdbcTypeCount() );
keySelectableMappings.forEachSelectable(
(columnIndex, selection) -> {
columns.add( selection.getSelectionExpression() );
}
);
this.associationKey = new AssociationKey( keyTable, columns );
creationProcess.registerInitializationCallback(
"Embedded (composite) FK descriptor " + targetMappingType.getNavigableRole(),
@ -105,6 +112,13 @@ public class EmbeddedForeignKeyDescriptor implements ForeignKeyDescriptor {
keySelectableMappings,
creationProcess
);
final List<String> columns = new ArrayList<>( keySelectableMappings.getJdbcTypeCount() );
keySelectableMappings.forEachSelectable(
(columnIndex, selection) -> {
columns.add( selection.getSelectionExpression() );
}
);
this.associationKey = new AssociationKey( keyTable, columns );
}
@Override
@ -135,14 +149,13 @@ public class EmbeddedForeignKeyDescriptor implements ForeignKeyDescriptor {
@Override
public DomainResult<?> createKeyDomainResult(
NavigablePath collectionPath,
NavigablePath navigablePath,
TableGroup tableGroup,
DomainResultCreationState creationState) {
assert tableGroup.getTableReference( collectionPath, keyTable ) != null;
return createDomainResult(
collectionPath,
navigablePath,
tableGroup,
null,
keyTable,
keyMappingType,
creationState
@ -151,14 +164,15 @@ public class EmbeddedForeignKeyDescriptor implements ForeignKeyDescriptor {
@Override
public DomainResult<?> createTargetDomainResult(
NavigablePath collectionPath,
NavigablePath navigablePath,
TableGroup tableGroup,
DomainResultCreationState creationState) {
assert tableGroup.getTableReference( collectionPath, targetTable ) != null;
assert tableGroup.getTableReference( navigablePath, targetTable ) != null;
return createDomainResult(
collectionPath,
navigablePath,
tableGroup,
null,
targetTable,
targetMappingType,
creationState
@ -166,7 +180,7 @@ public class EmbeddedForeignKeyDescriptor implements ForeignKeyDescriptor {
}
@Override
public DomainResult createCollectionFetchDomainResult(
public DomainResult<?> createCollectionFetchDomainResult(
NavigablePath collectionPath,
TableGroup tableGroup,
DomainResultCreationState creationState) {
@ -174,6 +188,7 @@ public class EmbeddedForeignKeyDescriptor implements ForeignKeyDescriptor {
return createDomainResult(
collectionPath,
tableGroup,
null,
targetTable,
targetMappingType,
creationState
@ -183,6 +198,7 @@ public class EmbeddedForeignKeyDescriptor implements ForeignKeyDescriptor {
return createDomainResult(
collectionPath,
tableGroup,
null,
keyTable,
keyMappingType,
creationState
@ -191,29 +207,16 @@ public class EmbeddedForeignKeyDescriptor implements ForeignKeyDescriptor {
}
@Override
public DomainResult createDomainResult(
public DomainResult<?> createDomainResult(
NavigablePath navigablePath,
TableGroup tableGroup,
Side side,
DomainResultCreationState creationState) {
return createDomainResult(
navigablePath,
tableGroup,
keyTable,
keyMappingType,
creationState
);
}
@Override
public DomainResult createDomainResult(
NavigablePath navigablePath,
TableGroup tableGroup,
boolean isKeyReferringSide,
DomainResultCreationState creationState) {
if ( isKeyReferringSide ) {
if ( side == Side.KEY ) {
return createDomainResult(
navigablePath,
tableGroup,
null,
keyTable,
keyMappingType,
creationState
@ -223,6 +226,7 @@ public class EmbeddedForeignKeyDescriptor implements ForeignKeyDescriptor {
return createDomainResult(
navigablePath,
tableGroup,
null,
targetTable,
targetMappingType,
creationState
@ -230,9 +234,19 @@ public class EmbeddedForeignKeyDescriptor implements ForeignKeyDescriptor {
}
}
private DomainResult createDomainResult(
@Override
public <T> DomainResult<T> createDomainResult(
NavigablePath navigablePath,
TableGroup tableGroup,
String resultVariable,
DomainResultCreationState creationState) {
return createDomainResult( navigablePath, tableGroup, resultVariable, keyTable, keyMappingType, creationState );
}
private <T> DomainResult<T> createDomainResult(
NavigablePath navigablePath,
TableGroup tableGroup,
String resultVariable,
String columnContainingTable,
EmbeddableValuedModelPart modelPart,
DomainResultCreationState creationState) {
@ -279,12 +293,19 @@ public class EmbeddedForeignKeyDescriptor implements ForeignKeyDescriptor {
);
}
return new EmbeddableForeignKeyResultImpl<>(
resultNavigablePath,
modelPart,
null,
creationState
);
final Side currentForeignKeyResolvingKey = creationState.getCurrentlyResolvingForeignKeyPart();
try {
creationState.setCurrentlyResolvingForeignKeyPart( keyMappingType == modelPart ? Side.KEY : Side.TARGET );
return new EmbeddableForeignKeyResultImpl<>(
resultNavigablePath,
modelPart,
resultVariable,
creationState
);
}
finally {
creationState.setCurrentlyResolvingForeignKeyPart( currentForeignKeyResolvingKey );
}
}
@Override
@ -420,15 +441,6 @@ public class EmbeddedForeignKeyDescriptor implements ForeignKeyDescriptor {
@Override
public AssociationKey getAssociationKey() {
if ( associationKey == null ) {
final List<String> columns = new ArrayList<>();
keySelectableMappings.forEachSelectable(
(columnIndex, selection) -> {
columns.add( selection.getSelectionExpression() );
}
);
associationKey = new AssociationKey( keyTable, columns );
}
return associationKey;
}
@ -457,38 +469,6 @@ public class EmbeddedForeignKeyDescriptor implements ForeignKeyDescriptor {
return targetMappingType.getNavigableRole();
}
@Override
public <T> DomainResult<T> createDomainResult(
NavigablePath navigablePath,
TableGroup tableGroup,
String resultVariable,
DomainResultCreationState creationState) {
final NavigablePath fkNavigablePath = navigablePath.append( getPartName() );
creationState.getSqlAstCreationState().getFromClauseAccess().resolveTableGroup(
fkNavigablePath,
np -> {
final TableGroupJoin tableGroupJoin = keyMappingType.createTableGroupJoin(
fkNavigablePath,
tableGroup,
null,
null,
true,
LockMode.NONE,
creationState.getSqlAstCreationState()
);
return tableGroupJoin.getJoinedGroup();
}
);
return new EmbeddableForeignKeyResultImpl<>(
fkNavigablePath,
keyMappingType,
resultVariable,
creationState
);
}
@Override
public void breakDownJdbcValues(Object domainValue, JdbcValueConsumer valueConsumer, SharedSessionContractImplementor session) {
assert domainValue instanceof Object[];

View File

@ -331,6 +331,11 @@ public class EntityCollectionPart
return collectionDescriptor.getAttributeMapping().getKeyDescriptor();
}
@Override
public ForeignKeyDescriptor.Side getSide() {
return ForeignKeyDescriptor.Side.TARGET;
}
@Override
public FetchStyle getStyle() {
return FetchStyle.JOIN;

View File

@ -532,20 +532,11 @@ public class PluralAttributeMappingImpl
NavigablePath fetchablePath,
DomainResultCreationState creationState,
SqlAstCreationState sqlAstCreationState) {
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 );
}
final DomainResult<?> foreignKeyDomainResult = getKeyDescriptor().createTargetDomainResult(
fetchablePath,
sqlAstCreationState.getFromClauseAccess().getTableGroup( fetchParent.getNavigablePath() ),
creationState
);
return new DelayedCollectionFetch(
fetchablePath,
this,

View File

@ -8,7 +8,6 @@ package org.hibernate.metamodel.mapping.internal;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.function.Function;
import java.util.function.IntFunction;
@ -41,7 +40,6 @@ import org.hibernate.sql.ast.tree.from.TableReference;
import org.hibernate.sql.ast.tree.from.TableReferenceJoin;
import org.hibernate.sql.ast.tree.predicate.ComparisonPredicate;
import org.hibernate.sql.ast.tree.predicate.Predicate;
import org.hibernate.sql.results.DomainResultCreationException;
import org.hibernate.sql.results.graph.DomainResult;
import org.hibernate.sql.results.graph.DomainResultCreationState;
import org.hibernate.sql.results.graph.Fetch;
@ -121,13 +119,13 @@ public class SimpleForeignKeyDescriptor implements ForeignKeyDescriptor, BasicVa
@Override
public DomainResult<?> createKeyDomainResult(
NavigablePath collectionPath,
NavigablePath navigablePath,
TableGroup tableGroup,
DomainResultCreationState creationState) {
assert tableGroup.getTableReference( collectionPath, keySide.getContainingTableExpression() ) != null;
assert tableGroup.getTableReference( navigablePath, keySide.getContainingTableExpression() ) != null;
return createDomainResult(
collectionPath,
navigablePath,
tableGroup,
keySide,
creationState
@ -135,11 +133,11 @@ public class SimpleForeignKeyDescriptor implements ForeignKeyDescriptor, BasicVa
}
@Override
public DomainResult<?> createTargetDomainResult(NavigablePath collectionPath, TableGroup tableGroup, DomainResultCreationState creationState) {
assert tableGroup.getTableReference( collectionPath, targetSide.getContainingTableExpression() ) != null;
public DomainResult<?> createTargetDomainResult(NavigablePath navigablePath, TableGroup tableGroup, DomainResultCreationState creationState) {
assert tableGroup.getTableReference( navigablePath, targetSide.getContainingTableExpression() ) != null;
return createDomainResult(
collectionPath,
navigablePath,
tableGroup,
targetSide,
creationState
@ -158,36 +156,16 @@ public class SimpleForeignKeyDescriptor implements ForeignKeyDescriptor, BasicVa
public DomainResult<?> createDomainResult(
NavigablePath navigablePath,
TableGroup tableGroup,
Side side,
DomainResultCreationState creationState) {
try {
if ( side == Side.KEY ) {
return createDomainResult( navigablePath, tableGroup, keySide, creationState );
}
catch (Exception e) {
throw new DomainResultCreationException(
String.format(
Locale.ROOT,
"Unable to create fk key domain-result `%s.%s` relative to `%s`",
keySide.getContainingTableExpression(),
keySide.getSelectionExpression(),
tableGroup
),
e
);
else {
return createDomainResult( navigablePath, tableGroup, targetSide, creationState );
}
}
@Override
public DomainResult<?> createDomainResult(
NavigablePath navigablePath,
TableGroup tableGroup,
boolean isKeyReferringSide,
DomainResultCreationState creationState) {
if ( isKeyReferringSide ) {
return createDomainResult( navigablePath, tableGroup, keySide, creationState );
}
return createDomainResult( navigablePath, tableGroup, targetSide, creationState );
}
@Override
public <T> DomainResult<T> createDomainResult(
NavigablePath navigablePath,

View File

@ -100,8 +100,8 @@ public class ToOneAttributeMapping
private final TableGroupProducer declaringTableGroupProducer;
private ForeignKeyDescriptor foreignKeyDescriptor;
private ForeignKeyDescriptor.Side lhsSide;
private String identifyingColumnsTableExpression;
private boolean isKeyReferringSide;
public ToOneAttributeMapping(
String name,
@ -284,9 +284,11 @@ public class ToOneAttributeMapping
@Override
public void setForeignKeyDescriptor(ForeignKeyDescriptor foreignKeyDescriptor) {
isKeyReferringSide = foreignKeyDescriptor.getAssociationKey().getTable().equals( identifyingColumnsTableExpression );
assert identifyingColumnsTableExpression != null;
this.foreignKeyDescriptor = foreignKeyDescriptor;
this.lhsSide = foreignKeyDescriptor.getAssociationKey().getTable().equals( identifyingColumnsTableExpression )
? ForeignKeyDescriptor.Side.KEY
: ForeignKeyDescriptor.Side.TARGET;
}
public void setIdentifyingColumnsTableExpression(String tableExpression) {
@ -298,8 +300,13 @@ public class ToOneAttributeMapping
return this.foreignKeyDescriptor;
}
@Override
public ForeignKeyDescriptor.Side getSide() {
return lhsSide;
}
public boolean canJoinForeignKey(EntityIdentifierMapping identifierMapping) {
return isKeyReferringSide && identifierMapping == getForeignKeyDescriptor().getTargetPart() && !isNullable;
return lhsSide == ForeignKeyDescriptor.Side.KEY && identifierMapping == getForeignKeyDescriptor().getTargetPart() && !isNullable;
}
public String getReferencedPropertyName() {
@ -467,7 +474,7 @@ public class ToOneAttributeMapping
We have a cirularity but it is not bidirectional
*/
if ( isKeyReferringSide ) {
if ( lhsSide == ForeignKeyDescriptor.Side.KEY ) {
final TableGroup parentTableGroup = creationState
.getSqlAstCreationState()
.getFromClauseAccess()
@ -476,7 +483,7 @@ public class ToOneAttributeMapping
assert !creationState.isResolvingCircularFetch();
try {
creationState.setResolvingCircularFetch( true );
foreignKeyDomainResult = foreignKeyDescriptor.createDomainResult(
foreignKeyDomainResult = foreignKeyDescriptor.createKeyDomainResult(
fetchablePath,
parentTableGroup,
creationState
@ -634,16 +641,24 @@ public class ToOneAttributeMapping
*/
final boolean isKeyReferringSide;
if ( isFetchingForeignKey( fetchParent.getNavigablePath() ) ) {
isKeyReferringSide = !this.isKeyReferringSide;
final ForeignKeyDescriptor.Side resolvingKeySideOfForeignKey = creationState.getCurrentlyResolvingForeignKeyPart();
final ForeignKeyDescriptor.Side side;
if ( resolvingKeySideOfForeignKey == ForeignKeyDescriptor.Side.KEY && this.lhsSide == ForeignKeyDescriptor.Side.TARGET ) {
// If we are currently resolving the key part of a foreign key we do not want to add joins.
// So if the lhs of this association is the target of the FK, we have to use the KEY part to avoid a join
side = ForeignKeyDescriptor.Side.KEY;
}
else{
isKeyReferringSide = this.isKeyReferringSide;
else {
side = this.lhsSide;
}
final DomainResult<?> keyResult = foreignKeyDescriptor.createDomainResult( fetchablePath, parentTableGroup, isKeyReferringSide, creationState );
final DomainResult<?> keyResult = foreignKeyDescriptor.createDomainResult(
fetchablePath,
parentTableGroup,
side,
creationState
);
boolean selectByUniqueKey;
if ( isKeyReferringSide ) {
if ( side == ForeignKeyDescriptor.Side.KEY ) {
// case 1.2
selectByUniqueKey = false;
}
@ -672,16 +687,6 @@ public class ToOneAttributeMapping
);
}
private boolean isFetchingForeignKey(NavigablePath p) {
while ( p != null ) {
if ( ForeignKeyDescriptor.PART_NAME.equals( p.getLocalName() ) ) {
return true;
}
p = p.getParent();
}
return false;
}
@Override
public <T> DomainResult<T> createDelayedDomainResult(
NavigablePath navigablePath,
@ -690,7 +695,7 @@ public class ToOneAttributeMapping
DomainResultCreationState creationState) {
// We only need a join if the key is on the referring side i.e. this is an inverse to-one
// and if the FK refers to a non-PK, in which case we must load the whole entity
if ( !isKeyReferringSide || referencedPropertyName != null ) {
if ( lhsSide == ForeignKeyDescriptor.Side.TARGET || referencedPropertyName != null ) {
final TableGroupJoin tableGroupJoin = createTableGroupJoin(
navigablePath,
tableGroup,
@ -776,8 +781,8 @@ public class ToOneAttributeMapping
final SqlAliasBase sqlAliasBase = aliasBaseGenerator.createSqlAliasBase( aliasRoot );
// We can only use the parent table group if the FK is located there
// If this is false, the FK is on a join table
final boolean canUseParentTableGroup = isKeyReferringSide && declaringTableGroupProducer.containsTableReference(
identifyingColumnsTableExpression );
final boolean canUseParentTableGroup = lhsSide == ForeignKeyDescriptor.Side.KEY
&& declaringTableGroupProducer.containsTableReference( identifyingColumnsTableExpression );
final LazyTableGroup lazyTableGroup = new LazyTableGroup(
navigablePath,
() -> createTableGroupJoinInternal(
@ -916,7 +921,7 @@ public class ToOneAttributeMapping
@Override
public int forEachSelectable(int offset, SelectableConsumer consumer) {
if ( isKeyReferringSide ) {
if ( lhsSide == ForeignKeyDescriptor.Side.KEY ) {
return foreignKeyDescriptor.visitKeySelectables( offset, consumer );
}
else {

View File

@ -77,6 +77,7 @@ public class DomainResultCreationStateImpl
private final Stack<NavigablePath> relativePathStack = new StandardStack<>();
private boolean processingKeyFetches = false;
private boolean resolvingCircularFetch;
private ForeignKeyDescriptor.Side currentlyResolvingForeignKeySide;
public DomainResultCreationStateImpl(
String stateIdentifier,
@ -420,4 +421,14 @@ public class DomainResultCreationStateImpl
this.resolvingCircularFetch = resolvingCircularFetch;
}
@Override
public ForeignKeyDescriptor.Side getCurrentlyResolvingForeignKeyPart() {
return currentlyResolvingForeignKeySide;
}
@Override
public void setCurrentlyResolvingForeignKeyPart(ForeignKeyDescriptor.Side currentlyResolvingForeignKeySide) {
this.currentlyResolvingForeignKeySide = currentlyResolvingForeignKeySide;
}
}

View File

@ -339,6 +339,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
private int fetchDepth;
private boolean resolvingCircularFetch;
private ForeignKeyDescriptor.Side currentlyResolvingForeignKeySide;
private Map<String, FilterPredicate> collectionFilterPredicates;
private OrderByFragmentConsumer orderByFragmentConsumer;
@ -2718,7 +2719,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
final ForeignKeyDescriptor keyDescriptor = mapDescriptor.getKeyDescriptor();
final NavigablePath keyNavigablePath = mapNavigablePath.append( keyDescriptor.getPartName() );
final DomainResult keyResult = keyDescriptor.createDomainResult(
final DomainResult keyResult = keyDescriptor.createKeyDomainResult(
keyNavigablePath,
tableGroup,
this
@ -4699,6 +4700,16 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
this.resolvingCircularFetch = resolvingCircularFetch;
}
@Override
public ForeignKeyDescriptor.Side getCurrentlyResolvingForeignKeyPart() {
return currentlyResolvingForeignKeySide;
}
@Override
public void setCurrentlyResolvingForeignKeyPart(ForeignKeyDescriptor.Side currentlyResolvingForeignKeySide) {
this.currentlyResolvingForeignKeySide = currentlyResolvingForeignKeySide;
}
@Internal
public interface SqmAliasedNodeCollector {
void next();

View File

@ -12,12 +12,14 @@ import java.util.List;
import org.hibernate.LockMode;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.metamodel.mapping.BasicEntityIdentifierMapping;
import org.hibernate.metamodel.mapping.BasicValuedModelPart;
import org.hibernate.metamodel.mapping.CollectionPart;
import org.hibernate.metamodel.mapping.EntityAssociationMapping;
import org.hibernate.metamodel.mapping.EntityIdentifierMapping;
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.mapping.EntityValuedModelPart;
import org.hibernate.metamodel.mapping.ForeignKeyDescriptor;
import org.hibernate.metamodel.mapping.ModelPart;
import org.hibernate.metamodel.mapping.internal.SimpleForeignKeyDescriptor;
import org.hibernate.query.NavigablePath;
import org.hibernate.query.sqm.sql.SqmToSqlAstConverter;
@ -61,37 +63,52 @@ public class EntityValuedPathInterpretation<T> extends AbstractSqmPathInterpreta
if ( mapping instanceof EntityAssociationMapping ) {
final EntityAssociationMapping associationMapping = (EntityAssociationMapping) mapping;
final ForeignKeyDescriptor keyDescriptor = associationMapping.getForeignKeyDescriptor();
final ForeignKeyDescriptor fkDescriptor = associationMapping.getForeignKeyDescriptor();
final String lhsTable;
final ModelPart lhsPart;
if ( associationMapping.getSide() == ForeignKeyDescriptor.Side.KEY ) {
lhsTable = fkDescriptor.getKeyTable();
lhsPart = fkDescriptor.getKeyPart();
}
else {
lhsTable = fkDescriptor.getTargetTable();
lhsPart = fkDescriptor.getTargetPart();
}
final TableReference tableReference = tableGroup.resolveTableReference(
sqmPath.getNavigablePath(),
keyDescriptor.getKeyTable()
lhsTable
);
if ( keyDescriptor instanceof SimpleForeignKeyDescriptor ) {
final SimpleForeignKeyDescriptor simpleKeyDescriptor = (SimpleForeignKeyDescriptor) keyDescriptor;
if ( fkDescriptor instanceof SimpleForeignKeyDescriptor ) {
final BasicValuedModelPart basicValuedModelPart = (BasicValuedModelPart) lhsPart;
sqlExpression = sqlExprResolver.resolveSqlExpression(
createColumnReferenceKey( tableReference, simpleKeyDescriptor.getSelectionExpression() ),
createColumnReferenceKey( tableReference, basicValuedModelPart.getSelectionExpression() ),
processingState -> new ColumnReference(
tableReference,
simpleKeyDescriptor,
basicValuedModelPart,
sessionFactory
)
);
}
else {
final List<Expression> expressions = new ArrayList<>();
keyDescriptor.forEachSelectable(
(selectionIndex, selectableMapping) -> sqlExprResolver.resolveSqlExpression(
createColumnReferenceKey( tableReference, selectableMapping.getSelectionExpression() ),
processingState -> new ColumnReference(
tableReference,
selectableMapping,
sessionFactory
final List<Expression> expressions = new ArrayList<>( fkDescriptor.getJdbcTypeCount() );
lhsPart.forEachSelectable(
(selectionIndex, selectableMapping) -> expressions.add(
sqlExprResolver.resolveSqlExpression(
createColumnReferenceKey(
tableReference,
selectableMapping.getSelectionExpression()
),
processingState -> new ColumnReference(
tableReference,
selectableMapping,
sessionFactory
)
)
)
);
sqlExpression = new SqlTuple( expressions, keyDescriptor );
sqlExpression = new SqlTuple( expressions, lhsPart );
}
}
else {

View File

@ -10,6 +10,7 @@ import java.util.List;
import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.metamodel.mapping.AssociationKey;
import org.hibernate.metamodel.mapping.ForeignKeyDescriptor;
import org.hibernate.metamodel.mapping.ModelPart;
import org.hibernate.query.NavigablePath;
import org.hibernate.sql.ast.spi.SqlAliasBaseManager;
@ -81,4 +82,12 @@ public interface DomainResultCreationState {
boolean isResolvingCircularFetch();
void setResolvingCircularFetch(boolean resolvingCircularFetch);
/**
* Returns the part of the foreign key that is currently being resolved,
* or <code>null</code> if no foreign key is currently being resolved.
*/
ForeignKeyDescriptor.Side getCurrentlyResolvingForeignKeyPart();
void setCurrentlyResolvingForeignKeyPart(ForeignKeyDescriptor.Side currentlyResolvingForeignKeySide);
}

View File

@ -50,7 +50,7 @@ public class CollectionDomainResult implements DomainResult, CollectionResultGra
this.loadingAttribute = loadingAttribute;
this.resultVariable = resultVariable;
fkResult = loadingAttribute.getKeyDescriptor().createDomainResult(
fkResult = loadingAttribute.getKeyDescriptor().createKeyDomainResult(
loadingPath,
tableGroup,
creationState

View File

@ -78,7 +78,7 @@ public abstract class AbstractEntityResultGraphNode extends AbstractFetchParent
// If we don't do this here, LazyTableGroup#getTableReferenceInternal would have to use the target table in case {id} is encountered
if ( ( (ToOneAttributeMapping) referencedModelPart ).canJoinForeignKey( identifierMapping ) ) {
identifierResult = ( (ToOneAttributeMapping) referencedModelPart ).getForeignKeyDescriptor()
.createDomainResult(
.createKeyDomainResult(
navigablePath,
creationState.getSqlAstCreationState()
.getFromClauseAccess()
@ -156,12 +156,12 @@ public abstract class AbstractEntityResultGraphNode extends AbstractFetchParent
( (ManagedMappingType) mappingType ).visitAttributeMappings(
attributeMapping -> {
if ( attributeMapping instanceof ToOneAttributeMapping ) {
( (ToOneAttributeMapping) attributeMapping ).getForeignKeyDescriptor().createDomainResult(
navigablePath.getParent(),
entityTableGroup,
null,
creationState
);
( (ToOneAttributeMapping) attributeMapping ).getForeignKeyDescriptor()
.createKeyDomainResult(
navigablePath.getParent(),
entityTableGroup,
creationState
);
}
else {
attributeMapping.createDomainResult(

View File

@ -43,13 +43,11 @@ public class EntityDelayedResultImpl implements DomainResult {
DomainResultCreationState creationState) {
this.navigablePath = navigablePath;
this.entityValuedModelPart = entityValuedModelPart;
this.identifierResult = entityValuedModelPart.getForeignKeyDescriptor()
.createDomainResult(
navigablePath.append( EntityIdentifierMapping.ROLE_LOCAL_NAME ),
rootTableGroup,
null,
creationState
);
this.identifierResult = entityValuedModelPart.getForeignKeyDescriptor().createKeyDomainResult(
navigablePath.append( EntityIdentifierMapping.ROLE_LOCAL_NAME ),
rootTableGroup,
creationState
);
}
@Override

View File

@ -150,6 +150,11 @@ public class CircularBiDirectionalFetchImpl implements BiDirectionalFetch, Assoc
return ( (Association) fetchParent ).getForeignKeyDescriptor();
}
@Override
public ForeignKeyDescriptor.Side getSide() {
return ( (Association) fetchParent ).getSide();
}
@Override
public void breakDownJdbcValues(Object domainValue, JdbcValueConsumer valueConsumer, SharedSessionContractImplementor session) {
fetchable.breakDownJdbcValues( domainValue, valueConsumer, session );

View File

@ -10,14 +10,12 @@ import org.hibernate.LockMode;
import org.hibernate.engine.FetchTiming;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
import org.hibernate.metamodel.mapping.Association;
import org.hibernate.metamodel.mapping.AttributeMapping;
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.mapping.EntityValuedModelPart;
import org.hibernate.metamodel.mapping.ForeignKeyDescriptor;
import org.hibernate.metamodel.mapping.MappingType;
import org.hibernate.metamodel.mapping.internal.ToOneAttributeMapping;
import org.hibernate.metamodel.model.domain.NavigableRole;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.query.NavigablePath;
import org.hibernate.sql.results.graph.AssemblerCreationState;
import org.hibernate.sql.results.graph.BiDirectionalFetch;
@ -181,6 +179,11 @@ public class CircularFetchImpl implements BiDirectionalFetch, Association {
return ( (Association) fetchParent ).getForeignKeyDescriptor();
}
@Override
public ForeignKeyDescriptor.Side getSide() {
return ( (Association) fetchParent ).getSide();
}
@Override
public void breakDownJdbcValues(Object domainValue, JdbcValueConsumer valueConsumer, SharedSessionContractImplementor session) {
fetchable.breakDownJdbcValues( domainValue, valueConsumer, session );