Introduce special part name for FK target part to avoid issues with composite FK initializers
This commit is contained in:
parent
0ca38c8c87
commit
c548a79f0b
|
@ -44,6 +44,7 @@ public interface ForeignKeyDescriptor extends VirtualModelPart, ValueMapping {
|
|||
}
|
||||
|
||||
String PART_NAME = "{fk}";
|
||||
String TARGET_PART_NAME = "{fk-target}";
|
||||
|
||||
String getKeyTable();
|
||||
|
||||
|
|
|
@ -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() );
|
||||
}
|
||||
else {
|
||||
resultNavigablePath = navigablePath.append( CollectionPart.Nature.INDEX.getName() )
|
||||
.append( getPartName() );
|
||||
}
|
||||
}
|
||||
else {
|
||||
resultNavigablePath = navigablePath.append( getPartName() );
|
||||
}
|
||||
if ( modelPart == keySide.getModelPart() ) {
|
||||
resultNavigablePath = navigablePath.append( ForeignKeyDescriptor.PART_NAME );
|
||||
}
|
||||
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 {
|
||||
|
|
|
@ -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()
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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,80 +1364,80 @@ public class ToOneAttributeMapping
|
|||
// This is vital for the map key property check that comes next
|
||||
assert !( lhs instanceof PluralTableGroup );
|
||||
|
||||
TableGroup parentTableGroup = lhs;
|
||||
ModelPartContainer parentContainer = lhs.getModelPart();
|
||||
StringBuilder embeddablePathSb = null;
|
||||
// Traverse up embeddable table groups until we find a table group for a collection part
|
||||
while ( !( parentContainer instanceof CollectionPart ) ) {
|
||||
if ( parentContainer instanceof EmbeddableValuedModelPart ) {
|
||||
if ( embeddablePathSb == null ) {
|
||||
embeddablePathSb = new StringBuilder();
|
||||
}
|
||||
embeddablePathSb.insert( 0, parentContainer.getPartName() + "." );
|
||||
parentTableGroup = fromClauseAccess.findTableGroup( parentTableGroup.getNavigablePath().getParent() );
|
||||
parentContainer = parentTableGroup.getModelPart();
|
||||
}
|
||||
else {
|
||||
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 ) ) {
|
||||
final PluralTableGroup pluralTableGroup = (PluralTableGroup) fromClauseAccess.findTableGroup(
|
||||
parentTableGroup.getNavigablePath().getParent()
|
||||
);
|
||||
final String indexPropertyName = pluralTableGroup.getModelPart()
|
||||
.getIndexMetadata()
|
||||
.getIndexPropertyName();
|
||||
final String pathName;
|
||||
if ( embeddablePathSb != null ) {
|
||||
pathName = embeddablePathSb.append( getAttributeName() ).toString();
|
||||
if ( !addsPredicate && ( joinType == SqlAstJoinType.INNER || joinType == SqlAstJoinType.LEFT ) ) {
|
||||
TableGroup parentTableGroup = lhs;
|
||||
ModelPartContainer parentContainer = lhs.getModelPart();
|
||||
StringBuilder embeddablePathSb = null;
|
||||
// Traverse up embeddable table groups until we find a table group for a collection part
|
||||
while ( !( parentContainer instanceof CollectionPart ) ) {
|
||||
if ( parentContainer instanceof EmbeddableValuedModelPart ) {
|
||||
if ( embeddablePathSb == null ) {
|
||||
embeddablePathSb = new StringBuilder();
|
||||
}
|
||||
embeddablePathSb.insert( 0, parentContainer.getPartName() + "." );
|
||||
parentTableGroup = fromClauseAccess.findTableGroup( parentTableGroup.getNavigablePath().getParent() );
|
||||
parentContainer = parentTableGroup.getModelPart();
|
||||
}
|
||||
else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
else {
|
||||
pathName = getAttributeName();
|
||||
}
|
||||
if ( pathName.equals( indexPropertyName ) ) {
|
||||
final TableGroup indexTableGroup = pluralTableGroup.getIndexTableGroup();
|
||||
// If this is the map key property, we can reuse the index table group
|
||||
initializeIfNeeded( lhs, requestedJoinType, indexTableGroup );
|
||||
return new TableGroupJoin(
|
||||
navigablePath,
|
||||
joinType,
|
||||
new MappedByTableGroup(
|
||||
navigablePath,
|
||||
this,
|
||||
indexTableGroup,
|
||||
fetched,
|
||||
pluralTableGroup,
|
||||
(np, tableExpression) -> {
|
||||
if ( !canUseParentTableGroup ) {
|
||||
return false;
|
||||
}
|
||||
NavigablePath path = np.getParent();
|
||||
// Fast path
|
||||
if ( navigablePath.equals( path ) ) {
|
||||
return targetKeyPropertyNames.contains( np.getUnaliasedLocalName() )
|
||||
if ( CollectionPart.Nature.ELEMENT.getName().equals( parentTableGroup.getNavigablePath().getUnaliasedLocalName() ) ) {
|
||||
final PluralTableGroup pluralTableGroup = (PluralTableGroup) fromClauseAccess.findTableGroup(
|
||||
parentTableGroup.getNavigablePath().getParent()
|
||||
);
|
||||
final String indexPropertyName = pluralTableGroup.getModelPart()
|
||||
.getIndexMetadata()
|
||||
.getIndexPropertyName();
|
||||
final String pathName;
|
||||
if ( embeddablePathSb != null ) {
|
||||
pathName = embeddablePathSb.append( getAttributeName() ).toString();
|
||||
}
|
||||
else {
|
||||
pathName = getAttributeName();
|
||||
}
|
||||
if ( pathName.equals( indexPropertyName ) ) {
|
||||
final TableGroup indexTableGroup = pluralTableGroup.getIndexTableGroup();
|
||||
// If this is the map key property, we can reuse the index table group
|
||||
initializeIfNeeded( lhs, requestedJoinType, indexTableGroup );
|
||||
return new TableGroupJoin(
|
||||
navigablePath,
|
||||
joinType,
|
||||
new MappedByTableGroup(
|
||||
navigablePath,
|
||||
this,
|
||||
indexTableGroup,
|
||||
fetched,
|
||||
pluralTableGroup,
|
||||
(np, tableExpression) -> {
|
||||
if ( !canUseParentTableGroup ) {
|
||||
return false;
|
||||
}
|
||||
NavigablePath path = np.getParent();
|
||||
// Fast path
|
||||
if ( navigablePath.equals( path ) ) {
|
||||
return targetKeyPropertyNames.contains( np.getUnaliasedLocalName() )
|
||||
&& identifyingColumnsTableExpression.equals( tableExpression );
|
||||
}
|
||||
final StringBuilder sb = new StringBuilder( np.getFullPath().length() );
|
||||
sb.append( np.getUnaliasedLocalName() );
|
||||
while ( path != null && !navigablePath.equals( path ) ) {
|
||||
sb.insert( 0, '.' );
|
||||
sb.insert( 0, path.getUnaliasedLocalName() );
|
||||
path = path.getParent();
|
||||
}
|
||||
return navigablePath.equals( path )
|
||||
&& targetKeyPropertyNames.contains( sb.toString() )
|
||||
&& identifyingColumnsTableExpression.equals( tableExpression );
|
||||
}
|
||||
final StringBuilder sb = new StringBuilder( np.getFullPath().length() );
|
||||
sb.append( np.getUnaliasedLocalName() );
|
||||
while ( path != null && !navigablePath.equals( path ) ) {
|
||||
sb.insert( 0, '.' );
|
||||
sb.insert( 0, path.getUnaliasedLocalName() );
|
||||
path = path.getParent();
|
||||
}
|
||||
return navigablePath.equals( path )
|
||||
&& targetKeyPropertyNames.contains( sb.toString() )
|
||||
&& identifyingColumnsTableExpression.equals( tableExpression );
|
||||
}
|
||||
),
|
||||
null
|
||||
);
|
||||
),
|
||||
null
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue