internal JoinFragment ToJoinFragment(
            IDictionary <string, IFilter> enabledFilters,
            bool includeExtraJoins,
            SqlString withClauseFragment,
            string withClauseJoinAlias,
            string withRootAlias)
        {
            QueryJoinFragment joinFragment = new QueryJoinFragment(factory.Dialect, useThetaStyle);

            if (rootJoinable != null)
            {
                joinFragment.AddCrossJoin(rootJoinable.TableName, withRootAlias);
                string filterCondition = rootJoinable.FilterFragment(withRootAlias, enabledFilters);
                // JoinProcessor needs to know if the where clause fragment came from a dynamic filter or not so it
                // can put the where clause fragment in the right place in the SQL AST.   'hasFilterCondition' keeps track
                // of that fact.
                joinFragment.HasFilterCondition = joinFragment.AddCondition(filterCondition);
                if (includeExtraJoins)
                {
                    //TODO: not quite sure about the full implications of this!
                    AddExtraJoins(joinFragment, withRootAlias, rootJoinable, true);
                }
            }

            IJoinable last = rootJoinable;

            for (int i = 0; i < joins.Count; i++)
            {
                Join      join      = joins[i];
                string    on        = join.AssociationType.GetOnCondition(join.Alias, factory, enabledFilters);
                SqlString condition = new SqlString();
                if (last != null &&
                    IsManyToManyRoot(last) &&
                    ((IQueryableCollection)last).ElementType == join.AssociationType)
                {
                    // the current join represents the join between a many-to-many association table
                    // and its "target" table.  Here we need to apply any additional filters
                    // defined specifically on the many-to-many
                    string manyToManyFilter = ((IQueryableCollection)last)
                                              .GetManyToManyFilterFragment(join.Alias, enabledFilters);
                    condition = new SqlString("".Equals(manyToManyFilter)
                                                                                                ? on
                                                                                                : "".Equals(on)
                                                                                                                ? manyToManyFilter
                                                                                                                : on + " and " + manyToManyFilter);
                }
                else
                {
                    // NH Different behavior : NH1179 and NH1293
                    // Apply filters in Many-To-One association
                    var enabledForManyToOne = FilterHelper.GetEnabledForManyToOne(enabledFilters);
                    condition = new SqlString(string.IsNullOrEmpty(on) && enabledForManyToOne.Count > 0
                                                        ? join.Joinable.FilterFragment(join.Alias, enabledForManyToOne)
                                                        : on);
                }

                if (withClauseFragment != null)
                {
                    if (join.Alias.Equals(withClauseJoinAlias))
                    {
                        condition = condition.Append(" and ").Append(withClauseFragment);
                    }
                }

                // NH: the variable "condition" have to be a SqlString because it may contains Parameter instances with BackTrack
                joinFragment.AddJoin(
                    join.Joinable.TableName,
                    join.Alias,
                    join.LHSColumns,
                    JoinHelper.GetRHSColumnNames(join.AssociationType, factory),
                    join.JoinType,
                    condition
                    );
                if (includeExtraJoins)
                {
                    //TODO: not quite sure about the full implications of this!
                    AddExtraJoins(joinFragment, join.Alias, join.Joinable, join.JoinType == JoinType.InnerJoin);
                }
                last = join.Joinable;
            }
            if (next != null)
            {
                joinFragment.AddFragment(next.ToJoinFragment(enabledFilters, includeExtraJoins));
            }
            joinFragment.AddCondition(conditions.ToSqlString());
            if (isFromPart)
            {
                joinFragment.ClearWherePart();
            }
            return(joinFragment);
        }
        internal JoinFragment ToJoinFragment(
            IDictionary <string, IFilter> enabledFilters,
            bool includeAllSubclassJoins,
            bool renderSubclassJoins,
            SqlString withClauseFragment)
        {
            QueryJoinFragment joinFragment = new QueryJoinFragment(factory.Dialect, useThetaStyle);

            if (rootJoinable != null)
            {
                joinFragment.AddCrossJoin(rootJoinable.TableName, rootAlias);
                string filterCondition = rootJoinable.FilterFragment(rootAlias, enabledFilters);
                // JoinProcessor needs to know if the where clause fragment came from a dynamic filter or not so it
                // can put the where clause fragment in the right place in the SQL AST.   'hasFilterCondition' keeps track
                // of that fact.
                joinFragment.HasFilterCondition = joinFragment.AddCondition(filterCondition);
                AddSubclassJoins(joinFragment, rootAlias, rootJoinable, true, includeAllSubclassJoins);
            }

            var       withClauses = new SqlString[joins.Count];
            IJoinable last        = rootJoinable;

            for (int i = 0; i < joins.Count; i++)
            {
                Join join = joins[i];

                withClauses[i] = GetWithClause(enabledFilters, ref withClauseFragment, join, last);
                last           = join.Joinable;
            }

            if (rootJoinable == null && TableGroupJoinHelper.ProcessAsTableGroupJoin(joins, withClauses, includeAllSubclassJoins, joinFragment, alias => IsIncluded(alias), factory))
            {
                return(joinFragment);
            }

            for (int i = 0; i < joins.Count; i++)
            {
                Join join = joins[i];

                // NH: the variable "condition" have to be a SqlString because it may contains Parameter instances with BackTrack
                joinFragment.AddJoin(
                    join.Joinable.TableName,
                    join.Alias,
                    join.LHSColumns,
                    join.RHSColumns,
                    join.JoinType,
                    withClauses[i]
                    );

                AddSubclassJoins(joinFragment, join.Alias, join.Joinable, join.JoinType == JoinType.InnerJoin, renderSubclassJoins);
            }

            if (next != null)
            {
                joinFragment.AddFragment(next.ToJoinFragment(enabledFilters, includeAllSubclassJoins));
            }
            joinFragment.AddCondition(conditions.ToSqlString());
            if (isFromPart)
            {
                joinFragment.ClearWherePart();
            }
            return(joinFragment);
        }