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:
parent
a864e25339
commit
3be99c1c73
|
@ -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;
|
||||
|
|
|
@ -13,4 +13,5 @@ import org.hibernate.sql.results.graph.Fetchable;
|
|||
*/
|
||||
public interface Association extends Fetchable {
|
||||
ForeignKeyDescriptor getForeignKeyDescriptor();
|
||||
ForeignKeyDescriptor.Side getSide();
|
||||
}
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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[];
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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(
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -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 );
|
||||
|
|
Loading…
Reference in New Issue