HHH-15132 - Improvements for NavigablePath

Begin breaking down "full path"
This commit is contained in:
Steve Ebersole 2022-03-21 14:10:59 -05:00
parent 73153be99d
commit f474449e7d
19 changed files with 190 additions and 67 deletions

View File

@ -667,14 +667,14 @@ public class EntityCollectionPart
NavigablePath path = np.getParent(); NavigablePath path = np.getParent();
// Fast path // Fast path
if ( navigablePath.equals( path ) ) { if ( navigablePath.equals( path ) ) {
return targetKeyPropertyNames.contains( np.getUnaliasedLocalName() ) return targetKeyPropertyNames.contains( np.getLocalName() )
&& fkDescriptor.getKeyTable().equals( tableExpression ); && fkDescriptor.getKeyTable().equals( tableExpression );
} }
final StringBuilder sb = new StringBuilder( np.getFullPath().length() ); final StringBuilder sb = new StringBuilder( np.getFullPath().length() );
sb.append( np.getUnaliasedLocalName() ); sb.append( np.getLocalName() );
while ( path != null && !navigablePath.equals( path ) ) { while ( path != null && !navigablePath.equals( path ) ) {
sb.insert( 0, '.' ); sb.insert( 0, '.' );
sb.insert( 0, path.getUnaliasedLocalName() ); sb.insert( 0, path.getLocalName() );
path = path.getParent(); path = path.getParent();
} }
return navigablePath.equals( path ) return navigablePath.equals( path )

View File

@ -202,7 +202,7 @@ public class PluralAttributeMappingImpl
// then we say this is bidirectional, given that this is only invoked for model parts of the collection elements // then we say this is bidirectional, given that this is only invoked for model parts of the collection elements
return fkDescriptor.getTargetPart() == modelPart.getForeignKeyDescriptor().getTargetPart(); return fkDescriptor.getTargetPart() == modelPart.getForeignKeyDescriptor().getTargetPart();
} }
return fetchablePath.getUnaliasedLocalName().endsWith( bidirectionalAttributeName ); return fetchablePath.getLocalName().endsWith( bidirectionalAttributeName );
} }
@SuppressWarnings("unused") @SuppressWarnings("unused")

View File

