Search in sources :

Example 6 with Joinable

use of org.hibernate.persister.entity.Joinable in project hibernate-orm by hibernate.

the class JoinSequence method toJoinFragment.

public JoinFragment toJoinFragment(Map enabledFilters, boolean includeAllSubclassJoins, boolean renderSubclassJoins, String withClauseFragment) throws MappingException {
    final QueryJoinFragment joinFragment = new QueryJoinFragment(factory.getDialect(), useThetaStyle);
    Iterator<Join> iter;
    Join first;
    Joinable last;
    if (rootJoinable != null) {
        joinFragment.addCrossJoin(rootJoinable.getTableName(), rootAlias);
        final String filterCondition = rootJoinable.filterFragment(rootAlias, enabledFilters, treatAsDeclarations);
        // JoinProcessor needs to know if the where clause fragment came from a dynamic filter or not so it
        // can put the where clause fragment in the right place in the SQL AST.   'hasFilterCondition' keeps track
        // of that fact.
        joinFragment.setHasFilterCondition(joinFragment.addCondition(filterCondition));
        addSubclassJoins(joinFragment, rootAlias, rootJoinable, true, includeAllSubclassJoins, treatAsDeclarations);
        last = rootJoinable;
    } else if (needsTableGroupJoin(joins, withClauseFragment)) {
        iter = joins.iterator();
        first = iter.next();
        final String joinString;
        switch(first.joinType) {
            case INNER_JOIN:
                joinString = " inner join ";
                break;
            case LEFT_OUTER_JOIN:
                joinString = " left outer join ";
                break;
            case RIGHT_OUTER_JOIN:
                joinString = " right outer join ";
                break;
            case FULL_JOIN:
                joinString = " full outer join ";
                break;
            default:
                throw new AssertionFailure("undefined join type");
        }
        joinFragment.addFromFragmentString(joinString);
        joinFragment.addFromFragmentString(" (");
        joinFragment.addFromFragmentString(first.joinable.getTableName());
        joinFragment.addFromFragmentString(" ");
        joinFragment.addFromFragmentString(first.getAlias());
        for (Join join : joins) {
            // Skip joining the first join node as it is contained in the subquery
            if (join != first) {
                joinFragment.addJoin(join.getJoinable().getTableName(), join.getAlias(), join.getLHSColumns(), JoinHelper.getRHSColumnNames(join.getAssociationType(), factory), join.joinType);
            }
            addSubclassJoins(joinFragment, join.getAlias(), join.getJoinable(), // TODO: Think about if this could be made always true
            join.joinType == JoinType.INNER_JOIN, includeAllSubclassJoins, // builds the JoinSequence for HQL joins
            treatAsDeclarations);
        }
        joinFragment.addFromFragmentString(")");
        joinFragment.addFromFragmentString(" on ");
        final String rhsAlias = first.getAlias();
        final String[][] lhsColumns = first.getLHSColumns();
        final String[] rhsColumns = JoinHelper.getRHSColumnNames(first.getAssociationType(), factory);
        if (lhsColumns.length > 1) {
            joinFragment.addFromFragmentString("(");
        }
        for (int i = 0; i < lhsColumns.length; i++) {
            for (int j = 0; j < lhsColumns[i].length; j++) {
                joinFragment.addFromFragmentString(lhsColumns[i][j]);
                joinFragment.addFromFragmentString("=");
                joinFragment.addFromFragmentString(rhsAlias);
                joinFragment.addFromFragmentString(".");
                joinFragment.addFromFragmentString(rhsColumns[j]);
                if (j < lhsColumns[i].length - 1) {
                    joinFragment.addFromFragmentString(" and ");
                }
            }
            if (i < lhsColumns.length - 1) {
                joinFragment.addFromFragmentString(" or ");
            }
        }
        if (lhsColumns.length > 1) {
            joinFragment.addFromFragmentString(")");
        }
        joinFragment.addFromFragmentString(" and ");
        joinFragment.addFromFragmentString(withClauseFragment);
        return joinFragment;
    } else {
        last = null;
    }
    for (Join join : joins) {
        // technically the treatAsDeclarations should only apply to rootJoinable or to a single Join,
        // but that is not possible atm given how these JoinSequence and Join objects are built.
        // However, it is generally ok given how the HQL parser builds these JoinSequences (a HQL join
        // results in a JoinSequence with an empty rootJoinable and a single Join).  So we use that here
        // as an assumption
        final String on = join.getAssociationType().getOnCondition(join.getAlias(), factory, enabledFilters, treatAsDeclarations);
        String condition;
        if (last != null && isManyToManyRoot(last) && ((QueryableCollection) last).getElementType() == join.getAssociationType()) {
            // the current join represents the join between a many-to-many association table
            // and its "target" table.  Here we need to apply any additional filters
            // defined specifically on the many-to-many
            final String manyToManyFilter = ((QueryableCollection) last).getManyToManyFilterFragment(join.getAlias(), enabledFilters);
            condition = "".equals(manyToManyFilter) ? on : "".equals(on) ? manyToManyFilter : on + " and " + manyToManyFilter;
        } else {
            condition = on;
        }
        if (withClauseFragment != null && !isManyToManyRoot(join.joinable)) {
            condition += " and " + withClauseFragment;
        }
        joinFragment.addJoin(join.getJoinable().getTableName(), join.getAlias(), join.getLHSColumns(), JoinHelper.getRHSColumnNames(join.getAssociationType(), factory), join.joinType, condition);
        if (renderSubclassJoins) {
            addSubclassJoins(joinFragment, join.getAlias(), join.getJoinable(), join.joinType == JoinType.INNER_JOIN, includeAllSubclassJoins, // builds the JoinSequence for HQL joins
            treatAsDeclarations);
        }
        last = join.getJoinable();
    }
    if (next != null) {
        joinFragment.addFragment(next.toJoinFragment(enabledFilters, includeAllSubclassJoins));
    }
    joinFragment.addCondition(conditions.toString());
    if (isFromPart) {
        joinFragment.clearWherePart();
    }
    return joinFragment;
}
Also used : AssertionFailure(org.hibernate.AssertionFailure) QueryJoinFragment(org.hibernate.sql.QueryJoinFragment) Joinable(org.hibernate.persister.entity.Joinable) QueryableCollection(org.hibernate.persister.collection.QueryableCollection)

