Search in sources :

Example 1 with CircularBiDirectionalFetchImpl

use of org.hibernate.sql.results.internal.domain.CircularBiDirectionalFetchImpl in project hibernate-orm by hibernate.

the class ToOneAttributeMapping method createCircularBiDirectionalFetch.

private Fetch createCircularBiDirectionalFetch(NavigablePath fetchablePath, FetchParent fetchParent, NavigablePath parentNavigablePath, DomainResultCreationState creationState) {
    final NavigablePath referencedNavigablePath;
    final boolean hasBidirectionalFetchParent;
    FetchParent realFetchParent = fetchParent;
    // Traverse up the embeddable fetches
    while (realFetchParent.getNavigablePath() != parentNavigablePath) {
        realFetchParent = ((Fetch) fetchParent).getFetchParent();
    }
    if (parentNavigablePath.getParent() == null) {
        referencedNavigablePath = parentNavigablePath;
        hasBidirectionalFetchParent = true;
    } else if (CollectionPart.Nature.fromNameExact(parentNavigablePath.getUnaliasedLocalName()) != null) {
        referencedNavigablePath = parentNavigablePath.getParent().getParent();
        hasBidirectionalFetchParent = fetchParent instanceof Fetch && ((Fetch) fetchParent).getFetchParent() instanceof Fetch;
    } else {
        referencedNavigablePath = parentNavigablePath.getParent();
        hasBidirectionalFetchParent = fetchParent instanceof Fetch;
    }
    // The referencedNavigablePath can be null if this is a collection initialization
    if (referencedNavigablePath != null) {
        if (hasBidirectionalFetchParent) {
            // If this is the key side, we must ensure that the key is not null, so we create a domain result for it
            // In the CircularBiDirectionalFetchImpl we return null if the key is null instead of the bidirectional value
            final DomainResult<?> keyDomainResult;
            // For now, we don't do this if the key table is nullable to avoid an additional join
            if (sideNature == ForeignKeyDescriptor.Nature.KEY && !isKeyTableNullable) {
                keyDomainResult = foreignKeyDescriptor.createKeyDomainResult(fetchablePath, creationState.getSqlAstCreationState().getFromClauseAccess().findTableGroup(realFetchParent.getNavigablePath()), creationState);
            } else {
                keyDomainResult = null;
            }
            return new CircularBiDirectionalFetchImpl(FetchTiming.IMMEDIATE, fetchablePath, fetchParent, this, LockMode.READ, referencedNavigablePath, keyDomainResult);
        } else {
            // A query like `select ch from Phone p join p.callHistory ch` returns collection element domain results
            // but detects that Call#phone is bidirectional in the query.
            // The problem with a bidirectional fetch though is that we can't find an initializer
            // because there is none, as we don't fetch the data of the parent node.
            // To avoid creating another join, we create a special join fetch that uses the existing joined data
            final FromClauseAccess fromClauseAccess = creationState.getSqlAstCreationState().getFromClauseAccess();
            final TableGroup tableGroup = fromClauseAccess.getTableGroup(referencedNavigablePath);
            fromClauseAccess.registerTableGroup(fetchablePath, tableGroup);
            return new EntityFetchJoinedImpl(fetchParent, this, tableGroup, fetchablePath, creationState);
        }
    } else {
        // We get here is this is a lazy collection initialization for which we know the owner is 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 NavigablePath realParent;
        if (CollectionPart.Nature.fromNameExact(parentNavigablePath.getUnaliasedLocalName()) != null) {
            realParent = parentNavigablePath.getParent();
        } else {
            realParent = parentNavigablePath;
        }
        final TableGroup tableGroup = fromClauseAccess.getTableGroup(realParent);
        return new EntityDelayedFetchImpl(fetchParent, this, fetchablePath, foreignKeyDescriptor.createDomainResult(fetchablePath, tableGroup, sideNature, creationState), isSelectByUniqueKey(sideNature));
    }
}
Also used : Fetch(org.hibernate.sql.results.graph.Fetch) EntityFetch(org.hibernate.sql.results.graph.entity.EntityFetch) EntityFetchJoinedImpl(org.hibernate.sql.results.graph.entity.internal.EntityFetchJoinedImpl) CircularBiDirectionalFetchImpl(org.hibernate.sql.results.internal.domain.CircularBiDirectionalFetchImpl) TreatedNavigablePath(org.hibernate.query.spi.TreatedNavigablePath) NavigablePath(org.hibernate.query.spi.NavigablePath) EntityIdentifierNavigablePath(org.hibernate.query.sqm.spi.EntityIdentifierNavigablePath) CorrelatedTableGroup(org.hibernate.sql.ast.tree.from.CorrelatedTableGroup) MappedByTableGroup(org.hibernate.sql.ast.tree.from.MappedByTableGroup) LazyTableGroup(org.hibernate.sql.ast.tree.from.LazyTableGroup) StandardTableGroup(org.hibernate.sql.ast.tree.from.StandardTableGroup) TableGroup(org.hibernate.sql.ast.tree.from.TableGroup) PluralTableGroup(org.hibernate.sql.ast.tree.from.PluralTableGroup) FromClauseAccess(org.hibernate.sql.ast.spi.FromClauseAccess) FetchParent(org.hibernate.sql.results.graph.FetchParent) EntityDelayedFetchImpl(org.hibernate.sql.results.graph.entity.internal.EntityDelayedFetchImpl)

Aggregations

NavigablePath (org.hibernate.query.spi.NavigablePath)1 TreatedNavigablePath (org.hibernate.query.spi.TreatedNavigablePath)1 EntityIdentifierNavigablePath (org.hibernate.query.sqm.spi.EntityIdentifierNavigablePath)1 FromClauseAccess (org.hibernate.sql.ast.spi.FromClauseAccess)1 CorrelatedTableGroup (org.hibernate.sql.ast.tree.from.CorrelatedTableGroup)1 LazyTableGroup (org.hibernate.sql.ast.tree.from.LazyTableGroup)1 MappedByTableGroup (org.hibernate.sql.ast.tree.from.MappedByTableGroup)1 PluralTableGroup (org.hibernate.sql.ast.tree.from.PluralTableGroup)1 StandardTableGroup (org.hibernate.sql.ast.tree.from.StandardTableGroup)1 TableGroup (org.hibernate.sql.ast.tree.from.TableGroup)1 Fetch (org.hibernate.sql.results.graph.Fetch)1 FetchParent (org.hibernate.sql.results.graph.FetchParent)1 EntityFetch (org.hibernate.sql.results.graph.entity.EntityFetch)1 EntityDelayedFetchImpl (org.hibernate.sql.results.graph.entity.internal.EntityDelayedFetchImpl)1 EntityFetchJoinedImpl (org.hibernate.sql.results.graph.entity.internal.EntityFetchJoinedImpl)1 CircularBiDirectionalFetchImpl (org.hibernate.sql.results.internal.domain.CircularBiDirectionalFetchImpl)1