Fix resolving id columns for NativeQuery with inplicit joins and aliases
This commit is contained in:
parent
9bd5360bf2
commit
7fa5d45175
|
@ -6,6 +6,7 @@
|
|||
*/
|
||||
package org.hibernate.query.results;
|
||||
|
||||
import java.util.AbstractMap;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
@ -21,12 +22,15 @@ import org.hibernate.internal.util.collections.Stack;
|
|||
import org.hibernate.internal.util.collections.StandardStack;
|
||||
import org.hibernate.metamodel.mapping.Association;
|
||||
import org.hibernate.metamodel.mapping.AssociationKey;
|
||||
import org.hibernate.metamodel.mapping.AttributeMapping;
|
||||
import org.hibernate.metamodel.mapping.CompositeIdentifierMapping;
|
||||
import org.hibernate.metamodel.mapping.EntityIdentifierMapping;
|
||||
import org.hibernate.metamodel.mapping.EntityValuedModelPart;
|
||||
import org.hibernate.metamodel.mapping.ForeignKeyDescriptor;
|
||||
import org.hibernate.metamodel.mapping.EmbeddableMappingType;
|
||||
import org.hibernate.metamodel.mapping.ModelPart;
|
||||
import org.hibernate.metamodel.mapping.internal.BasicValuedCollectionPart;
|
||||
import org.hibernate.metamodel.mapping.internal.NonAggregatedIdentifierMappingImpl;
|
||||
import org.hibernate.metamodel.mapping.internal.SingleAttributeIdentifierMapping;
|
||||
import org.hibernate.query.EntityIdentifierNavigablePath;
|
||||
import org.hibernate.query.NavigablePath;
|
||||
import org.hibernate.query.results.dynamic.DynamicFetchBuilderLegacy;
|
||||
|
@ -74,7 +78,7 @@ public class DomainResultCreationStateImpl
|
|||
private final SessionFactoryImplementor sessionFactory;
|
||||
|
||||
private final Stack<Function<String, FetchBuilder>> fetchBuilderResolverStack = new StandardStack<>( fetchableName -> null );
|
||||
private final Stack<NavigablePath> relativePathStack = new StandardStack<>();
|
||||
private final Stack<Map.Entry<String, NavigablePath>> relativePathStack = new StandardStack<>();
|
||||
private Map<String, LockMode> registeredLockModes;
|
||||
private boolean processingKeyFetches = false;
|
||||
private boolean resolvingCircularFetch;
|
||||
|
@ -123,7 +127,8 @@ public class DomainResultCreationStateImpl
|
|||
}
|
||||
|
||||
public NavigablePath getCurrentRelativePath() {
|
||||
return relativePathStack.getCurrent();
|
||||
final Map.Entry<String, NavigablePath> entry = relativePathStack.getCurrent();
|
||||
return entry == null ? null : entry.getValue();
|
||||
}
|
||||
|
||||
public void pushExplicitFetchMementoResolver(Function<String, FetchBuilder> resolver) {
|
||||
|
@ -326,33 +331,47 @@ public class DomainResultCreationStateImpl
|
|||
|
||||
final Consumer<Fetchable> fetchableConsumer = fetchable -> {
|
||||
final String fetchableName = fetchable.getFetchableName();
|
||||
final NavigablePath fetchPath = fetchParent.resolveNavigablePath( fetchable );
|
||||
final NavigablePath relativePath = relativePathStack.isEmpty()
|
||||
? new NavigablePath( fetchableName )
|
||||
: relativePathStack.getCurrent().append( fetchableName );
|
||||
Map.Entry<String, NavigablePath> currentEntry;
|
||||
if ( relativePathStack.isEmpty() ) {
|
||||
currentEntry = new AbstractMap.SimpleEntry<>(
|
||||
getRelativePath( "", fetchable, fetchableContainer ),
|
||||
new NavigablePath( fetchableName )
|
||||
);
|
||||
}
|
||||
else {
|
||||
final Map.Entry<String, NavigablePath> oldEntry = relativePathStack.getCurrent();
|
||||
final String key = oldEntry.getKey();
|
||||
currentEntry = new AbstractMap.SimpleEntry<>(
|
||||
getRelativePath( !key.isEmpty() ? key : "", fetchable, fetchableContainer ),
|
||||
oldEntry.getValue().append( fetchableName )
|
||||
);
|
||||
}
|
||||
// todo (6.0): figure out if we can somehow create the navigable paths in a better way
|
||||
final String fullPath = currentEntry.getKey();
|
||||
FetchBuilder explicitFetchBuilder = fetchBuilderResolverStack
|
||||
.getCurrent()
|
||||
.apply( fullPath );
|
||||
if ( fetchable instanceof Association && fetchable.getMappedFetchOptions().getTiming() == FetchTiming.DELAYED ) {
|
||||
final Association association = (Association) fetchable;
|
||||
final ForeignKeyDescriptor foreignKeyDescriptor = association.getForeignKeyDescriptor();
|
||||
if ( foreignKeyDescriptor.getPartMappingType() instanceof EmbeddableMappingType ) {
|
||||
relativePathStack.push( relativePath.append( ( (EmbeddableMappingType) foreignKeyDescriptor.getPartMappingType() ).getPartName() ) );
|
||||
}
|
||||
else {
|
||||
relativePathStack.push( relativePath.append( foreignKeyDescriptor.getPartName() ) );
|
||||
}
|
||||
}
|
||||
else {
|
||||
relativePathStack.push( relativePath );
|
||||
}
|
||||
try {
|
||||
String fullPath = relativePath.getFullPath();
|
||||
if ( fullPath.contains( EntityIdentifierMapping.ROLE_LOCAL_NAME ) ) {
|
||||
fullPath = fullPath.replace( EntityIdentifierMapping.ROLE_LOCAL_NAME + ".", "" );
|
||||
}
|
||||
FetchBuilder explicitFetchBuilder = fetchBuilderResolverStack
|
||||
.getCurrent()
|
||||
.apply( fullPath );
|
||||
|
||||
final String partName = attributeName( foreignKeyDescriptor.getSide( association.getSideNature().inverse() )
|
||||
.getModelPart());
|
||||
|
||||
if ( explicitFetchBuilder == null && partName != null ) {
|
||||
currentEntry = new AbstractMap.SimpleEntry<>(
|
||||
currentEntry.getKey() + "." + partName,
|
||||
currentEntry.getValue().append( partName )
|
||||
);
|
||||
explicitFetchBuilder = fetchBuilderResolverStack
|
||||
.getCurrent()
|
||||
.apply( currentEntry.getKey() );
|
||||
}
|
||||
}
|
||||
relativePathStack.push( currentEntry );
|
||||
try {
|
||||
|
||||
final NavigablePath fetchPath = fetchParent.resolveNavigablePath( fetchable );
|
||||
final FetchBuilder fetchBuilder;
|
||||
if ( explicitFetchBuilder != null ) {
|
||||
fetchBuilder = explicitFetchBuilder;
|
||||
|
@ -385,6 +404,7 @@ public class DomainResultCreationStateImpl
|
|||
finally {
|
||||
relativePathStack.pop();
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
boolean previous = this.processingKeyFetches;
|
||||
|
@ -394,11 +414,30 @@ public class DomainResultCreationStateImpl
|
|||
final EntityValuedModelPart entityValuedFetchable = (EntityValuedModelPart) fetchableContainer;
|
||||
final EntityIdentifierMapping identifierMapping = entityValuedFetchable.getEntityMappingType().getIdentifierMapping();
|
||||
final boolean idClass = identifierMapping instanceof NonAggregatedIdentifierMappingImpl;
|
||||
final String identifierAttributeName = attributeName( identifierMapping );
|
||||
if ( idClass ) {
|
||||
final Map.Entry<String, NavigablePath> oldEntry = relativePathStack.getCurrent();
|
||||
relativePathStack.push(
|
||||
new EntityIdentifierNavigablePath(
|
||||
relativePathStack.getCurrent(),
|
||||
attributeName( identifierMapping )
|
||||
new AbstractMap.SimpleEntry<>(
|
||||
oldEntry == null ? "" : oldEntry.getKey(),
|
||||
new EntityIdentifierNavigablePath(
|
||||
oldEntry == null ? fetchParent.getNavigablePath() : oldEntry.getValue(),
|
||||
identifierAttributeName
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
else if ( identifierMapping instanceof CompositeIdentifierMapping ) {
|
||||
final Map.Entry<String, NavigablePath> oldEntry = relativePathStack.getCurrent();
|
||||
relativePathStack.push(
|
||||
new AbstractMap.SimpleEntry<>(
|
||||
oldEntry == null ?
|
||||
identifierAttributeName :
|
||||
oldEntry.getKey() + "." + identifierAttributeName,
|
||||
new EntityIdentifierNavigablePath(
|
||||
oldEntry == null ? fetchParent.getNavigablePath() : oldEntry.getValue(),
|
||||
identifierAttributeName
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
@ -425,6 +464,16 @@ public class DomainResultCreationStateImpl
|
|||
return fetches;
|
||||
}
|
||||
|
||||
private String getRelativePath(String oldEntry, Fetchable fetchable, FetchableContainer fetchableContainer) {
|
||||
if ( fetchable instanceof AttributeMapping || fetchable instanceof SingleAttributeIdentifierMapping || fetchable instanceof BasicValuedCollectionPart ) {
|
||||
if ( !oldEntry.equals( "" ) ) {
|
||||
return oldEntry + '.' + fetchable.getFetchableName();
|
||||
}
|
||||
return fetchable.getFetchableName();
|
||||
}
|
||||
return oldEntry;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isResolvingCircularFetch() {
|
||||
return resolvingCircularFetch;
|
||||
|
|
|
@ -13,6 +13,7 @@ import org.hibernate.metamodel.mapping.BasicValuedModelPart;
|
|||
import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart;
|
||||
import org.hibernate.metamodel.mapping.EntityIdentifierMapping;
|
||||
import org.hibernate.metamodel.mapping.EntityMappingType;
|
||||
import org.hibernate.metamodel.mapping.ModelPart;
|
||||
import org.hibernate.metamodel.mapping.internal.SingleAttributeIdentifierMapping;
|
||||
import org.hibernate.query.EntityIdentifierNavigablePath;
|
||||
import org.hibernate.query.NavigablePath;
|
||||
|
@ -106,10 +107,16 @@ public class ResultsHelper {
|
|||
);
|
||||
}
|
||||
|
||||
public static String attributeName(EntityIdentifierMapping identifierMapping) {
|
||||
return identifierMapping instanceof SingleAttributeIdentifierMapping
|
||||
? ( (SingleAttributeIdentifierMapping) identifierMapping ).getAttributeName()
|
||||
: null;
|
||||
public static String attributeName(ModelPart identifierMapping) {
|
||||
if ( identifierMapping instanceof EntityIdentifierMapping ) {
|
||||
return identifierMapping instanceof SingleAttributeIdentifierMapping
|
||||
? ( (SingleAttributeIdentifierMapping) identifierMapping ).getAttributeName()
|
||||
: null;
|
||||
}
|
||||
else {
|
||||
return identifierMapping.getPartName();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static DomainResult convertIdFetchToResult(Fetch fetch, DomainResultCreationState creationState) {
|
||||
|
|
|
@ -9,7 +9,6 @@ package org.hibernate.orm.test.interceptor;
|
|||
import jakarta.persistence.PersistenceException;
|
||||
import jakarta.persistence.criteria.CriteriaBuilder;
|
||||
import jakarta.persistence.criteria.CriteriaQuery;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
@ -24,7 +23,6 @@ import org.hibernate.Interceptor;
|
|||
import org.hibernate.Session;
|
||||
import org.hibernate.Transaction;
|
||||
import org.hibernate.TransactionException;
|
||||
|
||||
import org.hibernate.testing.TestForIssue;
|
||||
import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase;
|
||||
|
||||
|
|
Loading…
Reference in New Issue