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 PART_NAME = "{fk}";
|
||||||
|
String TARGET_PART_NAME = "{fk-target}";
|
||||||
|
|
||||||
String getKeyTable();
|
String getKeyTable();
|
||||||
|
|
||||||
|
|
|
@ -306,26 +306,12 @@ public class EmbeddedForeignKeyDescriptor implements ForeignKeyDescriptor {
|
||||||
String columnContainingTable,
|
String columnContainingTable,
|
||||||
EmbeddableValuedModelPart modelPart,
|
EmbeddableValuedModelPart modelPart,
|
||||||
DomainResultCreationState creationState) {
|
DomainResultCreationState creationState) {
|
||||||
final NavigablePath fkNavigablePath = navigablePath.append( getPartName() );
|
|
||||||
final NavigablePath resultNavigablePath;
|
final NavigablePath resultNavigablePath;
|
||||||
if ( associationKey.getTable().equals( columnContainingTable ) ) {
|
if ( modelPart == keySide.getModelPart() ) {
|
||||||
final ModelPartContainer parentModelPart = tableGroup.getModelPart();
|
resultNavigablePath = navigablePath.append( ForeignKeyDescriptor.PART_NAME );
|
||||||
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() );
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
resultNavigablePath = navigablePath.append( getPartName() );
|
resultNavigablePath = navigablePath.append( ForeignKeyDescriptor.TARGET_PART_NAME );
|
||||||
}
|
}
|
||||||
final TableGroup fkTableGroup = creationState.getSqlAstCreationState().getFromClauseAccess().resolveTableGroup(
|
final TableGroup fkTableGroup = creationState.getSqlAstCreationState().getFromClauseAccess().resolveTableGroup(
|
||||||
resultNavigablePath,
|
resultNavigablePath,
|
||||||
|
@ -343,12 +329,6 @@ public class EmbeddedForeignKeyDescriptor implements ForeignKeyDescriptor {
|
||||||
return tableGroupJoin.getJoinedGroup();
|
return tableGroupJoin.getJoinedGroup();
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
if ( fkNavigablePath != resultNavigablePath ) {
|
|
||||||
creationState.getSqlAstCreationState().getFromClauseAccess().resolveTableGroup(
|
|
||||||
fkNavigablePath,
|
|
||||||
np -> fkTableGroup
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
final Nature currentForeignKeyResolvingKey = creationState.getCurrentlyResolvingForeignKeyPart();
|
final Nature currentForeignKeyResolvingKey = creationState.getCurrentlyResolvingForeignKeyPart();
|
||||||
try {
|
try {
|
||||||
|
|
|
@ -232,10 +232,17 @@ public class SimpleForeignKeyDescriptor implements ForeignKeyDescriptor, BasicVa
|
||||||
final SqlAstCreationState sqlAstCreationState = creationState.getSqlAstCreationState();
|
final SqlAstCreationState sqlAstCreationState = creationState.getSqlAstCreationState();
|
||||||
final SqlExpressionResolver sqlExpressionResolver = sqlAstCreationState.getSqlExpressionResolver();
|
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;
|
final TableReference tableReference;
|
||||||
try {
|
try {
|
||||||
tableReference = tableGroup.resolveTableReference(
|
tableReference = tableGroup.resolveTableReference(
|
||||||
navigablePath.append( getTargetPart().getFetchableName() ),
|
resultNavigablePath,
|
||||||
selectableMapping.getContainingTableExpression()
|
selectableMapping.getContainingTableExpression()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -748,7 +748,8 @@ public class ToOneAttributeMapping
|
||||||
private Key key;
|
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?
|
// 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;
|
return null;
|
||||||
}
|
}
|
||||||
|
@ -1363,80 +1364,80 @@ public class ToOneAttributeMapping
|
||||||
// This is vital for the map key property check that comes next
|
// This is vital for the map key property check that comes next
|
||||||
assert !( lhs instanceof PluralTableGroup );
|
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 );
|
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
|
// 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
|
// 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() )
|
if ( !addsPredicate && ( joinType == SqlAstJoinType.INNER || joinType == SqlAstJoinType.LEFT ) ) {
|
||||||
&& !addsPredicate && ( joinType == SqlAstJoinType.INNER || joinType == SqlAstJoinType.LEFT ) ) {
|
TableGroup parentTableGroup = lhs;
|
||||||
final PluralTableGroup pluralTableGroup = (PluralTableGroup) fromClauseAccess.findTableGroup(
|
ModelPartContainer parentContainer = lhs.getModelPart();
|
||||||
parentTableGroup.getNavigablePath().getParent()
|
StringBuilder embeddablePathSb = null;
|
||||||
);
|
// Traverse up embeddable table groups until we find a table group for a collection part
|
||||||
final String indexPropertyName = pluralTableGroup.getModelPart()
|
while ( !( parentContainer instanceof CollectionPart ) ) {
|
||||||
.getIndexMetadata()
|
if ( parentContainer instanceof EmbeddableValuedModelPart ) {
|
||||||
.getIndexPropertyName();
|
if ( embeddablePathSb == null ) {
|
||||||
final String pathName;
|
embeddablePathSb = new StringBuilder();
|
||||||
if ( embeddablePathSb != null ) {
|
}
|
||||||
pathName = embeddablePathSb.append( getAttributeName() ).toString();
|
embeddablePathSb.insert( 0, parentContainer.getPartName() + "." );
|
||||||
|
parentTableGroup = fromClauseAccess.findTableGroup( parentTableGroup.getNavigablePath().getParent() );
|
||||||
|
parentContainer = parentTableGroup.getModelPart();
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
if ( CollectionPart.Nature.ELEMENT.getName().equals( parentTableGroup.getNavigablePath().getUnaliasedLocalName() ) ) {
|
||||||
pathName = getAttributeName();
|
final PluralTableGroup pluralTableGroup = (PluralTableGroup) fromClauseAccess.findTableGroup(
|
||||||
}
|
parentTableGroup.getNavigablePath().getParent()
|
||||||
if ( pathName.equals( indexPropertyName ) ) {
|
);
|
||||||
final TableGroup indexTableGroup = pluralTableGroup.getIndexTableGroup();
|
final String indexPropertyName = pluralTableGroup.getModelPart()
|
||||||
// If this is the map key property, we can reuse the index table group
|
.getIndexMetadata()
|
||||||
initializeIfNeeded( lhs, requestedJoinType, indexTableGroup );
|
.getIndexPropertyName();
|
||||||
return new TableGroupJoin(
|
final String pathName;
|
||||||
navigablePath,
|
if ( embeddablePathSb != null ) {
|
||||||
joinType,
|
pathName = embeddablePathSb.append( getAttributeName() ).toString();
|
||||||
new MappedByTableGroup(
|
}
|
||||||
navigablePath,
|
else {
|
||||||
this,
|
pathName = getAttributeName();
|
||||||
indexTableGroup,
|
}
|
||||||
fetched,
|
if ( pathName.equals( indexPropertyName ) ) {
|
||||||
pluralTableGroup,
|
final TableGroup indexTableGroup = pluralTableGroup.getIndexTableGroup();
|
||||||
(np, tableExpression) -> {
|
// If this is the map key property, we can reuse the index table group
|
||||||
if ( !canUseParentTableGroup ) {
|
initializeIfNeeded( lhs, requestedJoinType, indexTableGroup );
|
||||||
return false;
|
return new TableGroupJoin(
|
||||||
}
|
navigablePath,
|
||||||
NavigablePath path = np.getParent();
|
joinType,
|
||||||
// Fast path
|
new MappedByTableGroup(
|
||||||
if ( navigablePath.equals( path ) ) {
|
navigablePath,
|
||||||
return targetKeyPropertyNames.contains( np.getUnaliasedLocalName() )
|
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 );
|
&& identifyingColumnsTableExpression.equals( tableExpression );
|
||||||
}
|
}
|
||||||
final StringBuilder sb = new StringBuilder( np.getFullPath().length() );
|
),
|
||||||
sb.append( np.getUnaliasedLocalName() );
|
null
|
||||||
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
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
// We never want to create empty composites for the FK target or PK, otherwise collections would break
|
||||||
createEmptyCompositesEnabled = !ForeignKeyDescriptor.PART_NAME.equals( navigablePath.getLocalName() )
|
createEmptyCompositesEnabled = !ForeignKeyDescriptor.PART_NAME.equals( navigablePath.getUnaliasedLocalName() )
|
||||||
&& !EntityIdentifierMapping.ROLE_LOCAL_NAME.equals( navigablePath.getLocalName() )
|
&& !ForeignKeyDescriptor.TARGET_PART_NAME.equals( navigablePath.getUnaliasedLocalName() )
|
||||||
|
&& !EntityIdentifierMapping.ROLE_LOCAL_NAME.equals( navigablePath.getUnaliasedLocalName() )
|
||||||
&& embeddableTypeDescriptor.isCreateEmptyCompositesEnabled();
|
&& embeddableTypeDescriptor.isCreateEmptyCompositesEnabled();
|
||||||
|
|
||||||
sessionFactory = creationState.getSqlAstCreationContext().getSessionFactory();
|
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.
|
// so we can't use the fetch parent access in that case.
|
||||||
if ( fetchParentAccess != null && embedded instanceof VirtualModelPart
|
if ( fetchParentAccess != null && embedded instanceof VirtualModelPart
|
||||||
&& !EntityIdentifierMapping.ROLE_LOCAL_NAME.equals( embedded.getFetchableName() )
|
&& !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 );
|
fetchParentAccess.resolveInstance( processingState );
|
||||||
compositeInstance = fetchParentAccess.getInitializedInstance();
|
compositeInstance = fetchParentAccess.getInitializedInstance();
|
||||||
}
|
}
|
||||||
|
@ -253,7 +255,8 @@ public abstract class AbstractEmbeddableInitializer extends AbstractFetchParentA
|
||||||
|
|
||||||
private void extractRowState(RowProcessingState processingState) {
|
private void extractRowState(RowProcessingState processingState) {
|
||||||
stateAllNull = true;
|
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() );
|
|| EntityIdentifierMapping.ROLE_LOCAL_NAME.equals( embedded.getFetchableName() );
|
||||||
for ( int i = 0; i < assemblers.size(); i++ ) {
|
for ( int i = 0; i < assemblers.size(); i++ ) {
|
||||||
final DomainResultAssembler<?> assembler = assemblers.get( i );
|
final DomainResultAssembler<?> assembler = assemblers.get( i );
|
||||||
|
|
|
@ -66,7 +66,8 @@ public class EmbeddableForeignKeyResultImpl<T>
|
||||||
final ToOneAttributeMapping toOne = (ToOneAttributeMapping) fetchable;
|
final ToOneAttributeMapping toOne = (ToOneAttributeMapping) fetchable;
|
||||||
shouldSelect = selected && !creationState.isAssociationKeyVisited(
|
shouldSelect = selected && !creationState.isAssociationKeyVisited(
|
||||||
toOne.getForeignKeyDescriptor().getAssociationKey()
|
toOne.getForeignKeyDescriptor().getAssociationKey()
|
||||||
) && !ForeignKeyDescriptor.PART_NAME.equals( getNavigablePath().getLocalName() );
|
) && !ForeignKeyDescriptor.PART_NAME.equals( getNavigablePath().getLocalName() )
|
||||||
|
&& !ForeignKeyDescriptor.TARGET_PART_NAME.equals( getNavigablePath().getLocalName() );
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
shouldSelect = selected;
|
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
|
// We only need to select in this phase if this is part of an identifier or foreign key
|
||||||
NavigablePath np = navigablePath.getParent();
|
NavigablePath np = navigablePath.getParent();
|
||||||
while ( np != null ) {
|
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 );
|
initializeInstance( rowProcessingState );
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue