Introduce special part name for FK target part to avoid issues with composite FK initializers

This commit is contained in:
Christian Beikov 2022-03-10 10:49:07 +01:00
parent 0ca38c8c87
commit c548a79f0b
7 changed files with 93 additions and 98 deletions

View File

@ -44,6 +44,7 @@ public interface ForeignKeyDescriptor extends VirtualModelPart, ValueMapping {
}
String PART_NAME = "{fk}";
String TARGET_PART_NAME = "{fk-target}";
String getKeyTable();

View File

@ -306,26 +306,12 @@ public class EmbeddedForeignKeyDescriptor implements ForeignKeyDescriptor {
String columnContainingTable,
EmbeddableValuedModelPart modelPart,
DomainResultCreationState creationState) {
final NavigablePath fkNavigablePath = navigablePath.append( getPartName() );
final NavigablePath resultNavigablePath;
if ( associationKey.getTable().equals( columnContainingTable ) ) {
final ModelPartContainer parentModelPart = tableGroup.getModelPart();
if ( parentModelPart instanceof PluralAttributeMapping ) {
if ( ( (PluralAttributeMapping) parentModelPart ).getIndexDescriptor() == null ) {
resultNavigablePath = navigablePath.append( CollectionPart.Nature.ELEMENT.getName() )
.append( getPartName() );
if ( modelPart == keySide.getModelPart() ) {
resultNavigablePath = navigablePath.append( ForeignKeyDescriptor.PART_NAME );
}
else {
resultNavigablePath = navigablePath.append( CollectionPart.Nature.INDEX.getName() )
.append( getPartName() );
}
}
else {
resultNavigablePath = navigablePath.append( getPartName() );
}
}
else {
resultNavigablePath = navigablePath.append( getPartName() );
resultNavigablePath = navigablePath.append( ForeignKeyDescriptor.TARGET_PART_NAME );
}
final TableGroup fkTableGroup = creationState.getSqlAstCreationState().getFromClauseAccess().resolveTableGroup(
resultNavigablePath,
@ -343,12 +329,6 @@ public class EmbeddedForeignKeyDescriptor implements ForeignKeyDescriptor {
return tableGroupJoin.getJoinedGroup();
}
);
if ( fkNavigablePath != resultNavigablePath ) {
creationState.getSqlAstCreationState().getFromClauseAccess().resolveTableGroup(
fkNavigablePath,
np -> fkTableGroup
);
}
final Nature currentForeignKeyResolvingKey = creationState.getCurrentlyResolvingForeignKeyPart();
try {

View File

@ -232,10 +232,17 @@ public class SimpleForeignKeyDescriptor implements ForeignKeyDescriptor, BasicVa
final SqlAstCreationState sqlAstCreationState = creationState.getSqlAstCreationState();
final SqlExpressionResolver sqlExpressionResolver = sqlAstCreationState.getSqlExpressionResolver();
final NavigablePath resultNavigablePath;
if ( selectableMapping == keySide.getModelPart() ) {
resultNavigablePath = navigablePath.append( ForeignKeyDescriptor.PART_NAME );
}
else {
resultNavigablePath = navigablePath.append( ForeignKeyDescriptor.TARGET_PART_NAME );
}
final TableReference tableReference;
try {
tableReference = tableGroup.resolveTableReference(
navigablePath.append( getTargetPart().getFetchableName() ),
resultNavigablePath,
selectableMapping.getContainingTableExpression()
);
}

View File

@ -748,7 +748,8 @@ public class ToOneAttributeMapping
private Key key;
}
*/
if ( parentNavigablePath.getLocalName().equals( ForeignKeyDescriptor.PART_NAME ) ) {
if ( parentNavigablePath.getUnaliasedLocalName().equals( ForeignKeyDescriptor.PART_NAME )
|| parentNavigablePath.getUnaliasedLocalName().equals( ForeignKeyDescriptor.TARGET_PART_NAME ) ) {
// todo (6.0): maybe it's better to have a flag in creation state that marks if we are building a circular fetch domain result already to skip this?
return null;
}
@ -1363,6 +1364,11 @@ public class ToOneAttributeMapping
// This is vital for the map key property check that comes next
assert !( lhs instanceof PluralTableGroup );
final SqlAstJoinType joinType = requireNonNullElse( requestedJoinType, SqlAstJoinType.INNER );
// If a parent is a collection part, there is no custom predicate and the join is INNER or LEFT
// we check if this attribute is the map key property to reuse the existing index table group
if ( !addsPredicate && ( joinType == SqlAstJoinType.INNER || joinType == SqlAstJoinType.LEFT ) ) {
TableGroup parentTableGroup = lhs;
ModelPartContainer parentContainer = lhs.getModelPart();
StringBuilder embeddablePathSb = null;
@ -1380,13 +1386,7 @@ public class ToOneAttributeMapping
break;
}
}
final SqlAstJoinType joinType = requireNonNullElse( requestedJoinType, SqlAstJoinType.INNER );
// If a parent is a collection part, there is no custom predicate and the join is INNER or LEFT
// we check if this attribute is the map key property to reuse the existing index table group
if ( CollectionPart.Nature.ELEMENT.getName().equals( parentTableGroup.getNavigablePath().getUnaliasedLocalName() )
&& !addsPredicate && ( joinType == SqlAstJoinType.INNER || joinType == SqlAstJoinType.LEFT ) ) {
if ( CollectionPart.Nature.ELEMENT.getName().equals( parentTableGroup.getNavigablePath().getUnaliasedLocalName() ) ) {
final PluralTableGroup pluralTableGroup = (PluralTableGroup) fromClauseAccess.findTableGroup(
parentTableGroup.getNavigablePath().getParent()
);
@ -1439,6 +1439,7 @@ public class ToOneAttributeMapping
);
}
}
}
final LazyTableGroup lazyTableGroup = createRootTableGroupJoin(
navigablePath,

View File

@ -108,8 +108,9 @@ public abstract class AbstractEmbeddableInitializer extends AbstractFetchParentA
);
// We never want to create empty composites for the FK target or PK, otherwise collections would break
createEmptyCompositesEnabled = !ForeignKeyDescriptor.PART_NAME.equals( navigablePath.getLocalName() )
&& !EntityIdentifierMapping.ROLE_LOCAL_NAME.equals( navigablePath.getLocalName() )
createEmptyCompositesEnabled = !ForeignKeyDescriptor.PART_NAME.equals( navigablePath.getUnaliasedLocalName() )
&& !ForeignKeyDescriptor.TARGET_PART_NAME.equals( navigablePath.getUnaliasedLocalName() )
&& !EntityIdentifierMapping.ROLE_LOCAL_NAME.equals( navigablePath.getUnaliasedLocalName() )
&& embeddableTypeDescriptor.isCreateEmptyCompositesEnabled();
sessionFactory = creationState.getSqlAstCreationContext().getSessionFactory();
@ -231,7 +232,8 @@ public abstract class AbstractEmbeddableInitializer extends AbstractFetchParentA
// so we can't use the fetch parent access in that case.
if ( fetchParentAccess != null && embedded instanceof VirtualModelPart
&& !EntityIdentifierMapping.ROLE_LOCAL_NAME.equals( embedded.getFetchableName() )
&& !ForeignKeyDescriptor.PART_NAME.equals( navigablePath.getUnaliasedLocalName() ) ) {
&& !ForeignKeyDescriptor.PART_NAME.equals( navigablePath.getUnaliasedLocalName() )
&& !ForeignKeyDescriptor.TARGET_PART_NAME.equals( navigablePath.getUnaliasedLocalName() ) ) {
fetchParentAccess.resolveInstance( processingState );
compositeInstance = fetchParentAccess.getInitializedInstance();
}
@ -253,7 +255,8 @@ public abstract class AbstractEmbeddableInitializer extends AbstractFetchParentA
private void extractRowState(RowProcessingState processingState) {
stateAllNull = true;
final boolean isKey = ForeignKeyDescriptor.PART_NAME.equals( navigablePath.getLocalName() )
final boolean isKey = ForeignKeyDescriptor.PART_NAME.equals( navigablePath.getUnaliasedLocalName() )
|| ForeignKeyDescriptor.TARGET_PART_NAME.equals( navigablePath.getUnaliasedLocalName() )
|| EntityIdentifierMapping.ROLE_LOCAL_NAME.equals( embedded.getFetchableName() );
for ( int i = 0; i < assemblers.size(); i++ ) {
final DomainResultAssembler<?> assembler = assemblers.get( i );

View File

@ -66,7 +66,8 @@ public class EmbeddableForeignKeyResultImpl<T>
final ToOneAttributeMapping toOne = (ToOneAttributeMapping) fetchable;
shouldSelect = selected && !creationState.isAssociationKeyVisited(
toOne.getForeignKeyDescriptor().getAssociationKey()
) && !ForeignKeyDescriptor.PART_NAME.equals( getNavigablePath().getLocalName() );
) && !ForeignKeyDescriptor.PART_NAME.equals( getNavigablePath().getLocalName() )
&& !ForeignKeyDescriptor.TARGET_PART_NAME.equals( getNavigablePath().getLocalName() );
}
else {
shouldSelect = selected;

View File

@ -87,7 +87,9 @@ public class EntitySelectFetchInitializer extends AbstractFetchParentAccess impl
// We only need to select in this phase if this is part of an identifier or foreign key
NavigablePath np = navigablePath.getParent();
while ( np != null ) {
if ( np instanceof EntityIdentifierNavigablePath || ForeignKeyDescriptor.PART_NAME.equals( np.getUnaliasedLocalName() ) ) {
if ( np instanceof EntityIdentifierNavigablePath
|| ForeignKeyDescriptor.PART_NAME.equals( np.getUnaliasedLocalName() )
|| ForeignKeyDescriptor.TARGET_PART_NAME.equals( np.getUnaliasedLocalName() )) {
initializeInstance( rowProcessingState );
return;
}