// detect cases when withClause is used on multiple tables or when join keys depend on subclass columns private static bool NeedsTableGroupJoin(IReadOnlyList <IJoin> joins, SqlString[] withClauseFragments, bool includeSubclasses) { bool hasWithClause = withClauseFragments.Any(x => SqlStringHelper.IsNotEmpty(x)); //NH Specific: No alias processing (see hibernate JoinSequence.NeedsTableGroupJoin) if (joins.Count > 1 && hasWithClause) { return(true); } foreach (var join in joins) { var entityPersister = GetEntityPersister(join.Joinable); if (entityPersister?.HasSubclassJoins(includeSubclasses) != true) { continue; } if (hasWithClause) { return(true); } if (entityPersister.ColumnsDependOnSubclassJoins(join.RHSColumns)) { return(true); } } return(false); }
/// <summary> /// Generate a sequence of <c>LEFT OUTER JOIN</c> clauses for the given associations. /// </summary> protected JoinFragment MergeOuterJoins(IList <OuterJoinableAssociation> associations) { JoinFragment outerjoin = Dialect.CreateOuterJoinFragment(); var sortedAssociations = GetSortedAssociations(associations); OuterJoinableAssociation last = null; foreach (OuterJoinableAssociation oj in sortedAssociations) { if (last != null && last.IsManyToManyWith(oj)) { oj.AddManyToManyJoin(outerjoin, (IQueryableCollection)last.Joinable); } else { // NH Different behavior : NH1179 and NH1293 // Apply filters for entity joins and Many-To-One associations SqlString filter = null; var enabledFiltersForJoin = oj.ForceFilter ? enabledFilters : enabledFiltersForManyToOne; if (oj.ForceFilter || enabledFiltersForJoin.Count > 0) { string manyToOneFilterFragment = oj.Joinable.FilterFragment(oj.RHSAlias, enabledFiltersForJoin); bool joinClauseDoesNotContainsFilterAlready = oj.On?.IndexOfCaseInsensitive(manyToOneFilterFragment) == -1; if (joinClauseDoesNotContainsFilterAlready) { filter = new SqlString(manyToOneFilterFragment); } } if (TableGroupJoinHelper.ProcessAsTableGroupJoin(new[] { oj }, new[] { oj.On, filter }, true, outerjoin, alias => true, factory)) { continue; } oj.AddJoins(outerjoin); // Ensure that the join condition is added to the join, not the where clause. // Adding the condition to the where clause causes left joins to become inner joins. if (SqlStringHelper.IsNotEmpty(filter)) { outerjoin.AddFromFragmentString(filter); } } last = oj; } return(outerjoin); }
public OuterJoinableAssociation(IAssociationType joinableType, String lhsAlias, String[] lhsColumns, String rhsAlias, JoinType joinType, SqlString withClause, ISessionFactoryImplementor factory, IDictionary <string, IFilter> enabledFilters) { this.joinableType = joinableType; this.lhsAlias = lhsAlias; this.lhsColumns = lhsColumns; this.rhsAlias = rhsAlias; this.joinType = joinType; joinable = joinableType.GetAssociatedJoinable(factory); rhsColumns = JoinHelper.GetRHSColumnNames(joinableType, factory); on = new SqlString(joinableType.GetOnCondition(rhsAlias, factory, enabledFilters)); if (SqlStringHelper.IsNotEmpty(withClause)) { on = on.Append(" and ( ").Append(withClause).Append(" )"); } this.enabledFilters = enabledFilters; // needed later for many-to-many/filter application }
private void AddJoinNodes(IRestrictableStatement query, JoinSequence join, FromElement fromElement, bool supportRootAlias) { JoinFragment joinFragment = join.ToJoinFragment( _walker.EnabledFilters, fromElement.UseFromFragment || fromElement.IsDereferencedBySuperclassOrSubclassProperty, fromElement.WithClauseFragment, fromElement.WithClauseJoinAlias, supportRootAlias ? join.RootAlias : string.Empty ); SqlString frag = joinFragment.ToFromFragmentString; SqlString whereFrag = joinFragment.ToWhereFragmentString; // If the from element represents a JOIN_FRAGMENT and it is // a theta-style join, convert its type from JOIN_FRAGMENT // to FROM_FRAGMENT if (fromElement.Type == HqlSqlWalker.JOIN_FRAGMENT && (join.IsThetaStyle || SqlStringHelper.IsNotEmpty(whereFrag))) { fromElement.Type = HqlSqlWalker.FROM_FRAGMENT; fromElement.JoinSequence.SetUseThetaStyle(true); // this is used during SqlGenerator processing } // If there is a FROM fragment and the FROM element is an explicit, then add the from part. if (fromElement.UseFromFragment /*&& StringHelper.isNotEmpty( frag )*/) { SqlString fromFragment = ProcessFromFragment(frag, join).Trim(); if (log.IsDebugEnabled()) { log.Debug("Using FROM fragment [{0}]", fromFragment); } ProcessDynamicFilterParameters(fromFragment, fromElement, _walker); } _syntheticAndFactory.AddWhereFragment( joinFragment, whereFrag, query, fromElement, _walker ); }