Example 7 with Joinable

use of org.hibernate.persister.entity.Joinable in project hibernate-orm by hibernate.

the class LoadQueryJoinAndFetchProcessor method processEntityFetch.

private void processEntityFetch(SelectStatementBuilder selectStatementBuilder, FetchSource fetchSource, EntityFetch fetch, ReaderCollector readerCollector, FetchStatsImpl fetchStats) {
    // todo : still need to think through expressing bi-directionality in the new model...
    // if ( BidirectionalEntityFetch.class.isInstance( fetch ) ) {
    // log.tracef( "Skipping bi-directional entity fetch [%s]", fetch );
    // return;
    // }
    fetchStats.processingFetch(fetch);
    if (!FetchStrategyHelper.isJoinFetched(fetch.getFetchStrategy())) {
        // not join fetched, so nothing else to do
        return;
    }
    // First write out the SQL SELECT fragments
    final Joinable joinable = (Joinable) fetch.getEntityPersister();
    EntityReferenceAliases aliases = aliasResolutionContext.resolveEntityReferenceAliases(fetch.getQuerySpaceUid());
    // the null arguments here relate to many-to-many fetches
    selectStatementBuilder.appendSelectClauseFragment(joinable.selectFragment(null, null, aliases.getTableAlias(), aliases.getColumnAliases().getSuffix(), null, true));
    // process its identifier fetches first (building EntityReferenceInitializers for them if needed)
    if (fetch.getIdentifierDescription().hasFetches()) {
        final FetchSource entityIdentifierAsFetchSource = (FetchSource) fetch.getIdentifierDescription();
        for (Fetch identifierFetch : entityIdentifierAsFetchSource.getFetches()) {
            processFetch(selectStatementBuilder, fetch, identifierFetch, readerCollector, fetchStats);
        }
    }
    // build an EntityReferenceInitializers for the incoming fetch itself
    readerCollector.add(new EntityReferenceInitializerImpl(fetch, aliases));
    // then visit each of our (non-identifier) fetches
    processFetches(fetch, selectStatementBuilder, readerCollector, fetchStats);
}
Also used : Fetch(org.hibernate.loader.plan.spi.Fetch) EntityFetch(org.hibernate.loader.plan.spi.EntityFetch) CollectionAttributeFetch(org.hibernate.loader.plan.spi.CollectionAttributeFetch) FetchSource(org.hibernate.loader.plan.spi.FetchSource) EntityReferenceAliases(org.hibernate.loader.plan.exec.spi.EntityReferenceAliases) Joinable(org.hibernate.persister.entity.Joinable) EntityReferenceInitializerImpl(org.hibernate.loader.plan.exec.process.internal.EntityReferenceInitializerImpl)

Example 8 with Joinable

use of org.hibernate.persister.entity.Joinable in project hibernate-orm by hibernate.

the class LoadQueryJoinAndFetchProcessor method processCollectionFetch.