@ -748,8 +748,8 @@ public class ToOneAttributeMapping
private Key key; private Key key;
} }
*/ */
if ( parentNavigablePath.getUnaliasedLocalName().equals( ForeignKeyDescriptor.PART_NAME ) if ( parentNavigablePath.getLocalName().equals( ForeignKeyDescriptor.PART_NAME )
|| parentNavigablePath.getUnaliasedLocalName().equals( ForeignKeyDescriptor.TARGET_PART_NAME ) ) { || parentNavigablePath.getLocalName().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;
} }
@ -893,9 +893,9 @@ public class ToOneAttributeMapping
parent.getFullPath() = "Mother.biologicalChild" parent.getFullPath() = "Mother.biologicalChild"
*/ */
final NavigablePath grandparentNavigablePath = parentNavigablePath.getParent(); final NavigablePath grandparentNavigablePath = parentNavigablePath.getParent();
if ( parentNavigablePath.getUnaliasedLocalName().equals( CollectionPart.Nature.ELEMENT.getName() ) if ( parentNavigablePath.getLocalName().equals( CollectionPart.Nature.ELEMENT.getName() )
&& grandparentNavigablePath != null && grandparentNavigablePath != null
&& grandparentNavigablePath.getUnaliasedLocalName().equals( bidirectionalAttributeName ) ) { && grandparentNavigablePath.getLocalName().equals( bidirectionalAttributeName ) ) {
final NavigablePath parentPath = grandparentNavigablePath.getParent(); final NavigablePath parentPath = grandparentNavigablePath.getParent();
// This can be null for a collection loader // This can be null for a collection loader
if ( parentPath == null ) { if ( parentPath == null ) {
@ -915,13 +915,13 @@ public class ToOneAttributeMapping
} }
// If we have a parent, we ensure that the parent is the same as the attribute name // If we have a parent, we ensure that the parent is the same as the attribute name
else { else {
return parentPath.getUnaliasedLocalName().equals( navigableRole.getLocalName() ); return parentPath.getLocalName().equals( navigableRole.getLocalName() );
} }
} }
} }
return false; return false;
} }
return parentNavigablePath.getUnaliasedLocalName().equals( bidirectionalAttributeName ); return parentNavigablePath.getLocalName().equals( bidirectionalAttributeName );
} }
public String getBidirectionalAttributeName(){ public String getBidirectionalAttributeName(){
@ -944,7 +944,7 @@ public class ToOneAttributeMapping
referencedNavigablePath = parentNavigablePath; referencedNavigablePath = parentNavigablePath;
hasBidirectionalFetchParent = true; hasBidirectionalFetchParent = true;
} }
else if ( CollectionPart.Nature.fromNameExact( parentNavigablePath.getUnaliasedLocalName() ) != null ) { else if ( CollectionPart.Nature.fromNameExact( parentNavigablePath.getLocalName() ) != null ) {
referencedNavigablePath = parentNavigablePath.getParent().getParent(); referencedNavigablePath = parentNavigablePath.getParent().getParent();
hasBidirectionalFetchParent = fetchParent instanceof Fetch hasBidirectionalFetchParent = fetchParent instanceof Fetch
&& ( (Fetch) fetchParent ).getFetchParent() instanceof Fetch; && ( (Fetch) fetchParent ).getFetchParent() instanceof Fetch;
@ -1007,7 +1007,7 @@ public class ToOneAttributeMapping
// So we create a delayed fetch, as we are sure to find the entity in the PC // So we create a delayed fetch, as we are sure to find the entity in the PC
final FromClauseAccess fromClauseAccess = creationState.getSqlAstCreationState().getFromClauseAccess(); final FromClauseAccess fromClauseAccess = creationState.getSqlAstCreationState().getFromClauseAccess();
final NavigablePath realParent; final NavigablePath realParent;
if ( CollectionPart.Nature.fromNameExact( parentNavigablePath.getUnaliasedLocalName() ) != null ) { if ( CollectionPart.Nature.fromNameExact( parentNavigablePath.getLocalName() ) != null ) {
realParent = parentNavigablePath.getParent(); realParent = parentNavigablePath.getParent();
} }
else { else {
@ -1386,7 +1386,7 @@ public class ToOneAttributeMapping
break; break;
} }
} }
if ( CollectionPart.Nature.ELEMENT.getName().equals( parentTableGroup.getNavigablePath().getUnaliasedLocalName() ) ) { if ( CollectionPart.Nature.ELEMENT.getName().equals( parentTableGroup.getNavigablePath().getLocalName() ) ) {
final PluralTableGroup pluralTableGroup = (PluralTableGroup) fromClauseAccess.findTableGroup( final PluralTableGroup pluralTableGroup = (PluralTableGroup) fromClauseAccess.findTableGroup(
parentTableGroup.getNavigablePath().getParent() parentTableGroup.getNavigablePath().getParent()
); );
@ -1420,14 +1420,14 @@ public class ToOneAttributeMapping
NavigablePath path = np.getParent(); NavigablePath path = np.getParent();
// Fast path // Fast path
if ( navigablePath.equals( path ) ) { if ( navigablePath.equals( path ) ) {
return targetKeyPropertyNames.contains( np.getUnaliasedLocalName() ) return targetKeyPropertyNames.contains( np.getLocalName() )
&& identifyingColumnsTableExpression.equals( tableExpression ); && identifyingColumnsTableExpression.equals( tableExpression );
} }
final StringBuilder sb = new StringBuilder( np.getFullPath().length() ); final StringBuilder sb = new StringBuilder( np.getFullPath().length() );
sb.append( np.getUnaliasedLocalName() ); sb.append( np.getLocalName() );
while ( path != null && !navigablePath.equals( path ) ) { while ( path != null && !navigablePath.equals( path ) ) {
sb.insert( 0, '.' ); sb.insert( 0, '.' );
sb.insert( 0, path.getUnaliasedLocalName() ); sb.insert( 0, path.getLocalName() );
path = path.getParent(); path = path.getParent();
} }
return navigablePath.equals( path ) return navigablePath.equals( path )
@ -1542,14 +1542,14 @@ public class ToOneAttributeMapping
NavigablePath path = np.getParent(); NavigablePath path = np.getParent();
// Fast path // Fast path
if ( navigablePath.equals( path ) ) { if ( navigablePath.equals( path ) ) {
return targetKeyPropertyNames.contains( np.getUnaliasedLocalName() ) return targetKeyPropertyNames.contains( np.getLocalName() )
&& identifyingColumnsTableExpression.equals( tableExpression ); && identifyingColumnsTableExpression.equals( tableExpression );
} }
final StringBuilder sb = new StringBuilder( np.getFullPath().length() ); final StringBuilder sb = new StringBuilder( np.getFullPath().length() );
sb.append( np.getUnaliasedLocalName() ); sb.append( np.getLocalName() );
while ( path != null && !navigablePath.equals( path ) ) { while ( path != null && !navigablePath.equals( path ) ) {
sb.insert( 0, '.' ); sb.insert( 0, '.' );
sb.insert( 0, path.getUnaliasedLocalName() ); sb.insert( 0, path.getLocalName() );
path = path.getParent(); path = path.getParent();
} }
return navigablePath.equals( path ) return navigablePath.equals( path )

View File

@ -66,7 +66,7 @@ public class FunctionExpression implements OrderingExpression, FunctionRendering
final OrderingExpression orderingExpression = arguments.get( i ); final OrderingExpression orderingExpression = arguments.get( i );
final String subModelPartName; final String subModelPartName;
if ( orderingExpression instanceof DomainPath ) { if ( orderingExpression instanceof DomainPath ) {
final String partName = ( (DomainPath) orderingExpression ).getNavigablePath().getUnaliasedLocalName(); final String partName = ( (DomainPath) orderingExpression ).getNavigablePath().getLocalName();
if ( CollectionPart.Nature.ELEMENT.getName().equals( partName ) ) { if ( CollectionPart.Nature.ELEMENT.getName().equals( partName ) ) {
subModelPartName = AbstractDomainPath.ELEMENT_TOKEN; subModelPartName = AbstractDomainPath.ELEMENT_TOKEN;
} }

View File

@ -4013,7 +4013,7 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
SqmPath<?> lhs = pluralAttributePath.getLhs(); SqmPath<?> lhs = pluralAttributePath.getLhs();
final List<String> implicitJoinPaths = new ArrayList<>(); final List<String> implicitJoinPaths = new ArrayList<>();
while ( !( lhs instanceof AbstractSqmFrom<?, ?> ) ) { while ( !( lhs instanceof AbstractSqmFrom<?, ?> ) ) {
implicitJoinPaths.add( lhs.getNavigablePath().getUnaliasedLocalName() ); implicitJoinPaths.add( lhs.getNavigablePath().getLocalName() );
lhs = lhs.getLhs(); lhs = lhs.getLhs();
} }
final AbstractSqmFrom<?, ?> correlationBase = (AbstractSqmFrom<?, ?>) lhs; final AbstractSqmFrom<?, ?> correlationBase = (AbstractSqmFrom<?, ?>) lhs;
@ -4022,7 +4022,7 @@ public class SemanticQueryBuilder<R> extends HqlParserBaseVisitor<Object> implem
for ( int i = implicitJoinPaths.size() - 1; i >= 0; i-- ) { for ( int i = implicitJoinPaths.size() - 1; i >= 0; i-- ) {
joinBase = joinBase.join( implicitJoinPaths.get( i ) ); joinBase = joinBase.join( implicitJoinPaths.get( i ) );
} }
final SqmAttributeJoin<?, ?> collectionJoin = joinBase.join( pluralAttributePath.getNavigablePath().getUnaliasedLocalName() ); final SqmAttributeJoin<?, ?> collectionJoin = joinBase.join( pluralAttributePath.getNavigablePath().getLocalName() );
fromClause.addRoot( correlation.getCorrelatedRoot() ); fromClause.addRoot( correlation.getCorrelatedRoot() );
if ( collectionReferenceCtx == null ) { if ( collectionReferenceCtx == null ) {
final SqmLiteral<Integer> literal = new SqmLiteral<>( final SqmLiteral<Integer> literal = new SqmLiteral<>(

View File

@ -240,7 +240,7 @@ public class SqmPathRegistryImpl implements SqmPathRegistry {
return (X) existing; return (X) existing;
} }
final SqmFrom<?, ?> sqmFrom = resolveFrom( path.getLhs() ).join( path.getNavigablePath().getUnaliasedLocalName() ); final SqmFrom<?, ?> sqmFrom = resolveFrom( path.getLhs() ).join( path.getNavigablePath().getLocalName() );
register( sqmFrom ); register( sqmFrom );
//noinspection unchecked //noinspection unchecked
return (X) sqmFrom; return (X) sqmFrom;

View File

@ -171,6 +171,6 @@ public class ImplicitFetchBuilderEmbeddable implements ImplicitFetchBuilder {
@Override @Override
public void visitFetchBuilders(BiConsumer<String, FetchBuilder> consumer) { public void visitFetchBuilders(BiConsumer<String, FetchBuilder> consumer) {
fetchBuilders.forEach( (k, v) -> consumer.accept( k.getUnaliasedLocalName(), v ) ); fetchBuilders.forEach( (k, v) -> consumer.accept( k.getLocalName(), v ) );
} }
} }

View File

@ -151,7 +151,7 @@ public class ImplicitFetchBuilderEntity implements ImplicitFetchBuilder {
@Override @Override
public void visitFetchBuilders(BiConsumer<String, FetchBuilder> consumer) { public void visitFetchBuilders(BiConsumer<String, FetchBuilder> consumer) {
fetchBuilders.forEach( (k, v) -> consumer.accept( k.getUnaliasedLocalName(), v ) ); fetchBuilders.forEach( (k, v) -> consumer.accept( k.getLocalName(), v ) );
} }
@Override @Override

View File

@ -2983,7 +2983,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
prepareReusablePath( path, () -> null ); prepareReusablePath( path, () -> null );
final NavigablePath navigablePath; final NavigablePath navigablePath;
if ( CollectionPart.Nature.fromNameExact( path.getNavigablePath().getUnaliasedLocalName() ) != null ) { if ( CollectionPart.Nature.fromNameExact( path.getNavigablePath().getLocalName() ) != null ) {
navigablePath = path.getLhs().getLhs().getNavigablePath(); navigablePath = path.getLhs().getLhs().getNavigablePath();
} }
else if ( path instanceof SqmTreatedRoot<?, ?> ) { else if ( path instanceof SqmTreatedRoot<?, ?> ) {
@ -3648,7 +3648,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
assert parentTableGroup != null; assert parentTableGroup != null;
final PluralAttributeMapping pluralAttributeMapping = (PluralAttributeMapping) parentTableGroup.getModelPart().findSubPart( final PluralAttributeMapping pluralAttributeMapping = (PluralAttributeMapping) parentTableGroup.getModelPart().findSubPart(
pluralPath.getNavigablePath().getUnaliasedLocalName(), pluralPath.getNavigablePath().getLocalName(),
null null
); );
assert pluralAttributeMapping != null; assert pluralAttributeMapping != null;
@ -5344,7 +5344,7 @@ public abstract class BaseSqmToSqlAstConverter<T extends Statement> extends Base
path.getLhs().getNavigablePath() path.getLhs().getNavigablePath()
); );
final NavigablePath navigablePath = parentTableGroup.getNavigablePath().append( final NavigablePath navigablePath = parentTableGroup.getNavigablePath().append(
path.getNavigablePath().getUnaliasedLocalName(), path.getNavigablePath().getLocalName(),
Long.toString( System.nanoTime() ) Long.toString( System.nanoTime() )
); );
final TableGroup tableGroup = new SyntheticVirtualTableGroup( final TableGroup tableGroup = new SyntheticVirtualTableGroup(

View File

@ -103,7 +103,7 @@ public abstract class AbstractSqmPath<T> extends AbstractSqmExpression<T> implem
reusablePaths = new HashMap<>(); reusablePaths = new HashMap<>();
} }
final String relativeName = path.getNavigablePath().getUnaliasedLocalName(); final String relativeName = path.getNavigablePath().getLocalName();
final SqmPath<?> previous = reusablePaths.put( relativeName, path ); final SqmPath<?> previous = reusablePaths.put( relativeName, path );
if ( previous != null && previous != path ) { if ( previous != null && previous != path ) {

View File

@ -108,7 +108,7 @@ public class SqmPluralValuedSimplePath<E> extends AbstractSqmSimplePath<E> {
final SqmPathRegistry pathRegistry = creationState.getCurrentProcessingState().getPathRegistry(); final SqmPathRegistry pathRegistry = creationState.getCurrentProcessingState().getPathRegistry();
final String alias = selector.toHqlString(); final String alias = selector.toHqlString();
final NavigablePath navigablePath = getNavigablePath().getParent().append( final NavigablePath navigablePath = getNavigablePath().getParent().append(
getNavigablePath().getUnaliasedLocalName(), getNavigablePath().getLocalName(),
alias alias
).append( CollectionPart.Nature.ELEMENT.getName() ); ).append( CollectionPart.Nature.ELEMENT.getName() );
final SqmFrom<?, ?> indexedPath = pathRegistry.findFromByPath( navigablePath ); final SqmFrom<?, ?> indexedPath = pathRegistry.findFromByPath( navigablePath );

View File

@ -77,7 +77,7 @@ public class SqmAliasedNodeRef extends AbstractSqmExpression<Integer> {
sb.append( position ); sb.append( position );
} }
else { else {
sb.append( navigablePath.getUnaliasedLocalName() ); sb.append( navigablePath.getLocalName() );
} }
} }
} }

View File

@ -23,23 +23,28 @@ public class NavigablePath implements DotIdentifierSequence, Serializable {
public static final String IDENTIFIER_MAPPER_PROPERTY = "_identifierMapper"; public static final String IDENTIFIER_MAPPER_PROPERTY = "_identifierMapper";
private final NavigablePath parent; private final NavigablePath parent;
private final String fullPath; private final String localName;
private final String unaliasedLocalName; private final String alias;
private final String identifierForTableGroup; private final String identifierForTableGroup;
private final String fullPath;
public NavigablePath(NavigablePath parent, String navigableName) { public NavigablePath(NavigablePath parent, String navigableName) {
this.parent = parent; this.parent = parent;
this.alias = null;
// the _identifierMapper is a "hidden property" on entities with composite keys. // the _identifierMapper is a "hidden property" on entities with composite keys.
// concatenating it will prevent the path from correctly being used to look up // concatenating it will prevent the path from correctly being used to look up
// various things such as criteria paths and fetch profile association paths // various things such as criteria paths and fetch profile association paths
if ( IDENTIFIER_MAPPER_PROPERTY.equals( navigableName ) ) { if ( IDENTIFIER_MAPPER_PROPERTY.equals( navigableName ) ) {
this.fullPath = parent != null ? parent.getFullPath() : ""; this.localName = "";
this.unaliasedLocalName = "";
this.identifierForTableGroup = parent != null ? parent.getIdentifierForTableGroup() : ""; this.identifierForTableGroup = parent != null ? parent.getIdentifierForTableGroup() : "";
this.fullPath = parent != null ? parent.getFullPath() : "";
} }
else { else {
this.unaliasedLocalName = navigableName; this.localName = navigableName;
if ( parent != null ) { if ( parent != null ) {
final String parentFullPath = parent.getFullPath(); final String parentFullPath = parent.getFullPath();
this.fullPath = StringHelper.isEmpty( parentFullPath ) this.fullPath = StringHelper.isEmpty( parentFullPath )
@ -51,7 +56,7 @@ public class NavigablePath implements DotIdentifierSequence, Serializable {
} }
else { else {
this.fullPath = navigableName; this.fullPath = navigableName;
identifierForTableGroup = navigableName; this.identifierForTableGroup = navigableName;
} }
} }
} }
@ -62,28 +67,32 @@ public class NavigablePath implements DotIdentifierSequence, Serializable {
public NavigablePath(String rootName, String alias) { public NavigablePath(String rootName, String alias) {
this.parent = null; this.parent = null;
this.alias = StringHelper.nullIfEmpty( alias );
this.localName = rootName;
this.identifierForTableGroup = rootName;
this.fullPath = alias == null ? rootName : rootName + "(" + alias + ")"; this.fullPath = alias == null ? rootName : rootName + "(" + alias + ")";
this.unaliasedLocalName = StringHelper.unqualify( rootName );
identifierForTableGroup = rootName;
} }
public NavigablePath(NavigablePath parent, String property, String alias) { public NavigablePath(NavigablePath parent, String property, String alias) {
String navigableName = alias == null alias = StringHelper.nullIfEmpty( alias );
final String navigableName = alias == null
? property ? property
: property + '(' + alias + ')'; : property + '(' + alias + ')';
this.parent = parent; this.parent = parent;
this.alias = alias;
// the _identifierMapper is a "hidden property" on entities with composite keys. // the _identifierMapper is a "hidden property" on entities with composite keys.
// concatenating it will prevent the path from correctly being used to look up // concatenating it will prevent the path from correctly being used to look up
// various things such as criteria paths and fetch profile association paths // various things such as criteria paths and fetch profile association paths
if ( IDENTIFIER_MAPPER_PROPERTY.equals( navigableName ) ) { if ( IDENTIFIER_MAPPER_PROPERTY.equals( navigableName ) ) {
this.fullPath = parent != null ? parent.getFullPath() : ""; this.fullPath = parent != null ? parent.getFullPath() : "";
this.unaliasedLocalName = ""; this.localName = "";
identifierForTableGroup = parent != null ? parent.getFullPath() : ""; identifierForTableGroup = parent != null ? parent.getFullPath() : "";
} }
else { else {
this.unaliasedLocalName = property; this.localName = property;
if ( parent != null ) { if ( parent != null ) {
final String parentFullPath = parent.getFullPath(); final String parentFullPath = parent.getFullPath();
this.fullPath = StringHelper.isEmpty( parentFullPath ) this.fullPath = StringHelper.isEmpty( parentFullPath )
@ -107,11 +116,12 @@ public class NavigablePath implements DotIdentifierSequence, Serializable {
public NavigablePath( public NavigablePath(
NavigablePath parent, NavigablePath parent,
String fullPath, String fullPath,
String unaliasedLocalName, String localName,
String identifierForTableGroup) { String identifierForTableGroup) {
this.parent = parent; this.parent = parent;
this.alias = null;
this.fullPath = fullPath; this.fullPath = fullPath;
this.unaliasedLocalName = unaliasedLocalName; this.localName = localName;
this.identifierForTableGroup = identifierForTableGroup; this.identifierForTableGroup = identifierForTableGroup;
} }
@ -140,24 +150,29 @@ public class NavigablePath implements DotIdentifierSequence, Serializable {
} }
public String getLocalName() { public String getLocalName() {
return parent == null ? fullPath : StringHelper.unqualify( fullPath ); return localName;
} }
public String getUnaliasedLocalName() { public String getAlias() {
return unaliasedLocalName; return alias;
} }
public String getFullPath() { public boolean isAliased() {
return fullPath; return alias != null;
} }
public String getIdentifierForTableGroup() { public String getIdentifierForTableGroup() {
// todo (6.0) : is this `if` really needed? seems this is already handled in constructors
if ( parent == null ) { if ( parent == null ) {
return fullPath; return fullPath;
} }
return identifierForTableGroup; return identifierForTableGroup;
} }
public String getFullPath() {
return fullPath;
}
public boolean isParent(NavigablePath navigablePath) { public boolean isParent(NavigablePath navigablePath) {
while ( navigablePath != null ) { while ( navigablePath != null ) {
if ( this.equals( navigablePath.getParent() ) ) { if ( this.equals( navigablePath.getParent() ) ) {

View File

@ -41,11 +41,6 @@ public class TreatedNavigablePath extends NavigablePath {
return new TreatedNavigablePath( getRealParent(), entityName, alias ); return new TreatedNavigablePath( getRealParent(), entityName, alias );
} }
@Override
public String getLocalName() {
return getUnaliasedLocalName();
}
@Override @Override
public int hashCode() { public int hashCode() {
return getFullPath().hashCode(); return getFullPath().hashCode();

View File

@ -108,9 +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.getUnaliasedLocalName() ) createEmptyCompositesEnabled = !ForeignKeyDescriptor.PART_NAME.equals( navigablePath.getLocalName() )
&& !ForeignKeyDescriptor.TARGET_PART_NAME.equals( navigablePath.getUnaliasedLocalName() ) && !ForeignKeyDescriptor.TARGET_PART_NAME.equals( navigablePath.getLocalName() )
&& !EntityIdentifierMapping.ROLE_LOCAL_NAME.equals( navigablePath.getUnaliasedLocalName() ) && !EntityIdentifierMapping.ROLE_LOCAL_NAME.equals( navigablePath.getLocalName() )
&& embeddableTypeDescriptor.isCreateEmptyCompositesEnabled(); && embeddableTypeDescriptor.isCreateEmptyCompositesEnabled();
sessionFactory = creationState.getSqlAstCreationContext().getSessionFactory(); sessionFactory = creationState.getSqlAstCreationContext().getSessionFactory();
@ -232,8 +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.getLocalName() )
&& !ForeignKeyDescriptor.TARGET_PART_NAME.equals( navigablePath.getUnaliasedLocalName() ) ) { && !ForeignKeyDescriptor.TARGET_PART_NAME.equals( navigablePath.getLocalName() ) ) {
fetchParentAccess.resolveInstance( processingState ); fetchParentAccess.resolveInstance( processingState );
compositeInstance = fetchParentAccess.getInitializedInstance(); compositeInstance = fetchParentAccess.getInitializedInstance();
} }
@ -255,8 +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.getUnaliasedLocalName() ) final boolean isKey = ForeignKeyDescriptor.PART_NAME.equals( navigablePath.getLocalName() )
|| ForeignKeyDescriptor.TARGET_PART_NAME.equals( navigablePath.getUnaliasedLocalName() ) || ForeignKeyDescriptor.TARGET_PART_NAME.equals( navigablePath.getLocalName() )
|| 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 );

View File

@ -112,7 +112,7 @@ public class EmbeddableFetchImpl extends AbstractFetchParent implements Embeddab
for ( TableGroupJoin tableGroupJoin : tableGroup.getTableGroupJoins() ) { for ( TableGroupJoin tableGroupJoin : tableGroup.getTableGroupJoins() ) {
final NavigablePath navigablePath = tableGroupJoin.getNavigablePath(); final NavigablePath navigablePath = tableGroupJoin.getNavigablePath();
if ( tableGroupJoin.getJoinedGroup().isFetched() if ( tableGroupJoin.getJoinedGroup().isFetched()
&& fetchable.getFetchableName().equals( navigablePath.getUnaliasedLocalName() ) && fetchable.getFetchableName().equals( navigablePath.getLocalName() )
&& tableGroupJoin.getJoinedGroup().getModelPart() == fetchable ) { && tableGroupJoin.getJoinedGroup().getModelPart() == fetchable ) {
return navigablePath; return navigablePath;
} }

View File

@ -56,12 +56,11 @@ public class EntityResultImpl extends AbstractEntityResultGraphNode implements E
@Override @Override
public NavigablePath resolveNavigablePath(Fetchable fetchable) { public NavigablePath resolveNavigablePath(Fetchable fetchable) {
if ( fetchable instanceof TableGroupProducer && if ( fetchable instanceof TableGroupProducer && getNavigablePath().isAliased() ) {
!getNavigablePath().getUnaliasedLocalName().equals( getNavigablePath().getLocalName() ) ) {
for ( TableGroupJoin tableGroupJoin : tableGroup.getTableGroupJoins() ) { for ( TableGroupJoin tableGroupJoin : tableGroup.getTableGroupJoins() ) {
final NavigablePath navigablePath = tableGroupJoin.getNavigablePath(); final NavigablePath navigablePath = tableGroupJoin.getNavigablePath();
if ( tableGroupJoin.getJoinedGroup().isFetched() if ( tableGroupJoin.getJoinedGroup().isFetched()
&& fetchable.getFetchableName().equals( navigablePath.getUnaliasedLocalName() ) && fetchable.getFetchableName().equals( navigablePath.getLocalName() )
&& tableGroupJoin.getJoinedGroup().getModelPart() == fetchable ) { && tableGroupJoin.getJoinedGroup().getModelPart() == fetchable ) {
return navigablePath; return navigablePath;
} }

View File

@ -88,8 +88,8 @@ public class EntitySelectFetchInitializer extends AbstractFetchParentAccess impl
NavigablePath np = navigablePath.getParent(); NavigablePath np = navigablePath.getParent();
while ( np != null ) { while ( np != null ) {
if ( np instanceof EntityIdentifierNavigablePath if ( np instanceof EntityIdentifierNavigablePath
|| ForeignKeyDescriptor.PART_NAME.equals( np.getUnaliasedLocalName() ) || ForeignKeyDescriptor.PART_NAME.equals( np.getLocalName() )
|| ForeignKeyDescriptor.TARGET_PART_NAME.equals( np.getUnaliasedLocalName() )) { || ForeignKeyDescriptor.TARGET_PART_NAME.equals( np.getLocalName() )) {
initializeInstance( rowProcessingState ); initializeInstance( rowProcessingState );
return; return;
} }

View File

@ -0,0 +1,114 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.orm.test.spi.path;
import org.hibernate.metamodel.mapping.EntityIdentifierMapping;
import org.hibernate.spi.EntityIdentifierNavigablePath;
import org.hibernate.spi.NavigablePath;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.Assertions.assertThat;
/**
* @author Steve Ebersole
*/
public class NavigablePathTests {
@Test
public void testRoots() {
final NavigablePath root = new NavigablePath( "org.hibernate.Root", "r" );
assertThat( root.equals( root ) ).isTrue();
assertThat( root.getFullPath() ).isEqualTo( "org.hibernate.Root(r)" );
assertThat( root.getLocalName() ).isEqualTo( "org.hibernate.Root" );
assertThat( root.isAliased() ).isTrue();
assertThat( root.getAlias() ).isEqualTo( "r" );
final NavigablePath root2 = new NavigablePath( "org.hibernate.Root", "r" );
assertThat( root.equals( root2 ) ).isTrue();
}
@Test
public void testSubPaths() {
final NavigablePath root = new NavigablePath( "org.hibernate.Root", "r" );
final NavigablePath name1 = root.append( "name" );
final NavigablePath name2 = root.append( "name" );
assertThat( name1.equals( name2 ) ).isTrue();
final NavigablePath id = root.append( "id" );
assertThat( name1.equals( root ) ).isFalse();
assertThat( id.equals( root ) ).isFalse();
}
@Test
public void testParallelSubPaths() {
final NavigablePath root1 = new NavigablePath( "org.hibernate.Root", "r" );
final NavigablePath root2 = new NavigablePath( "org.hibernate.Root", "r" );
final NavigablePath name1 = root1.append( "name" );
final NavigablePath name2 = root2.append( "name" );
assertThat( name1.equals( name2 ) ).isTrue();
}
@Test
public void testNestedPaths() {
final NavigablePath root = new NavigablePath( "org.hibernate.Root", "r" );
final NavigablePath comp1 = root.append( "comp" );
final NavigablePath comp2 = root.append( "comp" );
final NavigablePath comp1Name = comp1.append( "name" );
final NavigablePath comp2Name = comp2.append( "name" );
assertThat( comp1Name.equals( comp2Name ) ).isTrue();
}
@Test
public void testDivergentNestedPaths() {
final NavigablePath root = new NavigablePath( "org.hibernate.Root", "r" );
final NavigablePath comp = root.append( "comp" );
final NavigablePath other = root.append( "other" );
final NavigablePath compName = comp.append( "name" );
final NavigablePath otherName = other.append( "name" );
assertThat( compName.equals( otherName ) ).isFalse();
}
@Test
public void testStringification() {
final String rootStr = "org.hibernate.Root";
final String aliasedRootStr = "org.hibernate.Root(r)";
final String nameStr = "name";
final String namePathStr = aliasedRootStr + "." + nameStr;
final NavigablePath root = new NavigablePath( rootStr, "r" );
final NavigablePath name = root.append( "name" );
assertThat( name.getLocalName() ).isEqualTo( nameStr );
assertThat( name.getFullPath() ).isEqualTo( namePathStr );
}
@Test
public void testIdentifierPaths() {
final String rootStr = "org.hibernate.Root";
final String aliasedRootStr = "org.hibernate.Root(r)";
final String pkStr = "pk";
final String pkFullPathStr = aliasedRootStr + "." + EntityIdentifierMapping.ROLE_LOCAL_NAME;
final NavigablePath root = new NavigablePath( rootStr, "r" );
final NavigablePath idPath = new EntityIdentifierNavigablePath( root, pkStr );
assertThat( idPath.getLocalName() ).isEqualTo( EntityIdentifierMapping.ROLE_LOCAL_NAME );
assertThat( idPath.getFullPath() ).isEqualTo( pkFullPathStr );
}
}