AliasResolutionContext aliasResolutionContext,
ReaderCollector readerCollector,
FetchStatsImpl stats) {
stats.processingFetch( fetch );
final CollectionReferenceAliases aliases = aliasResolutionContext.resolveAliases( fetch );
if ( fetch.getCollectionPersister().isManyToMany() ) {
final QueryableCollection queryableCollection = (QueryableCollection) fetch.getCollectionPersister();
final Joinable joinableCollection = (Joinable) fetch.getCollectionPersister();
// 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 = resolveLhsTableAlias( fetchOwner, fetch, aliasResolutionContext );
// 2) the m-n table : user_role
final String collectionTableAlias = aliases.getCollectionTableAlias();
// 3) the element table : role
final String elementTableAlias = aliases.getElementTableAlias();
{
// add join fragments from the owner table -> collection table ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
final String filterFragment = ( (Joinable) fetch.getCollectionPersister() ).filterFragment(
collectionTableAlias,
buildingParameters.getQueryInfluencers().getEnabledFilters()
);
joinFragment.addJoin(
joinableCollection.getTableName(),
collectionTableAlias,
StringHelper.qualify( ownerTableAlias, extractJoinable( fetchOwner ).getKeyColumnNames() ),
queryableCollection.getKeyColumnNames(),
fetch.isNullable() ? JoinType.LEFT_OUTER_JOIN : JoinType.INNER_JOIN,
filterFragment
);
joinFragment.addJoins(
joinableCollection.fromJoinFragment( collectionTableAlias, false, true ),
joinableCollection.whereJoinFragment( collectionTableAlias, false, true )
);
// add select fragments from the collection table ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
selectStatementBuilder.appendSelectClauseFragment(
joinableCollection.selectFragment(
(Joinable) queryableCollection.getElementPersister(),
ownerTableAlias,
collectionTableAlias,
aliases.getEntityElementColumnAliases().getSuffix(),
aliases.getCollectionColumnAliases().getSuffix(),
true
)
);
}
{
// add join fragments from the collection table -> element entity table ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
final String additionalJoinConditions = resolveAdditionalJoinCondition(
factory,
elementTableAlias,
fetchOwner,
fetch,
buildingParameters.getQueryInfluencers(),
aliasResolutionContext
);
final String manyToManyFilter = fetch.getCollectionPersister().getManyToManyFilterFragment(
collectionTableAlias,
buildingParameters.getQueryInfluencers().getEnabledFilters()
);
final String condition;
if ( "".equals( manyToManyFilter ) ) {
condition = additionalJoinConditions;
}
else if ( "".equals( additionalJoinConditions ) ) {
condition = manyToManyFilter;
}
else {
condition = additionalJoinConditions + " and " + manyToManyFilter;
}
final OuterJoinLoadable elementPersister = (OuterJoinLoadable) queryableCollection.getElementPersister();
addJoins(
joinFragment,
elementPersister,
// JoinType.INNER_JOIN,
JoinType.LEFT_OUTER_JOIN,
elementTableAlias,
elementPersister.getIdentifierColumnNames(),
StringHelper.qualify( collectionTableAlias, queryableCollection.getElementColumnNames() ),
condition
);
// add select fragments from the element entity table ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
selectStatementBuilder.appendSelectClauseFragment(
elementPersister.selectFragment(
aliases.getElementTableAlias(),
aliases.getEntityElementColumnAliases().getSuffix()
)
);
}
final String manyToManyOrdering = queryableCollection.getManyToManyOrderByString( collectionTableAlias );
if ( StringHelper.isNotEmpty( manyToManyOrdering ) ) {
selectStatementBuilder.appendOrderByFragment( manyToManyOrdering );
}
final String ordering = queryableCollection.getSQLOrderByString( collectionTableAlias );
if ( StringHelper.isNotEmpty( ordering ) ) {
selectStatementBuilder.appendOrderByFragment( ordering );
}
final EntityReferenceAliases entityReferenceAliases = new EntityReferenceAliases() {
@Override
public String getTableAlias() {
return aliases.getElementTableAlias();
}
@Override
public EntityAliases getColumnAliases() {
return aliases.getEntityElementColumnAliases();
}
};
final EntityReference elementEntityReference = (EntityReference) fetch.getElementGraph();
readerCollector.addReader(
new EntityReferenceReader(
elementEntityReference,
entityReferenceAliases,
buildIdentifierReader(
selectStatementBuilder,
factory,
joinFragment,
elementEntityReference,
buildingParameters,
aliasResolutionContext,
readerCollector,
entityReferenceAliases,
stats
)
)
);
}
else {
final QueryableCollection queryableCollection = (QueryableCollection) fetch.getCollectionPersister();
final Joinable joinableCollection = (Joinable) fetch.getCollectionPersister();
final String rhsTableAlias = aliases.getElementTableAlias();
final String[] rhsColumnNames = JoinHelper.getRHSColumnNames( fetch.getFetchedType(), factory );
final String lhsTableAlias = resolveLhsTableAlias( fetchOwner, fetch, aliasResolutionContext );
// todo : this is not exactly correct. it assumes the join refers to the LHS PK
final String[] aliasedLhsColumnNames = fetch.toSqlSelectFragments( lhsTableAlias );
final String on = resolveAdditionalJoinCondition(
factory,
rhsTableAlias,
fetchOwner,
fetch,
buildingParameters.getQueryInfluencers(),
aliasResolutionContext
);
addJoins(
joinFragment,
joinableCollection,
fetch.isNullable() ? JoinType.LEFT_OUTER_JOIN : JoinType.INNER_JOIN,
rhsTableAlias,
rhsColumnNames,
aliasedLhsColumnNames,
on
);
// select the "collection columns"
selectStatementBuilder.appendSelectClauseFragment(
queryableCollection.selectFragment(
rhsTableAlias,
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.getEntityElementColumnAliases().getSuffix()
)
);
final EntityReferenceAliases entityReferenceAliases = new EntityReferenceAliases() {
@Override
public String getTableAlias() {
return aliases.getElementTableAlias();
}
@Override
public EntityAliases getColumnAliases() {
return aliases.getEntityElementColumnAliases();
}
};
final EntityReference elementEntityReference = (EntityReference) fetch.getElementGraph();
readerCollector.addReader(