Capture whether a foreign key is constrained and allow skipping the foreign key access optimization explicitly
This commit is contained in:
parent
f23ecfc58e
commit
86000e9f22
|
@ -469,6 +469,10 @@ public abstract class SimpleValue implements KeyValue {
|
|||
public void setForeignKeyName(String foreignKeyName) {
|
||||
this.foreignKeyName = foreignKeyName;
|
||||
}
|
||||
|
||||
public boolean isConstrained() {
|
||||
return !"none".equals( foreignKeyName ) && !hasFormula();
|
||||
}
|
||||
|
||||
public String getForeignKeyDefinition() {
|
||||
return foreignKeyDefinition;
|
||||
|
|
|
@ -135,4 +135,6 @@ public interface ForeignKeyDescriptor extends VirtualModelPart {
|
|||
MappingModelCreationProcess creationProcess);
|
||||
|
||||
AssociationKey getAssociationKey();
|
||||
|
||||
boolean hasConstraint();
|
||||
}
|
||||
|
|
|
@ -212,7 +212,7 @@ public class BasicAttributeMapping
|
|||
TableGroup tableGroup,
|
||||
String resultVariable,
|
||||
DomainResultCreationState creationState) {
|
||||
final SqlSelection sqlSelection = resolveSqlSelection( tableGroup, creationState );
|
||||
final SqlSelection sqlSelection = resolveSqlSelection( tableGroup, true, creationState );
|
||||
|
||||
//noinspection unchecked
|
||||
return new BasicResult(
|
||||
|
@ -224,12 +224,15 @@ public class BasicAttributeMapping
|
|||
);
|
||||
}
|
||||
|
||||
private SqlSelection resolveSqlSelection(TableGroup tableGroup, DomainResultCreationState creationState) {
|
||||
private SqlSelection resolveSqlSelection(
|
||||
TableGroup tableGroup,
|
||||
boolean allowFkOptimization,
|
||||
DomainResultCreationState creationState) {
|
||||
final SqlExpressionResolver expressionResolver = creationState.getSqlAstCreationState().getSqlExpressionResolver();
|
||||
final TableReference tableReference = tableGroup.resolveTableReference(
|
||||
tableGroup.getNavigablePath()
|
||||
.append( getNavigableRole().getNavigableName() ),
|
||||
getContainingTableExpression()
|
||||
tableGroup.getNavigablePath().append( getNavigableRole().getNavigableName() ),
|
||||
getContainingTableExpression(),
|
||||
allowFkOptimization
|
||||
);
|
||||
final String tableAlias = tableReference.getIdentificationVariable();
|
||||
return expressionResolver.resolveSqlSelection(
|
||||
|
@ -254,7 +257,7 @@ public class BasicAttributeMapping
|
|||
NavigablePath navigablePath,
|
||||
TableGroup tableGroup,
|
||||
DomainResultCreationState creationState) {
|
||||
resolveSqlSelection( tableGroup, creationState );
|
||||
resolveSqlSelection( tableGroup, true, creationState );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -263,7 +266,7 @@ public class BasicAttributeMapping
|
|||
TableGroup tableGroup,
|
||||
DomainResultCreationState creationState,
|
||||
BiConsumer<SqlSelection, JdbcMapping> selectionConsumer) {
|
||||
selectionConsumer.accept( resolveSqlSelection( tableGroup, creationState ), getJdbcMapping() );
|
||||
selectionConsumer.accept( resolveSqlSelection( tableGroup, true, creationState ), getJdbcMapping() );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -291,7 +294,7 @@ public class BasicAttributeMapping
|
|||
|
||||
assert tableGroup != null;
|
||||
|
||||
final SqlSelection sqlSelection = resolveSqlSelection( tableGroup, creationState );
|
||||
final SqlSelection sqlSelection = resolveSqlSelection( tableGroup, false, creationState );
|
||||
valuesArrayPosition = sqlSelection.getValuesArrayPosition();
|
||||
}
|
||||
|
||||
|
|
|
@ -175,7 +175,7 @@ public class BasicEntityIdentifierMappingImpl implements BasicEntityIdentifierMa
|
|||
TableGroup tableGroup,
|
||||
String resultVariable,
|
||||
DomainResultCreationState creationState) {
|
||||
final SqlSelection sqlSelection = resolveSqlSelection( navigablePath, tableGroup, creationState );
|
||||
final SqlSelection sqlSelection = resolveSqlSelection( navigablePath, tableGroup, true, creationState );
|
||||
|
||||
return new BasicResult(
|
||||
sqlSelection.getValuesArrayPosition(),
|
||||
|
@ -190,18 +190,19 @@ public class BasicEntityIdentifierMappingImpl implements BasicEntityIdentifierMa
|
|||
NavigablePath navigablePath,
|
||||
TableGroup tableGroup,
|
||||
DomainResultCreationState creationState) {
|
||||
resolveSqlSelection( navigablePath, tableGroup, creationState );
|
||||
resolveSqlSelection( navigablePath, tableGroup, true, creationState );
|
||||
}
|
||||
|
||||
private SqlSelection resolveSqlSelection(
|
||||
NavigablePath navigablePath,
|
||||
TableGroup tableGroup,
|
||||
boolean allowFkOptimization,
|
||||
DomainResultCreationState creationState) {
|
||||
final SqlExpressionResolver expressionResolver = creationState.getSqlAstCreationState()
|
||||
.getSqlExpressionResolver();
|
||||
final TableReference rootTableReference;
|
||||
try {
|
||||
rootTableReference = tableGroup.resolveTableReference( navigablePath, rootTable );
|
||||
rootTableReference = tableGroup.resolveTableReference( navigablePath, rootTable, allowFkOptimization );
|
||||
}
|
||||
catch (Exception e) {
|
||||
throw new IllegalStateException(
|
||||
|
|
|
@ -58,6 +58,7 @@ public class EmbeddedForeignKeyDescriptor implements ForeignKeyDescriptor {
|
|||
private final String targetTable;
|
||||
private final SelectableMappings targetSelectableMappings;
|
||||
private final AssociationKey associationKey;
|
||||
private final boolean hasConstraint;
|
||||
|
||||
public EmbeddedForeignKeyDescriptor(
|
||||
EmbeddableValuedModelPart keyMappingType,
|
||||
|
@ -66,6 +67,7 @@ public class EmbeddedForeignKeyDescriptor implements ForeignKeyDescriptor {
|
|||
SelectableMappings keySelectableMappings,
|
||||
String targetTable,
|
||||
SelectableMappings targetSelectableMappings,
|
||||
boolean hasConstraint,
|
||||
MappingModelCreationProcess creationProcess) {
|
||||
this.keyTable = keyTable;
|
||||
this.keySelectableMappings = keySelectableMappings;
|
||||
|
@ -80,6 +82,7 @@ public class EmbeddedForeignKeyDescriptor implements ForeignKeyDescriptor {
|
|||
}
|
||||
);
|
||||
this.associationKey = new AssociationKey( keyTable, columns );
|
||||
this.hasConstraint = hasConstraint;
|
||||
|
||||
creationProcess.registerInitializationCallback(
|
||||
"Embedded (composite) FK descriptor " + targetMappingType.getNavigableRole(),
|
||||
|
@ -121,6 +124,7 @@ public class EmbeddedForeignKeyDescriptor implements ForeignKeyDescriptor {
|
|||
}
|
||||
);
|
||||
this.associationKey = new AssociationKey( keyTable, columns );
|
||||
this.hasConstraint = original.hasConstraint;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -439,8 +443,7 @@ public class EmbeddedForeignKeyDescriptor implements ForeignKeyDescriptor {
|
|||
}
|
||||
|
||||
final TableReference tableReference = lhs.resolveTableReference(
|
||||
lhs.getNavigablePath()
|
||||
.append( getNavigableRole().getNavigableName() ),
|
||||
lhs.getNavigablePath().append( getNavigableRole().getNavigableName() ),
|
||||
table
|
||||
);
|
||||
if ( tableReference != null ) {
|
||||
|
@ -460,6 +463,11 @@ public class EmbeddedForeignKeyDescriptor implements ForeignKeyDescriptor {
|
|||
return targetSelectableMappings.forEachSelectable( offset, consumer );
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasConstraint() {
|
||||
return hasConstraint;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AssociationKey getAssociationKey() {
|
||||
return associationKey;
|
||||
|
|
|
@ -45,6 +45,7 @@ import org.hibernate.mapping.PersistentClass;
|
|||
import org.hibernate.mapping.Property;
|
||||
import org.hibernate.mapping.Resolvable;
|
||||
import org.hibernate.mapping.Selectable;
|
||||
import org.hibernate.mapping.SimpleValue;
|
||||
import org.hibernate.mapping.Table;
|
||||
import org.hibernate.mapping.ToOne;
|
||||
import org.hibernate.mapping.Value;
|
||||
|
@ -932,7 +933,8 @@ public class MappingModelCreationHelper {
|
|||
null,
|
||||
keySelectableMapping,
|
||||
simpleFkTarget,
|
||||
isReferenceToPrimaryKey
|
||||
isReferenceToPrimaryKey,
|
||||
( (SimpleValue) bootValueMappingKey ).isConstrained()
|
||||
)
|
||||
);
|
||||
}
|
||||
|
@ -1077,6 +1079,7 @@ public class MappingModelCreationHelper {
|
|||
keySelectableMapping,
|
||||
simpleFkTarget,
|
||||
bootValueMapping.isReferenceToPrimaryKey(),
|
||||
bootValueMapping.isConstrained(),
|
||||
swapDirection
|
||||
);
|
||||
attributeMapping.setForeignKeyDescriptor( foreignKeyDescriptor );
|
||||
|
@ -1119,10 +1122,12 @@ public class MappingModelCreationHelper {
|
|||
boolean inverse,
|
||||
Dialect dialect,
|
||||
MappingModelCreationProcess creationProcess) {
|
||||
final boolean hasConstraint;
|
||||
final SelectableMappings keySelectableMappings;
|
||||
final String keyTableExpression;
|
||||
if ( bootValueMapping instanceof Collection ) {
|
||||
final Collection collectionBootValueMapping = (Collection) bootValueMapping;
|
||||
hasConstraint = ( (SimpleValue) collectionBootValueMapping.getKey() ).isConstrained();
|
||||
keyTableExpression = getTableIdentifierExpression(
|
||||
collectionBootValueMapping.getCollectionTable(),
|
||||
creationProcess
|
||||
|
@ -1137,6 +1142,13 @@ public class MappingModelCreationHelper {
|
|||
);
|
||||
}
|
||||
else {
|
||||
if ( bootValueMapping instanceof OneToMany ) {
|
||||
// We assume there is a constraint if the mapping is not nullable
|
||||
hasConstraint = !bootValueMapping.isNullable();
|
||||
}
|
||||
else {
|
||||
hasConstraint = ( (SimpleValue) bootValueMapping ).isConstrained();
|
||||
}
|
||||
keyTableExpression = getTableIdentifierExpression(
|
||||
bootValueMapping.getTable(),
|
||||
creationProcess
|
||||
|
@ -1162,6 +1174,7 @@ public class MappingModelCreationHelper {
|
|||
embeddableValuedModelPart.getEmbeddableTypeDescriptor(),
|
||||
keyTableExpression,
|
||||
keySelectableMappings,
|
||||
hasConstraint,
|
||||
creationProcess
|
||||
);
|
||||
}
|
||||
|
@ -1177,6 +1190,7 @@ public class MappingModelCreationHelper {
|
|||
keySelectableMappings,
|
||||
embeddableValuedModelPart.getContainingTableExpression(),
|
||||
embeddableValuedModelPart.getEmbeddableTypeDescriptor(),
|
||||
hasConstraint,
|
||||
creationProcess
|
||||
);
|
||||
}
|
||||
|
|
|
@ -25,6 +25,7 @@ import org.hibernate.mapping.IndexedCollection;
|
|||
import org.hibernate.mapping.IndexedConsumer;
|
||||
import org.hibernate.mapping.List;
|
||||
import org.hibernate.mapping.Property;
|
||||
import org.hibernate.mapping.SimpleValue;
|
||||
import org.hibernate.mapping.Value;
|
||||
import org.hibernate.metamodel.mapping.BasicValuedModelPart;
|
||||
import org.hibernate.metamodel.mapping.CollectionIdentifierDescriptor;
|
||||
|
@ -338,12 +339,21 @@ public class PluralAttributeMappingImpl
|
|||
dialect,
|
||||
creationProcess.getSqmFunctionRegistry()
|
||||
);
|
||||
final boolean hasConstraint;
|
||||
if ( fkBootDescriptorSource instanceof SimpleValue ) {
|
||||
hasConstraint = ( (SimpleValue) fkBootDescriptorSource ).isConstrained();
|
||||
}
|
||||
else {
|
||||
// We assume there is a constraint if the key is not nullable
|
||||
hasConstraint = !fkBootDescriptorSource.isNullable();
|
||||
}
|
||||
return new SimpleForeignKeyDescriptor(
|
||||
basicFkTargetPart,
|
||||
null,
|
||||
keySelectableMapping,
|
||||
basicFkTargetPart,
|
||||
entityType.isReferenceToPrimaryKey()
|
||||
entityType.isReferenceToPrimaryKey(),
|
||||
hasConstraint
|
||||
);
|
||||
}
|
||||
else if ( fkTargetPart instanceof EmbeddableValuedModelPart ) {
|
||||
|
|
|
@ -57,7 +57,7 @@ public class SimpleForeignKeyDescriptor implements ForeignKeyDescriptor, BasicVa
|
|||
private final SimpleForeignKeyDescriptorSide targetSide;
|
||||
|
||||
private final boolean refersToPrimaryKey;
|
||||
|
||||
private final boolean hasConstraint;
|
||||
private AssociationKey associationKey;
|
||||
|
||||
public SimpleForeignKeyDescriptor(
|
||||
|
@ -65,8 +65,9 @@ public class SimpleForeignKeyDescriptor implements ForeignKeyDescriptor, BasicVa
|
|||
PropertyAccess keyPropertyAccess,
|
||||
SelectableMapping keySelectableMapping,
|
||||
BasicValuedModelPart targetModelPart,
|
||||
boolean refersToPrimaryKey) {
|
||||
this( keyModelPart, keyPropertyAccess, keySelectableMapping, targetModelPart, refersToPrimaryKey, false );
|
||||
boolean refersToPrimaryKey,
|
||||
boolean hasConstraint) {
|
||||
this( keyModelPart, keyPropertyAccess, keySelectableMapping, targetModelPart, refersToPrimaryKey, hasConstraint, false );
|
||||
}
|
||||
|
||||
public SimpleForeignKeyDescriptor(
|
||||
|
@ -75,6 +76,7 @@ public class SimpleForeignKeyDescriptor implements ForeignKeyDescriptor, BasicVa
|
|||
SelectableMapping keySelectableMapping,
|
||||
BasicValuedModelPart targetModelPart,
|
||||
boolean refersToPrimaryKey,
|
||||
boolean hasConstraint,
|
||||
boolean swapDirection) {
|
||||
assert keySelectableMapping != null;
|
||||
assert targetModelPart != null;
|
||||
|
@ -94,6 +96,7 @@ public class SimpleForeignKeyDescriptor implements ForeignKeyDescriptor, BasicVa
|
|||
this.targetSide = new SimpleForeignKeyDescriptorSide( Nature.TARGET, targetModelPart );
|
||||
}
|
||||
this.refersToPrimaryKey = refersToPrimaryKey;
|
||||
this.hasConstraint = hasConstraint;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -135,7 +138,8 @@ public class SimpleForeignKeyDescriptor implements ForeignKeyDescriptor, BasicVa
|
|||
( (PropertyBasedMapping) keySide.getModelPart() ).getPropertyAccess(),
|
||||
selectableMappingAccess.apply( 0 ),
|
||||
targetSide.getModelPart(),
|
||||
refersToPrimaryKey
|
||||
refersToPrimaryKey,
|
||||
hasConstraint
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -426,6 +430,11 @@ public class SimpleForeignKeyDescriptor implements ForeignKeyDescriptor, BasicVa
|
|||
return getJdbcTypeCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasConstraint() {
|
||||
return hasConstraint;
|
||||
}
|
||||
|
||||
@Override
|
||||
public AssociationKey getAssociationKey() {
|
||||
if ( associationKey == null ) {
|
||||
|
|
|
@ -345,28 +345,9 @@ public class ToOneAttributeMapping
|
|||
? ForeignKeyDescriptor.Nature.KEY
|
||||
: ForeignKeyDescriptor.Nature.TARGET;
|
||||
|
||||
// Determine if the FK maps the id of the owner entity
|
||||
final boolean[] mapsId = new boolean[1];
|
||||
final EntityMappingType containingEntityMapping = findContainingEntityMapping();
|
||||
foreignKeyDescriptor.getKeyPart().forEachSelectable(
|
||||
(fkIndex, fkMapping) -> {
|
||||
if ( !mapsId[0] ) {
|
||||
containingEntityMapping.getEntityPersister().getIdentifierMapping().forEachSelectable(
|
||||
(idIndex, idMapping) -> {
|
||||
if ( fkMapping.getContainingTableExpression()
|
||||
.equals( idMapping.getContainingTableExpression() )
|
||||
&& fkMapping.getSelectionExpression()
|
||||
.equals( idMapping.getSelectionExpression() ) ) {
|
||||
mapsId[0] = true;
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
);
|
||||
// We can only use the parent table group if the FK is located there
|
||||
// If this is not the case, the FK is on a join/secondary table, so we need a join
|
||||
this.canUseParentTableGroup = !mapsId[0] && sideNature == ForeignKeyDescriptor.Nature.KEY
|
||||
// We can only use the parent table group if the FK is located there and ignoreNotFound is false
|
||||
// If this is not the case, the FK is not constrained or on a join/secondary table, so we need a join
|
||||
this.canUseParentTableGroup = !isIgnoreNotFound && sideNature == ForeignKeyDescriptor.Nature.KEY
|
||||
&& declaringTableGroupProducer.containsTableReference( identifyingColumnsTableExpression );
|
||||
}
|
||||
|
||||
|
@ -881,7 +862,7 @@ public class ToOneAttributeMapping
|
|||
SqlExpressionResolver sqlExpressionResolver,
|
||||
SqlAstCreationContext creationContext) {
|
||||
final SqlAliasBase sqlAliasBase = aliasBaseGenerator.createSqlAliasBase( sqlAliasStem );
|
||||
boolean canUseInnerJoin = sqlAstJoinType == SqlAstJoinType.INNER || lhs.canUseInnerJoins() && !isNullable;
|
||||
final boolean canUseInnerJoin = sqlAstJoinType == SqlAstJoinType.INNER || lhs.canUseInnerJoins() && !isNullable;
|
||||
final LazyTableGroup lazyTableGroup = new LazyTableGroup(
|
||||
canUseInnerJoin,
|
||||
navigablePath,
|
||||
|
|
|
@ -119,8 +119,11 @@ public class TableGroupImpl implements TableGroup {
|
|||
}
|
||||
|
||||
@Override
|
||||
public TableReference resolveTableReference(NavigablePath navigablePath, String tableExpression) {
|
||||
final TableReference tableReference = getTableReference( navigablePath, tableExpression );
|
||||
public TableReference resolveTableReference(
|
||||
NavigablePath navigablePath,
|
||||
String tableExpression,
|
||||
boolean allowFkOptimization) {
|
||||
final TableReference tableReference = getTableReference( navigablePath, tableExpression, allowFkOptimization );
|
||||
if ( tableReference == null ) {
|
||||
throw new IllegalStateException( "Could not resolve binding for table `" + tableExpression + "`" );
|
||||
}
|
||||
|
@ -129,14 +132,17 @@ public class TableGroupImpl implements TableGroup {
|
|||
}
|
||||
|
||||
@Override
|
||||
public TableReference getTableReference(NavigablePath navigablePath, String tableExpression) {
|
||||
if ( primaryTableReference.getTableReference( navigablePath , tableExpression ) != null ) {
|
||||
public TableReference getTableReference(
|
||||
NavigablePath navigablePath,
|
||||
String tableExpression,
|
||||
boolean allowFkOptimization) {
|
||||
if ( primaryTableReference.getTableReference( navigablePath , tableExpression, allowFkOptimization ) != null ) {
|
||||
return primaryTableReference;
|
||||
}
|
||||
|
||||
for ( TableGroupJoin tableGroupJoin : getTableGroupJoins() ) {
|
||||
final TableReference primaryTableReference = tableGroupJoin.getJoinedGroup().getPrimaryTableReference();
|
||||
if ( primaryTableReference.getTableReference( navigablePath, tableExpression ) != null ) {
|
||||
if ( primaryTableReference.getTableReference( navigablePath, tableExpression, allowFkOptimization ) != null ) {
|
||||
return primaryTableReference;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -65,7 +65,10 @@ public class CteTableGroup implements TableGroup {
|
|||
}
|
||||
|
||||
@Override
|
||||
public TableReference getTableReference(NavigablePath navigablePath, String tableExpression) {
|
||||
public TableReference getTableReference(
|
||||
NavigablePath navigablePath,
|
||||
String tableExpression,
|
||||
boolean allowFkOptimization) {
|
||||
if ( cteTableReference.getTableExpression().equals( tableExpression ) ) {
|
||||
return cteTableReference;
|
||||
}
|
||||
|
@ -73,7 +76,10 @@ public class CteTableGroup implements TableGroup {
|
|||
}
|
||||
|
||||
@Override
|
||||
public TableReference resolveTableReference(NavigablePath navigablePath, String tableExpression) {
|
||||
public TableReference resolveTableReference(
|
||||
NavigablePath navigablePath,
|
||||
String tableExpression,
|
||||
boolean allowFkOptimization) {
|
||||
return cteTableReference;
|
||||
}
|
||||
|
||||
|
|
|
@ -25,10 +25,17 @@ public abstract class AbstractColumnReferenceQualifier implements ColumnReferenc
|
|||
// TableReference handling
|
||||
|
||||
@Override
|
||||
public TableReference resolveTableReference(NavigablePath navigablePath, String tableExpression) {
|
||||
public TableReference resolveTableReference(
|
||||
NavigablePath navigablePath,
|
||||
String tableExpression,
|
||||
boolean allowFkOptimization) {
|
||||
assert tableExpression != null;
|
||||
|
||||
final TableReference tableReference = getTableReferenceInternal( navigablePath, tableExpression );
|
||||
final TableReference tableReference = getTableReferenceInternal(
|
||||
navigablePath,
|
||||
tableExpression,
|
||||
allowFkOptimization
|
||||
);
|
||||
if ( tableReference == null ) {
|
||||
throw new IllegalStateException( "Could not resolve binding for table `" + tableExpression + "`" );
|
||||
}
|
||||
|
@ -37,14 +44,22 @@ public abstract class AbstractColumnReferenceQualifier implements ColumnReferenc
|
|||
}
|
||||
|
||||
@Override
|
||||
public TableReference getTableReference(NavigablePath navigablePath, String tableExpression) {
|
||||
return getTableReferenceInternal( navigablePath, tableExpression );
|
||||
public TableReference getTableReference(
|
||||
NavigablePath navigablePath,
|
||||
String tableExpression,
|
||||
boolean allowFkOptimization) {
|
||||
return getTableReferenceInternal( navigablePath, tableExpression, allowFkOptimization );
|
||||
}
|
||||
|
||||
protected TableReference getTableReferenceInternal(
|
||||
NavigablePath navigablePath,
|
||||
String tableExpression) {
|
||||
final TableReference primaryTableReference = getPrimaryTableReference().getTableReference( navigablePath , tableExpression );
|
||||
String tableExpression,
|
||||
boolean allowFkOptimization) {
|
||||
final TableReference primaryTableReference = getPrimaryTableReference().getTableReference(
|
||||
navigablePath,
|
||||
tableExpression,
|
||||
allowFkOptimization
|
||||
);
|
||||
if ( primaryTableReference != null) {
|
||||
return primaryTableReference;
|
||||
}
|
||||
|
@ -52,7 +67,9 @@ public abstract class AbstractColumnReferenceQualifier implements ColumnReferenc
|
|||
for ( TableReferenceJoin tableJoin : getTableReferenceJoins() ) {
|
||||
final TableReference tableReference = tableJoin.getJoinedTableReference().getTableReference(
|
||||
navigablePath,
|
||||
tableExpression );
|
||||
tableExpression,
|
||||
allowFkOptimization
|
||||
);
|
||||
if ( tableReference != null) {
|
||||
return tableReference;
|
||||
}
|
||||
|
|
|
@ -12,9 +12,25 @@ import org.hibernate.query.NavigablePath;
|
|||
* @author Steve Ebersole
|
||||
*/
|
||||
public interface ColumnReferenceQualifier {
|
||||
TableReference resolveTableReference(NavigablePath navigablePath, String tableExpression);
|
||||
TableReference getTableReference(NavigablePath navigablePath, String tableExpression);
|
||||
default TableReference resolveTableReference(NavigablePath navigablePath, String tableExpression) {
|
||||
return resolveTableReference( navigablePath, tableExpression, true );
|
||||
}
|
||||
|
||||
TableReference resolveTableReference(
|
||||
NavigablePath navigablePath,
|
||||
String tableExpression,
|
||||
boolean allowFkOptimization);
|
||||
|
||||
default TableReference getTableReference(NavigablePath navigablePath, String tableExpression) {
|
||||
return getTableReference( navigablePath, tableExpression, true );
|
||||
}
|
||||
|
||||
TableReference getTableReference(
|
||||
NavigablePath navigablePath,
|
||||
String tableExpression,
|
||||
boolean allowFkOptimization);
|
||||
|
||||
default TableReference getTableReference(String tableExpression) {
|
||||
return getTableReference( null, tableExpression );
|
||||
return getTableReference( null, tableExpression, true );
|
||||
}
|
||||
}
|
||||
|
|
|
@ -108,18 +108,30 @@ public class CompositeTableGroup implements VirtualTableGroup {
|
|||
}
|
||||
|
||||
@Override
|
||||
public TableReference getTableReference(NavigablePath navigablePath, String tableExpression) {
|
||||
return underlyingTableGroup.getTableReference( navigablePath, tableExpression );
|
||||
public TableReference getTableReference(
|
||||
NavigablePath navigablePath,
|
||||
String tableExpression,
|
||||
boolean allowFkOptimization) {
|
||||
return underlyingTableGroup.getTableReference( navigablePath, tableExpression, allowFkOptimization );
|
||||
}
|
||||
|
||||
@Override
|
||||
public TableReference resolveTableReference(NavigablePath navigablePath, String tableExpression) {
|
||||
TableReference tableReference = underlyingTableGroup.getTableReference( navigablePath, tableExpression );
|
||||
public TableReference resolveTableReference(
|
||||
NavigablePath navigablePath,
|
||||
String tableExpression,
|
||||
boolean allowFkOptimization) {
|
||||
final TableReference tableReference = underlyingTableGroup.getTableReference(
|
||||
navigablePath,
|
||||
tableExpression,
|
||||
allowFkOptimization
|
||||
);
|
||||
if ( tableReference != null ) {
|
||||
return tableReference;
|
||||
}
|
||||
for ( TableGroupJoin tableGroupJoin : getTableGroupJoins() ) {
|
||||
final TableReference primaryTableReference = tableGroupJoin.getJoinedGroup().getPrimaryTableReference().getTableReference( navigablePath, tableExpression );
|
||||
final TableReference primaryTableReference = tableGroupJoin.getJoinedGroup()
|
||||
.getPrimaryTableReference()
|
||||
.getTableReference( navigablePath, tableExpression, allowFkOptimization );
|
||||
if ( primaryTableReference != null ) {
|
||||
return primaryTableReference;
|
||||
}
|
||||
|
|
|
@ -61,19 +61,30 @@ public class CorrelatedTableGroup extends AbstractTableGroup {
|
|||
@Override
|
||||
protected TableReference getTableReferenceInternal(
|
||||
NavigablePath navigablePath,
|
||||
String tableExpression) {
|
||||
final TableReference primaryTableReference = correlatedTableGroup.getPrimaryTableReference().getTableReference( navigablePath, tableExpression );
|
||||
String tableExpression,
|
||||
boolean allowFkOptimization) {
|
||||
final TableReference primaryTableReference = correlatedTableGroup.getPrimaryTableReference().getTableReference(
|
||||
navigablePath,
|
||||
tableExpression,
|
||||
allowFkOptimization
|
||||
);
|
||||
if ( primaryTableReference != null ) {
|
||||
return primaryTableReference;
|
||||
}
|
||||
for ( TableGroupJoin tableGroupJoin : getTableGroupJoins() ) {
|
||||
final TableReference groupTableReference = tableGroupJoin.getJoinedGroup().getPrimaryTableReference().getTableReference( navigablePath, tableExpression );
|
||||
final TableReference groupTableReference = tableGroupJoin.getJoinedGroup()
|
||||
.getPrimaryTableReference()
|
||||
.getTableReference( navigablePath, tableExpression, allowFkOptimization );
|
||||
if ( groupTableReference != null ) {
|
||||
return groupTableReference;
|
||||
}
|
||||
}
|
||||
for ( TableReferenceJoin tableReferenceJoin : correlatedTableGroup.getTableReferenceJoins() ) {
|
||||
final TableReference tableReference = tableReferenceJoin.getJoinedTableReference().getTableReference( navigablePath, tableExpression );
|
||||
final TableReference tableReference = tableReferenceJoin.getJoinedTableReference().getTableReference(
|
||||
navigablePath,
|
||||
tableExpression,
|
||||
allowFkOptimization
|
||||
);
|
||||
if ( tableReference != null ) {
|
||||
return tableReference;
|
||||
}
|
||||
|
|
|
@ -158,38 +158,19 @@ public class LazyTableGroup extends AbstractColumnReferenceQualifier implements
|
|||
@Override
|
||||
public TableReference getTableReferenceInternal(
|
||||
NavigablePath navigablePath,
|
||||
String tableExpression) {
|
||||
/*
|
||||
todo (6.0): I think this could still return the wrong table reference in the following scenario
|
||||
a self-referential many-to-one association with a non-PK FK is join fetched
|
||||
The fetch for the property which is the FK target would be read from the parent which is wrong
|
||||
|
||||
@Entity
|
||||
class Book {
|
||||
@Id int id;
|
||||
String isbn;
|
||||
@ManyToOne
|
||||
@JoinColumn(name = "parentIsbn", referenceColumnName = "isbn")
|
||||
Book parentBook;
|
||||
}
|
||||
|
||||
For data [Book(isbn=123),Book(isbn=456, parentBook=123)] the query
|
||||
`from Book b join fetch b.parentBook where b.isbn = '456'`
|
||||
would lead to to fetching [Book(isbn=123),Book(isbn=123, parentBook=123)].
|
||||
I think the solution for this would be to pass a boolean flag to skip the parent table group,
|
||||
which is always set when resolving for a fetch since the fetch needs the target property value
|
||||
*/
|
||||
|
||||
if ( navigablePath == null || navigablePathChecker.test( navigablePath, tableExpression ) ) {
|
||||
String tableExpression,
|
||||
boolean allowFkOptimization) {
|
||||
if ( allowFkOptimization && ( navigablePath == null || navigablePathChecker.test( navigablePath, tableExpression ) ) ) {
|
||||
final TableReference reference = parentTableGroup.getTableReference(
|
||||
navigablePath,
|
||||
tableExpression
|
||||
tableExpression,
|
||||
allowFkOptimization
|
||||
);
|
||||
if ( reference != null ) {
|
||||
return reference;
|
||||
}
|
||||
}
|
||||
return getTableGroup().getTableReference( navigablePath, tableExpression );
|
||||
return getTableGroup().getTableReference( navigablePath, tableExpression, allowFkOptimization );
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -60,15 +60,21 @@ public class MutatingTableReferenceGroupWrapper implements VirtualTableGroup {
|
|||
}
|
||||
|
||||
@Override
|
||||
public TableReference getTableReference(NavigablePath navigablePath, String tableExpression) {
|
||||
public TableReference getTableReference(
|
||||
NavigablePath navigablePath,
|
||||
String tableExpression,
|
||||
boolean allowFkOptimization) {
|
||||
return mutatingTableReference.getTableExpression().equals( tableExpression )
|
||||
? mutatingTableReference
|
||||
: null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TableReference resolveTableReference(NavigablePath navigablePath, String tableExpression) {
|
||||
return getTableReference( navigablePath, tableExpression );
|
||||
public TableReference resolveTableReference(
|
||||
NavigablePath navigablePath,
|
||||
String tableExpression,
|
||||
boolean allowFkOptimization) {
|
||||
return getTableReference( navigablePath, tableExpression, allowFkOptimization );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -133,8 +133,12 @@ public class StandardTableGroup extends AbstractTableGroup {
|
|||
@Override
|
||||
public TableReference getTableReferenceInternal(
|
||||
NavigablePath navigablePath,
|
||||
String tableExpression) {
|
||||
TableReference tableReference = primaryTableReference.getTableReference( navigablePath, tableExpression );
|
||||
String tableExpression, boolean allowFkOptimization) {
|
||||
final TableReference tableReference = primaryTableReference.getTableReference(
|
||||
navigablePath,
|
||||
tableExpression,
|
||||
allowFkOptimization
|
||||
);
|
||||
if ( tableReference != null ) {
|
||||
return tableReference;
|
||||
}
|
||||
|
@ -145,7 +149,7 @@ public class StandardTableGroup extends AbstractTableGroup {
|
|||
final TableReferenceJoin join = tableJoins.get( i );
|
||||
assert join != null;
|
||||
final TableReference resolveTableReference = join.getJoinedTableReference()
|
||||
.getTableReference( navigablePath, tableExpression );
|
||||
.getTableReference( navigablePath, tableExpression, allowFkOptimization );
|
||||
if ( resolveTableReference != null ) {
|
||||
return resolveTableReference;
|
||||
}
|
||||
|
@ -157,7 +161,7 @@ public class StandardTableGroup extends AbstractTableGroup {
|
|||
|
||||
for ( TableGroupJoin tableGroupJoin : getTableGroupJoins() ) {
|
||||
final TableReference primaryTableReference = tableGroupJoin.getJoinedGroup().getPrimaryTableReference();
|
||||
if ( primaryTableReference.getTableReference( navigablePath, tableExpression ) != null ) {
|
||||
if ( primaryTableReference.getTableReference( navigablePath, tableExpression, allowFkOptimization ) != null ) {
|
||||
return primaryTableReference;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -52,7 +52,10 @@ public class TableReference implements SqlAstNode, ColumnReferenceQualifier {
|
|||
}
|
||||
|
||||
@Override
|
||||
public TableReference resolveTableReference(NavigablePath navigablePath, String tableExpression) {
|
||||
public TableReference resolveTableReference(
|
||||
NavigablePath navigablePath,
|
||||
String tableExpression,
|
||||
boolean allowFkOptimization) {
|
||||
if ( tableExpression.equals( getTableExpression() ) ) {
|
||||
return this;
|
||||
}
|
||||
|
@ -60,7 +63,10 @@ public class TableReference implements SqlAstNode, ColumnReferenceQualifier {
|
|||
}
|
||||
|
||||
@Override
|
||||
public TableReference getTableReference(NavigablePath navigablePath, String tableExpression) {
|
||||
public TableReference getTableReference(
|
||||
NavigablePath navigablePath,
|
||||
String tableExpression,
|
||||
boolean allowFkOptimization) {
|
||||
if ( this.tableExpression.equals( tableExpression ) ) {
|
||||
return this;
|
||||
}
|
||||
|
|
|
@ -113,19 +113,25 @@ public class UnionTableGroup implements VirtualTableGroup {
|
|||
}
|
||||
|
||||
@Override
|
||||
public TableReference getTableReference(NavigablePath navigablePath, String tableExpression) {
|
||||
return resolveTableReference( navigablePath, tableExpression );
|
||||
public TableReference getTableReference(
|
||||
NavigablePath navigablePath,
|
||||
String tableExpression,
|
||||
boolean allowFkOptimization) {
|
||||
return resolveTableReference( navigablePath, tableExpression, allowFkOptimization );
|
||||
}
|
||||
|
||||
@Override
|
||||
public TableReference resolveTableReference(NavigablePath navigablePath, String tableExpression) {
|
||||
if ( tableReference.getTableReference( navigablePath, tableExpression ) != null ) {
|
||||
public TableReference resolveTableReference(
|
||||
NavigablePath navigablePath,
|
||||
String tableExpression,
|
||||
boolean allowFkOptimization) {
|
||||
if ( tableReference.getTableReference( navigablePath, tableExpression, allowFkOptimization ) != null ) {
|
||||
return tableReference;
|
||||
}
|
||||
if ( tableGroupJoins != null ) {
|
||||
for ( TableGroupJoin tableGroupJoin : tableGroupJoins ) {
|
||||
final TableReference tableReference = tableGroupJoin.getJoinedGroup()
|
||||
.resolveTableReference( navigablePath, tableExpression );
|
||||
.resolveTableReference( navigablePath, tableExpression, allowFkOptimization );
|
||||
if ( tableReference != null ) {
|
||||
return tableReference;
|
||||
}
|
||||
|
|
|
@ -27,7 +27,10 @@ public class UnionTableReference extends TableReference {
|
|||
}
|
||||
|
||||
@Override
|
||||
public TableReference resolveTableReference(NavigablePath navigablePath, String tableExpression) {
|
||||
public TableReference resolveTableReference(
|
||||
NavigablePath navigablePath,
|
||||
String tableExpression,
|
||||
boolean allowFkOptimization) {
|
||||
if ( hasTableExpression( tableExpression ) ) {
|
||||
return this;
|
||||
}
|
||||
|
@ -35,7 +38,10 @@ public class UnionTableReference extends TableReference {
|
|||
}
|
||||
|
||||
@Override
|
||||
public TableReference getTableReference(NavigablePath navigablePath, String tableExpression) {
|
||||
public TableReference getTableReference(
|
||||
NavigablePath navigablePath,
|
||||
String tableExpression,
|
||||
boolean allowFkOptimization) {
|
||||
if ( hasTableExpression( tableExpression ) ) {
|
||||
return this;
|
||||
}
|
||||
|
|
|
@ -101,13 +101,19 @@ public class EntityCollectionPartTableGroup implements TableGroup {
|
|||
}
|
||||
|
||||
@Override
|
||||
public TableReference getTableReference(NavigablePath navigablePath, String tableExpression) {
|
||||
return collectionTableGroup.getTableReference( navigablePath, tableExpression );
|
||||
public TableReference getTableReference(
|
||||
NavigablePath navigablePath,
|
||||
String tableExpression,
|
||||
boolean allowFkOptimization) {
|
||||
return collectionTableGroup.getTableReference( navigablePath, tableExpression, allowFkOptimization );
|
||||
}
|
||||
|
||||
@Override
|
||||
public TableReference resolveTableReference(NavigablePath navigablePath, String tableExpression) {
|
||||
return collectionTableGroup.resolveTableReference( navigablePath, tableExpression );
|
||||
public TableReference resolveTableReference(
|
||||
NavigablePath navigablePath,
|
||||
String tableExpression,
|
||||
boolean allowFkOptimization) {
|
||||
return collectionTableGroup.resolveTableReference( navigablePath, tableExpression, allowFkOptimization );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
Loading…
Reference in New Issue