private void processCollectionFetch(SelectStatementBuilder selectStatementBuilder, FetchSource fetchSource, CollectionAttributeFetch fetch, ReaderCollector readerCollector, FetchStatsImpl fetchStats) {
    fetchStats.processingFetch(fetch);
    if (!FetchStrategyHelper.isJoinFetched(fetch.getFetchStrategy())) {
        // not join fetched, so nothing else to do
        return;
    }
    final CollectionReferenceAliases aliases = aliasResolutionContext.resolveCollectionReferenceAliases(fetch.getQuerySpaceUid());
    final QueryableCollection queryableCollection = (QueryableCollection) fetch.getCollectionPersister();
    final Joinable joinableCollection = (Joinable) fetch.getCollectionPersister();
    if (fetch.getCollectionPersister().isManyToMany()) {
        // todo : better way to access `ownerTableAlias` here.
        // when processing the Join part of this we are able to look up the "lhs table alias" because we know
        // the 'lhs' QuerySpace.
        // 
        // Good idea to be able resolve a Join by lookup on the rhs and lhs uid?  If so, Fetch
        // for many-to-many we have 3 table aliases.  By way of example, consider a normal m-n: User<->Role
        // where User is the FetchOwner and Role (User.roles) is the Fetch.  We'd have:
        // 1) the owner's table : user
        final String ownerTableAlias = aliasResolutionContext.resolveSqlTableAliasFromQuerySpaceUid(fetchSource.getQuerySpaceUid());
        // 2) the m-n table : user_role
        final String collectionTableAlias = aliases.getCollectionTableAlias();
        // 3) the element table : role
        final String elementTableAlias = aliases.getElementTableAlias();
        // add select fragments from the collection table ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        selectStatementBuilder.appendSelectClauseFragment(joinableCollection.selectFragment((Joinable) queryableCollection.getElementPersister(), elementTableAlias, collectionTableAlias, aliases.getEntityElementAliases().getColumnAliases().getSuffix(), aliases.getCollectionColumnAliases().getSuffix(), true));
        // add select fragments from the element entity table ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
        final OuterJoinLoadable elementPersister = (OuterJoinLoadable) queryableCollection.getElementPersister();
        selectStatementBuilder.appendSelectClauseFragment(elementPersister.selectFragment(elementTableAlias, aliases.getEntityElementAliases().getColumnAliases().getSuffix()));
        // add SQL ORDER-BY fragments
        final String manyToManyOrdering = queryableCollection.getManyToManyOrderByString(elementTableAlias);
        if (StringHelper.isNotEmpty(manyToManyOrdering)) {
            selectStatementBuilder.appendOrderByFragment(manyToManyOrdering);
        }
        final String ordering = queryableCollection.getSQLOrderByString(collectionTableAlias);
        if (StringHelper.isNotEmpty(ordering)) {
            selectStatementBuilder.appendOrderByFragment(ordering);
        }
        readerCollector.add(new EntityReferenceInitializerImpl((EntityReference) fetch.getElementGraph(), aliasResolutionContext.resolveEntityReferenceAliases(fetch.getElementGraph().getQuerySpaceUid())));
    } else {
        // select the "collection columns"
        selectStatementBuilder.appendSelectClauseFragment(queryableCollection.selectFragment(aliases.getElementTableAlias(), aliases.getCollectionColumnAliases().getSuffix()));
        if (fetch.getCollectionPersister().isOneToMany()) {
            // if the collection elements are entities, select the entity columns as well
            final OuterJoinLoadable elementPersister = (OuterJoinLoadable) queryableCollection.getElementPersister();
            selectStatementBuilder.appendSelectClauseFragment(elementPersister.selectFragment(aliases.getElementTableAlias(), aliases.getEntityElementAliases().getColumnAliases().getSuffix()));
            readerCollector.add(new EntityReferenceInitializerImpl((EntityReference) fetch.getElementGraph(), aliasResolutionContext.resolveEntityReferenceAliases(fetch.getElementGraph().getQuerySpaceUid())));
        }
        final String ordering = queryableCollection.getSQLOrderByString(aliases.getElementTableAlias());
        if (StringHelper.isNotEmpty(ordering)) {
            selectStatementBuilder.appendOrderByFragment(ordering);
        }
    }
    if (fetch.getElementGraph() != null) {
        processFetches(fetch.getElementGraph(), selectStatementBuilder, readerCollector);
    }
    readerCollector.add(new CollectionReferenceInitializerImpl(fetch, aliases));
}
Also used : OuterJoinLoadable(org.hibernate.persister.entity.OuterJoinLoadable) Joinable(org.hibernate.persister.entity.Joinable) EntityReferenceInitializerImpl(org.hibernate.loader.plan.exec.process.internal.EntityReferenceInitializerImpl) EntityReference(org.hibernate.loader.plan.spi.EntityReference) CollectionReferenceAliases(org.hibernate.loader.plan.exec.spi.CollectionReferenceAliases) QueryableCollection(org.hibernate.persister.collection.QueryableCollection) CollectionReferenceInitializerImpl(org.hibernate.loader.plan.exec.process.internal.CollectionReferenceInitializerImpl)

