@Override public AssociationKey getAssociationKey() { final AssociationType type = getType(); if (type.isAnyType()) { return new AssociationKey( JoinHelper.getLHSTableName(type, attributeNumber(), (OuterJoinLoadable) getSource()), JoinHelper.getLHSColumnNames( type, attributeNumber(), 0, (OuterJoinLoadable) getSource(), sessionFactory())); } final Joinable joinable = type.getAssociatedJoinable(sessionFactory()); if (type.getForeignKeyDirection() == ForeignKeyDirection.FOREIGN_KEY_FROM_PARENT) { final String lhsTableName; final String[] lhsColumnNames; if (joinable.isCollection()) { final QueryableCollection collectionPersister = (QueryableCollection) joinable; lhsTableName = collectionPersister.getTableName(); lhsColumnNames = collectionPersister.getElementColumnNames(); } else { final OuterJoinLoadable entityPersister = (OuterJoinLoadable) source(); lhsTableName = getLHSTableName(type, attributeNumber(), entityPersister); lhsColumnNames = getLHSColumnNames(type, attributeNumber(), entityPersister, sessionFactory()); } return new AssociationKey(lhsTableName, lhsColumnNames); } else { return new AssociationKey(joinable.getTableName(), getRHSColumnNames(type, sessionFactory())); } }
public boolean isManyToManyWith(OuterJoinableAssociation other) { if (joinable.isCollection()) { QueryableCollection persister = (QueryableCollection) joinable; if (persister.isManyToMany()) { return persister.getElementType() == other.getJoinableType(); } } return false; }
protected String generateTableAlias(int n, PropertyPath path, Joinable joinable) { // TODO: deal with side-effects (changes to includeInResultRowList, userAliasList, // resultTypeList)!!! // for collection-of-entity, we are called twice for given "path" // once for the collection Joinable, once for the entity Joinable. // the second call will/must "consume" the alias + perform side effects according to // consumesEntityAlias() // for collection-of-other, however, there is only one call // it must "consume" the alias + perform side effects, despite what consumeEntityAlias() return // says // // note: the logic for adding to the userAliasList is still strictly based on // consumesEntityAlias return value boolean checkForSqlAlias = joinable.consumesEntityAlias(); if (!checkForSqlAlias && joinable.isCollection()) { // is it a collection-of-other (component or value) ? CollectionPersister collectionPersister = (CollectionPersister) joinable; Type elementType = collectionPersister.getElementType(); if (elementType.isComponentType() || !elementType.isEntityType()) { checkForSqlAlias = true; } } String sqlAlias = null; if (checkForSqlAlias) { final Criteria subcriteria = translator.getCriteria(path.getFullPath()); sqlAlias = subcriteria == null ? null : translator.getSQLAlias(subcriteria); if (joinable.consumesEntityAlias() && !translator.hasProjection()) { includeInResultRowList.add(subcriteria != null && subcriteria.getAlias() != null); if (sqlAlias != null) { if (subcriteria.getAlias() != null) { userAliasList.add(subcriteria.getAlias()); resultTypeList.add(translator.getResultType(subcriteria)); } } } } if (sqlAlias == null) { sqlAlias = super.generateTableAlias(n + translator.getSQLAliasCount(), path, joinable); } return sqlAlias; }
public String selectFragment( Joinable rhs, String rhsAlias, String lhsAlias, String entitySuffix, String collectionSuffix, boolean includeCollectionColumns) { // we need to determine the best way to know that two joinables // represent a single many-to-many... if (rhs != null && isManyToMany() && !rhs.isCollection()) { AssociationType elementType = ((AssociationType) getElementType()); if (rhs.equals(elementType.getAssociatedJoinable(getFactory()))) { return manyToManySelectFragment(rhs, rhsAlias, lhsAlias, collectionSuffix); } } return includeCollectionColumns ? selectFragment(lhsAlias, collectionSuffix) : ""; }
/** * Add on association (one-to-one, many-to-one, or a collection) to a list of associations to be * fetched by outerjoin */ private void addAssociationToJoinTree( final AssociationType type, final String[] aliasedLhsColumns, final String alias, final PropertyPath path, final int currentDepth, final JoinType joinType) throws MappingException { Joinable joinable = type.getAssociatedJoinable(getFactory()); // important to generate alias based on size of association collection // *before* adding this join to that collection String subalias = generateTableAlias(associations.size() + 1, path, joinable); // NOTE : it should be fine to continue to pass only filters below // (instead of LoadQueryInfluencers) since "from that point on" we // only need to worry about restrictions (and not say adding more // joins) OuterJoinableAssociation assoc = new OuterJoinableAssociation( path, type, alias, aliasedLhsColumns, subalias, joinType, getWithClause(path), hasRestriction(path), getFactory(), loadQueryInfluencers.getEnabledFilters()); assoc.validateJoin(path.getFullPath()); associations.add(assoc); int nextDepth = currentDepth + 1; // path = ""; if (!joinable.isCollection()) { if (joinable instanceof OuterJoinLoadable) { walkEntityTree((OuterJoinLoadable) joinable, subalias, path, nextDepth); } } else { if (joinable instanceof QueryableCollection) { walkCollectionTree((QueryableCollection) joinable, subalias, path, nextDepth); } } }