use of org.hibernate.query.sqm.spi.EntityIdentifierNavigablePath in project hibernate-orm by hibernate.
the class ToOneAttributeMapping method resolveCircularFetch.
@Override
public Fetch resolveCircularFetch(NavigablePath fetchablePath, FetchParent fetchParent, FetchTiming fetchTiming, DomainResultCreationState creationState) {
final AssociationKey associationKey = foreignKeyDescriptor.getAssociationKey();
if (creationState.isAssociationKeyVisited(associationKey) || bidirectionalAttributeName != null && !creationState.isRegisteringVisitedAssociationKeys()) {
NavigablePath parentNavigablePath = fetchablePath.getParent();
assert parentNavigablePath.equals(fetchParent.getNavigablePath());
/*
@Entity
public class Card {
@Id
private String id;
@ManyToOne
private CardField field;
}
@Entity
public class CardField {
@EmbeddedId
private PrimaryKey primaryKey;
}
@Embeddable
public class PrimaryKey {
@ManyToOne(optional = false)
private Card card;
@ManyToOne(optional = false)
private Key key;
}
*/
if (parentNavigablePath.getLocalName().equals(ForeignKeyDescriptor.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;
}
ModelPart parentModelPart = creationState.resolveModelPart(parentNavigablePath);
if (parentModelPart instanceof EmbeddedIdentifierMappingImpl) {
while (parentNavigablePath instanceof EntityIdentifierNavigablePath) {
parentNavigablePath = parentNavigablePath.getParent();
assert parentNavigablePath != null;
parentModelPart = creationState.resolveModelPart(parentNavigablePath);
}
}
while (parentModelPart instanceof EmbeddableValuedFetchable) {
parentNavigablePath = parentNavigablePath.getParent();
assert parentNavigablePath != null;
parentModelPart = creationState.resolveModelPart(parentNavigablePath);
}
if (isBidirectionalAttributeName(parentNavigablePath, parentModelPart, fetchablePath, creationState)) {
return createCircularBiDirectionalFetch(fetchablePath, fetchParent, parentNavigablePath, creationState);
}
/*
class Child {
@OneToOne
private Mother mother;
}
class Mother {
@OneToOne
private Child stepMother;
}
We have a circularity but it is not bidirectional
*/
final TableGroup parentTableGroup = creationState.getSqlAstCreationState().getFromClauseAccess().getTableGroup(fetchParent.getNavigablePath());
final DomainResult<?> foreignKeyDomainResult;
assert !creationState.isResolvingCircularFetch();
try {
creationState.setResolvingCircularFetch(true);
foreignKeyDomainResult = foreignKeyDescriptor.createDomainResult(fetchablePath, parentTableGroup, sideNature, creationState);
} finally {
creationState.setResolvingCircularFetch(false);
}
return new CircularFetchImpl(this, getEntityMappingType(), fetchTiming, fetchablePath, fetchParent, this, isSelectByUniqueKey(sideNature), fetchablePath, foreignKeyDomainResult);
}
return null;
}
use of org.hibernate.query.sqm.spi.EntityIdentifierNavigablePath in project hibernate-orm by hibernate.
the class FetchParent method resolveNavigablePath.
default NavigablePath resolveNavigablePath(Fetchable fetchable) {
final String fetchableName = fetchable.getFetchableName();
if (NavigablePath.IDENTIFIER_MAPPER_PROPERTY.equals(fetchableName)) {
return new EntityIdentifierNavigablePath(getNavigablePath(), fetchableName);
} else {
final FetchableContainer referencedMappingContainer = getReferencedMappingContainer();
final EntityMappingType fetchableEntityType = fetchable.findContainingEntityMapping();
final EntityMappingType fetchParentType;
if (referencedMappingContainer instanceof EmbeddableMappingType || referencedMappingContainer instanceof EmbeddableValuedModelPart) {
fetchParentType = referencedMappingContainer.findContainingEntityMapping();
} else if (referencedMappingContainer instanceof EntityMappingType) {
fetchParentType = (EntityMappingType) referencedMappingContainer;
} else {
fetchParentType = fetchableEntityType;
}
if (fetchParentType != fetchableEntityType) {
// todo (6.0): if the fetchParentType is a subtype of fetchableEntityType this shouldn't be necessary
return getNavigablePath().treatAs(fetchableEntityType.getEntityName()).append(fetchableName);
}
return getNavigablePath().append(fetchableName);
}
}
use of org.hibernate.query.sqm.spi.EntityIdentifierNavigablePath in project hibernate-orm by hibernate.
the class LoaderSelectBuilder method createFetchableBiConsumer.
private BiConsumer<Fetchable, Boolean> createFetchableBiConsumer(FetchParent fetchParent, QuerySpec querySpec, LoaderSqlAstCreationState creationState, List<Fetch> fetches) {
return (fetchable, isKeyFetchable) -> {
final NavigablePath fetchablePath;
if (isKeyFetchable) {
final EntityIdentifierMapping identifierMapping;
if (fetchParent instanceof BiDirectionalFetch) {
final BiDirectionalFetch parentAsBiDirectionalFetch = (BiDirectionalFetch) fetchParent;
final Fetchable biDirectionalFetchedMapping = parentAsBiDirectionalFetch.getFetchedMapping();
if (biDirectionalFetchedMapping instanceof EntityValuedFetchable) {
identifierMapping = ((EntityValuedFetchable) biDirectionalFetchedMapping).getEntityMappingType().getIdentifierMapping();
} else {
identifierMapping = null;
}
} else {
final FetchableContainer fetchableContainer = fetchParent.getReferencedMappingContainer();
if (fetchableContainer instanceof EntityValuedModelPart) {
final EntityValuedModelPart entityValuedModelPart = (EntityValuedModelPart) fetchableContainer;
identifierMapping = entityValuedModelPart.getEntityMappingType().getIdentifierMapping();
} else {
identifierMapping = null;
}
}
if (identifierMapping != null) {
fetchablePath = new EntityIdentifierNavigablePath(fetchParent.getNavigablePath(), attributeName(identifierMapping));
} else {
fetchablePath = fetchParent.resolveNavigablePath(fetchable);
}
} else {
fetchablePath = fetchParent.resolveNavigablePath(fetchable);
}
FetchTiming fetchTiming = fetchable.getMappedFetchOptions().getTiming();
boolean joined = fetchable.getMappedFetchOptions().getStyle() == FetchStyle.JOIN;
boolean explicitFetch = false;
EntityGraphTraversalState.TraversalResult traversalResult = null;
final boolean isFetchablePluralAttributeMapping = fetchable instanceof PluralAttributeMapping;
if (!(fetchable instanceof CollectionPart)) {
// 'entity graph' takes precedence over 'fetch profile'
if (entityGraphTraversalState != null) {
traversalResult = entityGraphTraversalState.traverse(fetchParent, fetchable, isKeyFetchable);
fetchTiming = traversalResult.getFetchTiming();
joined = traversalResult.isJoined();
explicitFetch = true;
} else if (loadQueryInfluencers.hasEnabledFetchProfiles()) {
// There is no point in checking the fetch profile if it can't affect this fetchable
if (fetchTiming != FetchTiming.IMMEDIATE || fetchable.incrementFetchDepth()) {
final String fetchableRole = fetchable.getNavigableRole().getFullPath();
for (String enabledFetchProfileName : loadQueryInfluencers.getEnabledFetchProfileNames()) {
final FetchProfile enabledFetchProfile = creationContext.getSessionFactory().getFetchProfile(enabledFetchProfileName);
final org.hibernate.engine.profile.Fetch profileFetch = enabledFetchProfile.getFetchByRole(fetchableRole);
if (profileFetch != null) {
fetchTiming = FetchTiming.IMMEDIATE;
joined = joined || profileFetch.getStyle() == org.hibernate.engine.profile.Fetch.Style.JOIN;
explicitFetch = true;
}
}
}
} else if (loadQueryInfluencers.getEnabledCascadingFetchProfile() != null) {
final CascadeStyle cascadeStyle = ((AttributeMapping) fetchable).getAttributeMetadataAccess().resolveAttributeMetadata(fetchable.findContainingEntityMapping()).getCascadeStyle();
final CascadingAction cascadingAction = loadQueryInfluencers.getEnabledCascadingFetchProfile().getCascadingAction();
if (cascadeStyle == null || cascadeStyle.doCascade(cascadingAction)) {
fetchTiming = FetchTiming.IMMEDIATE;
// In 5.x the CascadeEntityJoinWalker only join fetched the first collection fetch
if (isFetchablePluralAttributeMapping) {
joined = !hasCollectionJoinFetches;
} else {
joined = true;
}
}
}
}
final String previousBagRole = currentBagRole;
final String bagRole;
if (isFetchablePluralAttributeMapping && ((PluralAttributeMapping) fetchable).getMappedType().getCollectionSemantics() instanceof BagSemantics) {
bagRole = fetchable.getNavigableRole().getNavigableName();
} else {
bagRole = null;
}
if (joined && previousBagRole != null && bagRole != null) {
// Avoid join fetching multiple bags
joined = false;
}
boolean changeFetchDepth = !(fetchable instanceof BasicValuedModelPart) && !(fetchable instanceof EmbeddedAttributeMapping) && !(fetchable instanceof CollectionPart);
try {
if (changeFetchDepth) {
fetchDepth++;
}
// There is no need to check for circular fetches if this is an explicit fetch
if (!explicitFetch && !creationState.isResolvingCircularFetch()) {
final Fetch biDirectionalFetch = fetchable.resolveCircularFetch(fetchablePath, fetchParent, fetchTiming, creationState);
if (biDirectionalFetch != null) {
fetches.add(biDirectionalFetch);
return;
}
}
final Integer maximumFetchDepth = creationContext.getMaximumFetchDepth();
if (maximumFetchDepth != null) {
if (fetchDepth == maximumFetchDepth + 1) {
joined = false;
} else if (fetchDepth > maximumFetchDepth + 1) {
if (!(fetchable instanceof BasicValuedModelPart) && !(fetchable instanceof EmbeddedAttributeMapping)) {
return;
}
}
}
if (joined) {
// For join fetches we remember the currentBagRole so that we can avoid multiple bag fetches
if (bagRole != null) {
currentBagRole = bagRole;
}
} else {
// For non-join fetches, we reset the currentBagRole and set it to the previous value in the finally block
currentBagRole = null;
}
final Fetch fetch = fetchParent.generateFetchableFetch(fetchable, fetchablePath, fetchTiming, joined, null, creationState);
if (fetch.getTiming() == FetchTiming.IMMEDIATE && isFetchablePluralAttributeMapping) {
final PluralAttributeMapping pluralAttributeMapping = (PluralAttributeMapping) fetchable;
if (joined) {
hasCollectionJoinFetches = true;
final TableGroup joinTableGroup = creationState.getFromClauseAccess().getTableGroup(fetchablePath);
applyFiltering(querySpec, joinTableGroup, pluralAttributeMapping, creationState);
applyOrdering(querySpec, fetchablePath, pluralAttributeMapping, creationState);
}
}
fetches.add(fetch);
} finally {
if (changeFetchDepth) {
fetchDepth--;
}
// otherwise we could run into a multiple bag fetch situation
if (!joined) {
currentBagRole = previousBagRole;
}
if (entityGraphTraversalState != null && traversalResult != null) {
entityGraphTraversalState.backtrack(traversalResult);
}
}
};
}
use of org.hibernate.query.sqm.spi.EntityIdentifierNavigablePath in project hibernate-orm by hibernate.
the class DomainResultCreationStateImpl method visitFetches.
@Override
public List<Fetch> visitFetches(FetchParent fetchParent) {
final FetchableContainer fetchableContainer = fetchParent.getReferencedMappingContainer();
final List<Fetch> fetches = CollectionHelper.arrayList(fetchableContainer.getNumberOfFetchables());
final Consumer<Fetchable> fetchableConsumer = fetchable -> {
final String fetchableName = fetchable.getFetchableName();
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, 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);
DynamicFetchBuilderLegacy fetchBuilderLegacy;
if (explicitFetchBuilder == null) {
fetchBuilderLegacy = legacyFetchResolver.resolve(fromClauseAccess.findTableGroup(fetchParent.getNavigablePath()).getPrimaryTableReference().getIdentificationVariable(), fetchableName);
} else {
fetchBuilderLegacy = null;
}
if (fetchable instanceof Association && fetchable.getMappedFetchOptions().getTiming() == FetchTiming.DELAYED) {
final Association association = (Association) fetchable;
final ForeignKeyDescriptor foreignKeyDescriptor = association.getForeignKeyDescriptor();
final String partName = attributeName(foreignKeyDescriptor.getSide(association.getSideNature().inverse()).getModelPart());
// If there are no fetch builders for this association, we only want to fetch the FK
if (explicitFetchBuilder == null && fetchBuilderLegacy == null && partName != null) {
currentEntry = new AbstractMap.SimpleEntry<>(currentEntry.getKey() + "." + partName, currentEntry.getValue().append(partName));
explicitFetchBuilder = fetchBuilderResolverStack.getCurrent().apply(currentEntry.getKey());
if (explicitFetchBuilder == null) {
fetchBuilderLegacy = legacyFetchResolver.resolve(fromClauseAccess.findTableGroup(fetchParent.getNavigablePath()).getPrimaryTableReference().getIdentificationVariable(), fetchableName);
}
}
}
relativePathStack.push(currentEntry);
try {
final NavigablePath fetchPath = fetchParent.resolveNavigablePath(fetchable);
final FetchBuilder fetchBuilder;
if (explicitFetchBuilder != null) {
fetchBuilder = explicitFetchBuilder;
} else {
if (fetchBuilderLegacy == null) {
fetchBuilder = Builders.implicitFetchBuilder(fetchPath, fetchable, this);
} else {
fetchBuilder = fetchBuilderLegacy;
}
}
final Fetch fetch = fetchBuilder.buildFetch(fetchParent, fetchPath, jdbcResultsMetadata, (s, s2) -> {
throw new UnsupportedOperationException();
}, this);
fetches.add(fetch);
} finally {
relativePathStack.pop();
}
};
boolean previous = this.processingKeyFetches;
this.processingKeyFetches = true;
if (fetchableContainer instanceof EntityValuedModelPart) {
final EntityValuedModelPart entityValuedFetchable = (EntityValuedModelPart) fetchableContainer;
final EntityIdentifierMapping identifierMapping = entityValuedFetchable.getEntityMappingType().getIdentifierMapping();
final boolean idClass = identifierMapping instanceof NonAggregatedIdentifierMapping;
final String identifierAttributeName = attributeName(identifierMapping);
if (idClass) {
final Map.Entry<String, NavigablePath> oldEntry = relativePathStack.getCurrent();
relativePathStack.push(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)));
}
try {
if (identifierMapping instanceof FetchableContainer) {
// essentially means the entity has a composite id - ask the embeddable to visit its fetchables
((FetchableContainer) identifierMapping).visitFetchables(fetchableConsumer, null);
} else {
fetchableConsumer.accept((Fetchable) identifierMapping);
}
} finally {
this.processingKeyFetches = previous;
if (idClass) {
this.relativePathStack.pop();
}
}
}
fetchableContainer.visitKeyFetchables(fetchableConsumer, null);
fetchableContainer.visitFetchables(fetchableConsumer, null);
return fetches;
}
use of org.hibernate.query.sqm.spi.EntityIdentifierNavigablePath in project hibernate-orm by hibernate.
the class BasicValuedCollectionPart method generateFetch.
@Override
public Fetch generateFetch(FetchParent fetchParent, NavigablePath fetchablePath, FetchTiming fetchTiming, boolean selected, String resultVariable, DomainResultCreationState creationState) {
ResultsLogger.LOGGER.debugf("Generating Fetch for collection-part : `%s` -> `%s`", collectionDescriptor.getRole(), nature.getName());
NavigablePath parentNavigablePath = fetchablePath.getParent();
if (parentNavigablePath instanceof EntityIdentifierNavigablePath) {
parentNavigablePath = parentNavigablePath.getParent();
}
final TableGroup tableGroup = creationState.getSqlAstCreationState().getFromClauseAccess().findTableGroup(parentNavigablePath);
final SqlSelection sqlSelection = resolveSqlSelection(fetchablePath, tableGroup, true, creationState);
return new BasicFetch<>(sqlSelection.getValuesArrayPosition(), fetchParent, fetchablePath, this, valueConverter, FetchTiming.IMMEDIATE, creationState);
}
Aggregations