Example 9 with Joinable

use of org.hibernate.persister.entity.Joinable in project dhis2-core by dhis2.

the class HibernatePropertyIntrospector method updateJoinTables.

private void updateJoinTables() {
    if (!roleToRoleComputing.compareAndSet(false, true)) {
        // do it again
        return;
    }
    Map<String, List<String>> joinTableToRoles = new HashMap<>();
    SessionFactoryImplementor sessionFactoryImplementor = (SessionFactoryImplementor) sessionFactory;
    MetamodelImplementor metamodelImplementor = sessionFactoryImplementor.getMetamodel();
    for (CollectionPersister collectionPersister : metamodelImplementor.collectionPersisters().values()) {
        CollectionType collectionType = collectionPersister.getCollectionType();
        if (collectionPersister.isManyToMany() && collectionType.isAssociationType()) {
            Joinable associatedJoinable = collectionType.getAssociatedJoinable(sessionFactoryImplementor);
            if (!joinTableToRoles.containsKey(associatedJoinable.getTableName())) {
                joinTableToRoles.put(associatedJoinable.getTableName(), new ArrayList<>());
            }
            joinTableToRoles.get(associatedJoinable.getTableName()).add(collectionPersister.getRole());
        } else if (collectionPersister.isInverse() && collectionType instanceof SetType) {
            SetType setType = (SetType) collectionType;
            setType.getAssociatedJoinable(sessionFactoryImplementor);
        }
    }
    joinTableToRoles.entrySet().removeIf(entry -> entry.getValue().size() < 2);
    for (Map.Entry<String, List<String>> entry : joinTableToRoles.entrySet()) {
        roleToRole.put(entry.getValue().get(0), entry.getValue().get(1));
        roleToRole.put(entry.getValue().get(1), entry.getValue().get(0));
    }
}
Also used : MetamodelImplementor(org.hibernate.metamodel.spi.MetamodelImplementor) HashMap(java.util.HashMap) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap) SessionFactoryImplementor(org.hibernate.engine.spi.SessionFactoryImplementor) CollectionPersister(org.hibernate.persister.collection.CollectionPersister) SetType(org.hibernate.type.SetType) CollectionType(org.hibernate.type.CollectionType) Joinable(org.hibernate.persister.entity.Joinable) ArrayList(java.util.ArrayList) List(java.util.List) HashMap(java.util.HashMap) Map(java.util.Map) ConcurrentHashMap(java.util.concurrent.ConcurrentHashMap)

Example 10 with Joinable

use of org.hibernate.persister.entity.Joinable in project hibernate-orm by hibernate.

the class FromElementFactory method createFromElement.

private FromElement createFromElement(EntityPersister entityPersister) {
    Joinable joinable = (Joinable) entityPersister;
    String text = joinable.getTableName();
    AST ast = createFromElement(text);
    FromElement element = (FromElement) ast;
    return element;
}
Also used : AST(antlr.collections.AST) Joinable(org.hibernate.persister.entity.Joinable)

Aggregations

Joinable (org.hibernate.persister.entity.Joinable)19 QueryableCollection (org.hibernate.persister.collection.QueryableCollection)6 OuterJoinLoadable (org.hibernate.persister.entity.OuterJoinLoadable)6 AssociationKey (org.hibernate.persister.walking.spi.AssociationKey)5 AssociationType (org.hibernate.type.AssociationType)3 ArrayList (java.util.ArrayList)2 HashMap (java.util.HashMap)2 List (java.util.List)2 Map (java.util.Map)2 HibernateException (org.hibernate.HibernateException)2 SessionFactoryImplementor (org.hibernate.engine.spi.SessionFactoryImplementor)2 EntityReferenceInitializerImpl (org.hibernate.loader.plan.exec.process.internal.EntityReferenceInitializerImpl)2 EntityReferenceAliases (org.hibernate.loader.plan.exec.spi.EntityReferenceAliases)2 FetchSource (org.hibernate.loader.plan.spi.FetchSource)2 CollectionPersister (org.hibernate.persister.collection.CollectionPersister)2 EntityPersister (org.hibernate.persister.entity.EntityPersister)2 CollectionType (org.hibernate.type.CollectionType)2 SetType (org.hibernate.type.SetType)2 AST (antlr.collections.AST)1 SystemException (com.evolveum.midpoint.util.exception.SystemException)1