/** Get the order by string required for collection fetching */ protected static final String orderBy(List associations) throws MappingException { StringBuilder buf = new StringBuilder(); Iterator iter = associations.iterator(); OuterJoinableAssociation last = null; while (iter.hasNext()) { OuterJoinableAssociation oj = (OuterJoinableAssociation) iter.next(); if (oj.getJoinType() == JoinType.LEFT_OUTER_JOIN) { // why does this matter? if (oj.getJoinable().isCollection()) { final QueryableCollection queryableCollection = (QueryableCollection) oj.getJoinable(); if (queryableCollection.hasOrdering()) { final String orderByString = queryableCollection.getSQLOrderByString(oj.getRHSAlias()); buf.append(orderByString).append(", "); } } else { // it might still need to apply a collection ordering based on a // many-to-many defined order-by... if (last != null && last.getJoinable().isCollection()) { final QueryableCollection queryableCollection = (QueryableCollection) last.getJoinable(); if (queryableCollection.isManyToMany() && last.isManyToManyWith(oj)) { if (queryableCollection.hasManyToManyOrdering()) { final String orderByString = queryableCollection.getManyToManyOrderByString(oj.getRHSAlias()); buf.append(orderByString).append(", "); } } } } } last = oj; } if (buf.length() > 0) buf.setLength(buf.length() - 2); return buf.toString(); }
/** * Count the number of instances of Joinable which are actually also instances of Loadable, or are * one-to-many associations */ protected static final int countEntityPersisters(List associations) throws MappingException { int result = 0; Iterator iter = associations.iterator(); while (iter.hasNext()) { OuterJoinableAssociation oj = (OuterJoinableAssociation) iter.next(); if (oj.getJoinable().consumesEntityAlias()) { result++; } } return result; }
/** Get the position of the join with the given alias in the list of joins */ private static int getPosition(String lhsAlias, List associations) { int result = 0; for (int i = 0; i < associations.size(); i++) { OuterJoinableAssociation oj = (OuterJoinableAssociation) associations.get(i); if (oj.getJoinable() .consumesEntityAlias() /*|| oj.getJoinable().consumesCollectionAlias() */) { if (oj.rhsAlias.equals(lhsAlias)) return result; result++; } } return -1; }
/** * Count the number of instances of Joinable which are actually also instances of * PersistentCollection which are being fetched by outer join */ protected static final int countCollectionPersisters(List associations) throws MappingException { int result = 0; Iterator iter = associations.iterator(); while (iter.hasNext()) { OuterJoinableAssociation oj = (OuterJoinableAssociation) iter.next(); if (oj.getJoinType() == JoinType.LEFT_OUTER_JOIN && oj.getJoinable().isCollection() && !oj.hasRestriction()) { result++; } } return result; }
/** * 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); } } }
public boolean isManyToManyWith(OuterJoinableAssociation other) { if (joinable.isCollection()) { QueryableCollection persister = (QueryableCollection) joinable; if (persister.isManyToMany()) { return persister.getElementType() == other.getJoinableType(); } } return false; }
/** Generate a select list of columns containing all properties of the entity classes */ protected final String selectString(List associations) throws MappingException { if (associations.size() == 0) { return ""; } else { StringBuilder buf = new StringBuilder(associations.size() * 100); int entityAliasCount = 0; int collectionAliasCount = 0; for (int i = 0; i < associations.size(); i++) { OuterJoinableAssociation join = (OuterJoinableAssociation) associations.get(i); OuterJoinableAssociation next = (i == associations.size() - 1) ? null : (OuterJoinableAssociation) associations.get(i + 1); final Joinable joinable = join.getJoinable(); final String entitySuffix = (suffixes == null || entityAliasCount >= suffixes.length) ? null : suffixes[entityAliasCount]; final String collectionSuffix = (collectionSuffixes == null || collectionAliasCount >= collectionSuffixes.length) ? null : collectionSuffixes[collectionAliasCount]; final String selectFragment = joinable.selectFragment( next == null ? null : next.getJoinable(), next == null ? null : next.getRHSAlias(), join.getRHSAlias(), entitySuffix, collectionSuffix, join.getJoinType() == JoinType.LEFT_OUTER_JOIN); if (selectFragment.trim().length() > 0) { buf.append(", ").append(selectFragment); } if (joinable.consumesEntityAlias()) entityAliasCount++; if (joinable.consumesCollectionAlias() && join.getJoinType() == JoinType.LEFT_OUTER_JOIN) collectionAliasCount++; } return buf.toString(); } }
/** Generate a sequence of <tt>LEFT OUTER JOIN</tt> clauses for the given associations. */ protected final JoinFragment mergeOuterJoins(List associations) throws MappingException { JoinFragment outerjoin = getDialect().createOuterJoinFragment(); Iterator iter = associations.iterator(); OuterJoinableAssociation last = null; while (iter.hasNext()) { OuterJoinableAssociation oj = (OuterJoinableAssociation) iter.next(); if (last != null && last.isManyToManyWith(oj)) { oj.addManyToManyJoin(outerjoin, (QueryableCollection) last.getJoinable()); } else { oj.addJoins(outerjoin); } last = oj; } last = null; return outerjoin; }
protected void initPersisters( final List associations, final LockOptions lockOptions, final AssociationInitCallback callback) throws MappingException { final int joins = countEntityPersisters(associations); final int collections = countCollectionPersisters(associations); collectionOwners = collections == 0 ? null : new int[collections]; collectionPersisters = collections == 0 ? null : new CollectionPersister[collections]; collectionSuffixes = BasicLoader.generateSuffixes(joins + 1, collections); this.lockOptions = lockOptions; persisters = new Loadable[joins]; aliases = new String[joins]; owners = new int[joins]; ownerAssociationTypes = new EntityType[joins]; lockModeArray = ArrayHelper.fillArray(lockOptions.getLockMode(), joins); int i = 0; int j = 0; Iterator iter = associations.iterator(); while (iter.hasNext()) { final OuterJoinableAssociation oj = (OuterJoinableAssociation) iter.next(); if (!oj.isCollection()) { persisters[i] = (Loadable) oj.getJoinable(); aliases[i] = oj.getRHSAlias(); owners[i] = oj.getOwner(associations); ownerAssociationTypes[i] = (EntityType) oj.getJoinableType(); callback.associationProcessed(oj, i); i++; } else { QueryableCollection collPersister = (QueryableCollection) oj.getJoinable(); if (oj.getJoinType() == JoinType.LEFT_OUTER_JOIN && !oj.hasRestriction()) { // it must be a collection fetch collectionPersisters[j] = collPersister; collectionOwners[j] = oj.getOwner(associations); j++; } if (collPersister.isOneToMany()) { persisters[i] = (Loadable) collPersister.getElementPersister(); aliases[i] = oj.getRHSAlias(); callback.associationProcessed(oj, i); i++; } } } if (ArrayHelper.isAllNegative(owners)) owners = null; if (collectionOwners != null && ArrayHelper.isAllNegative(collectionOwners)) { collectionOwners = null; } }