Search in sources :

Example 1 with EntityDelayedFetchImpl

use of org.hibernate.sql.results.graph.entity.internal.EntityDelayedFetchImpl 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)

Example 2 with EntityDelayedFetchImpl

use of org.hibernate.sql.results.graph.entity.internal.EntityDelayedFetchImpl in project hibernate-orm by hibernate.

the class ToOneAttributeMapping method generateFetch.

@Override
public EntityFetch generateFetch(FetchParent fetchParent, NavigablePath fetchablePath, FetchTiming fetchTiming, boolean selected, String resultVariable, DomainResultCreationState creationState) {
    final SqlAstCreationState sqlAstCreationState = creationState.getSqlAstCreationState();
    final FromClauseAccess fromClauseAccess = sqlAstCreationState.getFromClauseAccess();
    final TableGroup parentTableGroup = fromClauseAccess.getTableGroup(fetchParent.getNavigablePath());
    final NavigablePath parentNavigablePath = fetchablePath.getParent();
    assert parentNavigablePath.equals(fetchParent.getNavigablePath()) || fetchParent.getNavigablePath() instanceof TreatedNavigablePath && parentNavigablePath.equals(fetchParent.getNavigablePath().getRealParent());
    if (fetchTiming == FetchTiming.IMMEDIATE && selected) {
        final TableGroup tableGroup;
        if (fetchParent instanceof EntityResultJoinedSubclassImpl && ((EntityPersister) fetchParent.getReferencedModePart()).findDeclaredAttributeMapping(getPartName()) == null) {
            final TableGroupJoin tableGroupJoin = createTableGroupJoin(fetchablePath, parentTableGroup, resultVariable, getJoinType(fetchablePath, parentTableGroup), true, false, creationState.getSqlAstCreationState());
            parentTableGroup.addTableGroupJoin(tableGroupJoin);
            tableGroup = tableGroupJoin.getJoinedGroup();
            fromClauseAccess.registerTableGroup(fetchablePath, tableGroup);
        } else {
            tableGroup = fromClauseAccess.resolveTableGroup(fetchablePath, np -> {
                final TableGroupJoin tableGroupJoin = createTableGroupJoin(fetchablePath, parentTableGroup, resultVariable, getDefaultSqlAstJoinType(parentTableGroup), true, false, creationState.getSqlAstCreationState());
                parentTableGroup.addTableGroupJoin(tableGroupJoin);
                return tableGroupJoin.getJoinedGroup();
            });
        }
        final boolean added = creationState.registerVisitedAssociationKey(foreignKeyDescriptor.getAssociationKey());
        AssociationKey additionalAssociationKey = null;
        if (cardinality == Cardinality.LOGICAL_ONE_TO_ONE && bidirectionalAttributeName != null) {
            final ModelPart bidirectionalModelPart = entityMappingType.findSubPart(bidirectionalAttributeName);
            // Add the inverse association key side as well to be able to resolve to a CircularFetch
            if (bidirectionalModelPart instanceof ToOneAttributeMapping) {
                assert bidirectionalModelPart.getPartMappingType() == declaringTableGroupProducer;
                final ToOneAttributeMapping bidirectionalAttribute = (ToOneAttributeMapping) bidirectionalModelPart;
                final AssociationKey secondKey = bidirectionalAttribute.getForeignKeyDescriptor().getAssociationKey();
                if (creationState.registerVisitedAssociationKey(secondKey)) {
                    additionalAssociationKey = secondKey;
                }
            }
        }
        final EntityFetchJoinedImpl entityFetchJoined = new EntityFetchJoinedImpl(fetchParent, this, tableGroup, fetchablePath, creationState);
        if (added) {
            creationState.removeVisitedAssociationKey(foreignKeyDescriptor.getAssociationKey());
        }
        if (additionalAssociationKey != null) {
            creationState.removeVisitedAssociationKey(additionalAssociationKey);
        }
        return entityFetchJoined;
    }
    /*
			1. No JoinTable
				Model:
					EntityA{
						@ManyToOne
						EntityB b
					}

					EntityB{
						@ManyToOne
						EntityA a
					}

				Relational:
					ENTITY_A( id )
					ENTITY_B( id, entity_a_id)

				1.1 EntityA -> EntityB : as keyResult we need ENTITY_B.id
				1.2 EntityB -> EntityA : as keyResult we need ENTITY_B.entity_a_id (FK referring column)

			2. JoinTable

		 */
    final ForeignKeyDescriptor.Nature resolvingKeySideOfForeignKey = creationState.getCurrentlyResolvingForeignKeyPart();
    final ForeignKeyDescriptor.Nature side;
    if (resolvingKeySideOfForeignKey == ForeignKeyDescriptor.Nature.KEY && this.sideNature == ForeignKeyDescriptor.Nature.TARGET) {
        // If we are currently resolving the key part of a foreign key we do not want to add joins.
        // So if the lhs of this association is the target of the FK, we have to use the KEY part to avoid a join
        side = ForeignKeyDescriptor.Nature.KEY;
    } else {
        side = this.sideNature;
    }
    final DomainResult<?> keyResult = foreignKeyDescriptor.createDomainResult(fetchablePath, parentTableGroup, side, creationState);
    final boolean selectByUniqueKey = isSelectByUniqueKey(side);
    if (fetchTiming == FetchTiming.IMMEDIATE) {
        return new EntityFetchSelectImpl(fetchParent, this, fetchablePath, keyResult, selectByUniqueKey, creationState);
    }
    return new EntityDelayedFetchImpl(fetchParent, this, fetchablePath, keyResult, selectByUniqueKey);
}
Also used : EntityPersister(org.hibernate.persister.entity.EntityPersister) AbstractEntityPersister(org.hibernate.persister.entity.AbstractEntityPersister) Arrays(java.util.Arrays) EntityPersister(org.hibernate.persister.entity.EntityPersister) Property(org.hibernate.mapping.Property) TableGroupJoin(org.hibernate.sql.ast.tree.from.TableGroupJoin) TreatedNavigablePath(org.hibernate.query.spi.TreatedNavigablePath) PropertyAccess(org.hibernate.property.access.spi.PropertyAccess) EntityResultImpl(org.hibernate.sql.results.graph.entity.internal.EntityResultImpl) EntityMappingType(org.hibernate.metamodel.mapping.EntityMappingType) ToOne(org.hibernate.mapping.ToOne) SqlAstCreationContext(org.hibernate.sql.ast.spi.SqlAstCreationContext) PluralAttributeMapping(org.hibernate.metamodel.mapping.PluralAttributeMapping) EntityAssociationMapping(org.hibernate.metamodel.mapping.EntityAssociationMapping) ForeignKeyDescriptor(org.hibernate.metamodel.mapping.ForeignKeyDescriptor) PersistentClass(org.hibernate.mapping.PersistentClass) FetchOptions(org.hibernate.sql.results.graph.FetchOptions) Join(org.hibernate.mapping.Join) TableGroupProducer(org.hibernate.sql.ast.tree.from.TableGroupProducer) SessionFactoryImplementor(org.hibernate.engine.spi.SessionFactoryImplementor) EntityDelayedResultImpl(org.hibernate.sql.results.graph.entity.internal.EntityDelayedResultImpl) CollectionPart(org.hibernate.metamodel.mapping.CollectionPart) SqlSelection(org.hibernate.sql.ast.spi.SqlSelection) CorrelatedTableGroup(org.hibernate.sql.ast.tree.from.CorrelatedTableGroup) EntityValuedFetchable(org.hibernate.sql.results.graph.entity.EntityValuedFetchable) EntityDelayedFetchImpl(org.hibernate.sql.results.graph.entity.internal.EntityDelayedFetchImpl) MappedByTableGroup(org.hibernate.sql.ast.tree.from.MappedByTableGroup) TableGroupJoinProducer(org.hibernate.sql.ast.tree.from.TableGroupJoinProducer) LazyTableGroup(org.hibernate.sql.ast.tree.from.LazyTableGroup) OneToOne(org.hibernate.mapping.OneToOne) VirtualModelPart(org.hibernate.metamodel.mapping.VirtualModelPart) NavigablePath(org.hibernate.query.spi.NavigablePath) StringHelper(org.hibernate.internal.util.StringHelper) DomainResult(org.hibernate.sql.results.graph.DomainResult) Set(java.util.Set) Value(org.hibernate.mapping.Value) Collection(org.hibernate.mapping.Collection) SqlAliasBase(org.hibernate.sql.ast.spi.SqlAliasBase) SqlExpressionResolver(org.hibernate.sql.ast.spi.SqlExpressionResolver) EntityIdentifierMapping(org.hibernate.metamodel.mapping.EntityIdentifierMapping) NavigableRole(org.hibernate.metamodel.model.domain.NavigableRole) ArrayHelper(org.hibernate.internal.util.collections.ArrayHelper) CircularBiDirectionalFetchImpl(org.hibernate.sql.results.internal.domain.CircularBiDirectionalFetchImpl) AbstractEntityPersister(org.hibernate.persister.entity.AbstractEntityPersister) SelectableConsumer(org.hibernate.metamodel.mapping.SelectableConsumer) SharedSessionContractImplementor(org.hibernate.engine.spi.SharedSessionContractImplementor) IndexedConsumer(org.hibernate.mapping.IndexedConsumer) FetchParent(org.hibernate.sql.results.graph.FetchParent) CircularFetchImpl(org.hibernate.sql.results.internal.domain.CircularFetchImpl) DomainResultCreationState(org.hibernate.sql.results.graph.DomainResultCreationState) SqlAliasBaseGenerator(org.hibernate.sql.ast.spi.SqlAliasBaseGenerator) EntityFetchSelectImpl(org.hibernate.sql.results.graph.entity.internal.EntityFetchSelectImpl) JdbcMapping(org.hibernate.metamodel.mapping.JdbcMapping) EntityResultJoinedSubclassImpl(org.hibernate.sql.results.graph.entity.internal.EntityResultJoinedSubclassImpl) SqlAliasStemHelper(org.hibernate.sql.ast.spi.SqlAliasStemHelper) EmbeddedComponentType(org.hibernate.type.EmbeddedComponentType) EntityType(org.hibernate.type.EntityType) Clause(org.hibernate.sql.ast.Clause) TableReference(org.hibernate.sql.ast.tree.from.TableReference) HashSet(java.util.HashSet) ModelPart(org.hibernate.metamodel.mapping.ModelPart) ComponentType(org.hibernate.type.ComponentType) CompositeType(org.hibernate.type.CompositeType) BiConsumer(java.util.function.BiConsumer) ManagedMappingType(org.hibernate.metamodel.mapping.ManagedMappingType) EntityIdentifierNavigablePath(org.hibernate.query.sqm.spi.EntityIdentifierNavigablePath) StandardTableGroup(org.hibernate.sql.ast.tree.from.StandardTableGroup) SqlAstCreationState(org.hibernate.sql.ast.spi.SqlAstCreationState) FetchTiming(org.hibernate.engine.FetchTiming) ManyToOne(org.hibernate.mapping.ManyToOne) LockMode(org.hibernate.LockMode) AssociationKey(org.hibernate.metamodel.mapping.AssociationKey) Predicate(org.hibernate.sql.ast.tree.predicate.Predicate) Iterator(java.util.Iterator) ModelPartContainer(org.hibernate.metamodel.mapping.ModelPartContainer) EmbeddableValuedFetchable(org.hibernate.sql.results.graph.embeddable.EmbeddableValuedFetchable) StateArrayContributorMetadataAccess(org.hibernate.metamodel.mapping.StateArrayContributorMetadataAccess) Fetch(org.hibernate.sql.results.graph.Fetch) Consumer(java.util.function.Consumer) QueryableCollection(org.hibernate.persister.collection.QueryableCollection) EntityFetch(org.hibernate.sql.results.graph.entity.EntityFetch) FetchStyle(org.hibernate.engine.FetchStyle) FromClauseAccess(org.hibernate.sql.ast.spi.FromClauseAccess) SqlAstJoinType(org.hibernate.sql.ast.SqlAstJoinType) Selectable(org.hibernate.mapping.Selectable) EmbeddableValuedModelPart(org.hibernate.metamodel.mapping.EmbeddableValuedModelPart) Collections(java.util.Collections) TableGroup(org.hibernate.sql.ast.tree.from.TableGroup) PluralTableGroup(org.hibernate.sql.ast.tree.from.PluralTableGroup) EntityFetchJoinedImpl(org.hibernate.sql.results.graph.entity.internal.EntityFetchJoinedImpl) Type(org.hibernate.type.Type) EntityFetchJoinedImpl(org.hibernate.sql.results.graph.entity.internal.EntityFetchJoinedImpl) AssociationKey(org.hibernate.metamodel.mapping.AssociationKey) 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) TreatedNavigablePath(org.hibernate.query.spi.TreatedNavigablePath) NavigablePath(org.hibernate.query.spi.NavigablePath) EntityIdentifierNavigablePath(org.hibernate.query.sqm.spi.EntityIdentifierNavigablePath) VirtualModelPart(org.hibernate.metamodel.mapping.VirtualModelPart) ModelPart(org.hibernate.metamodel.mapping.ModelPart) EmbeddableValuedModelPart(org.hibernate.metamodel.mapping.EmbeddableValuedModelPart) EntityResultJoinedSubclassImpl(org.hibernate.sql.results.graph.entity.internal.EntityResultJoinedSubclassImpl) EntityDelayedFetchImpl(org.hibernate.sql.results.graph.entity.internal.EntityDelayedFetchImpl) TableGroupJoin(org.hibernate.sql.ast.tree.from.TableGroupJoin) TreatedNavigablePath(org.hibernate.query.spi.TreatedNavigablePath) FromClauseAccess(org.hibernate.sql.ast.spi.FromClauseAccess) SqlAstCreationState(org.hibernate.sql.ast.spi.SqlAstCreationState) ForeignKeyDescriptor(org.hibernate.metamodel.mapping.ForeignKeyDescriptor) EntityFetchSelectImpl(org.hibernate.sql.results.graph.entity.internal.EntityFetchSelectImpl)

Aggregations

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