* Clone and prepare the JoinedAttributeManager nested JoinedAttributeManager.
* This is used for nested joining as the JoinedAttributeManager passed to the joined build object.
*/
public ObjectLevelReadQuery prepareNestedJoins(JoinedAttributeManager joinManager, ObjectBuildingQuery baseQuery, AbstractSession session) {
// A nested query must be built to pass to the descriptor that looks like the real query execution would.
ObjectLevelReadQuery nestedQuery = (ObjectLevelReadQuery)((ObjectLevelReadQuery)getSelectionQuery()).deepClone();
nestedQuery.setSession(session);
nestedQuery.setShouldUseSerializedObjectPolicy(baseQuery.shouldUseSerializedObjectPolicy());
// Must cascade for nested partial/join attributes, the expressions must be filter to only the nested ones.
if (baseQuery.hasPartialAttributeExpressions()) {
nestedQuery.setPartialAttributeExpressions(extractNestedExpressions(((ObjectLevelReadQuery)baseQuery).getPartialAttributeExpressions(), nestedQuery.getExpressionBuilder()));
// bug 5501751: USING GETALLOWINGNULL() WITH ADDPARTIALATTRIBUTE() BROKEN IN 10.1.3
// The query against Employee with
// query.addPartialAttribute(builder.getAllowingNull("address"));
// in case there's no address returns null instead of Address object.
// Note that in case
// query.addPartialAttribute(builder.getAllowingNull("address").get("city"));
// in case there's no address an empty Address object (all atributes are nulls) is returned.
if(nestedQuery.getPartialAttributeExpressions().isEmpty()) {
if(hasRootExpressionThatShouldUseOuterJoin(((ObjectLevelReadQuery)baseQuery).getPartialAttributeExpressions())) {
nestedQuery.setShouldBuildNullForNullPk(true);
}
}
} else {
if(nestedQuery.getDescriptor().hasFetchGroupManager()) {
FetchGroup sourceFG = baseQuery.getExecutionFetchGroup();
if (sourceFG != null) {
FetchGroup targetFetchGroup = sourceFG.getGroup(getAttributeName());
if (targetFetchGroup != null) {
nestedQuery.setFetchGroup(targetFetchGroup);
nestedQuery.prepareFetchGroup();
}
}
}
List nestedJoins = extractNestedNonAggregateExpressions(joinManager.getJoinedAttributeExpressions(), nestedQuery.getExpressionBuilder(), false);
if (nestedJoins.size() > 0) {
// Recompute the joined indexes based on the nested join expressions.
nestedQuery.getJoinedAttributeManager().clear();
nestedQuery.getJoinedAttributeManager().setJoinedAttributeExpressions_(nestedJoins);
// the next line sets isToManyJoinQuery flag
nestedQuery.getJoinedAttributeManager().prepareJoinExpressions(session);
nestedQuery.getJoinedAttributeManager().computeJoiningMappingQueries(session);
nestedQuery.getJoinedAttributeManager().computeJoiningMappingIndexes(true, session, 0);
} else if (nestedQuery.hasJoining()) {
// Clear any mapping level joins.
nestedQuery.setJoinedAttributeManager(null);
}
// Configure nested locking clause.
if (baseQuery.isLockQuery()) {
if (((ObjectLevelReadQuery)baseQuery).getLockingClause().isForUpdateOfClause()) {
ForUpdateOfClause clause = (ForUpdateOfClause)((ObjectLevelReadQuery)baseQuery).getLockingClause().clone();
clause.setLockedExpressions(extractNestedNonAggregateExpressions(clause.getLockedExpressions(), nestedQuery.getExpressionBuilder(), true));
nestedQuery.setLockingClause(clause);
} else {
nestedQuery.setLockingClause(((ObjectLevelReadQuery)baseQuery).getLockingClause());
}
}
}
nestedQuery.setShouldMaintainCache(baseQuery.shouldMaintainCache());
nestedQuery.setShouldRefreshIdentityMapResult(baseQuery.shouldRefreshIdentityMapResult());
// For flashback: Must still propagate all properties, as the
// attributes of this joined attribute may be read later too.
if (baseQuery.isObjectLevelReadQuery() && ((ObjectLevelReadQuery)baseQuery).hasAsOfClause()) {
nestedQuery.setAsOfClause(((ObjectLevelReadQuery)baseQuery).getAsOfClause());
}
nestedQuery.setCascadePolicy(baseQuery.getCascadePolicy());
if (nestedQuery.hasJoining()) {
nestedQuery.getJoinedAttributeManager().computeJoiningMappingQueries(session);
}
nestedQuery.setSession(null);
nestedQuery.setRequiresDeferredLocks(baseQuery.requiresDeferredLocks());
return nestedQuery;
}