Inheritance: Shaolinq.Persistence.Linq.Expressions.SqlExpressionVisitor
        protected override Expression VisitJoin(SqlJoinExpression join)
        {
            join = (SqlJoinExpression)base.VisitJoin(join);

            if (join.JoinType == SqlJoinType.Cross && this.currentWhere != null)
            {
                var declaredLeft  = SqlDeclaredAliasGatherer.Gather(join.Left);
                var declaredRight = SqlDeclaredAliasGatherer.Gather(join.Right);
                var declared      = new HashSet <string>(declaredLeft.Union(declaredRight));
                var exprs         = this.currentWhere.Split(ExpressionType.And, ExpressionType.AndAlso);
                var good          = exprs.Where(e => CanBeJoinCondition(e, declaredLeft, declaredRight, declared)).ToList();

                if (good.Count > 0)
                {
                    var condition = good.Join(ExpressionType.And);

                    join = this.UpdateJoin(join, SqlJoinType.Inner, join.Left, join.Right, condition);

                    var newWhere = exprs.Where(e => !good.Contains(e)).Join(ExpressionType.And);
                    this.currentWhere = newWhere;
                }
            }

            return(join);
        }
        public static HashSet <string> Gather(Expression source)
        {
            var gatherer = new SqlDeclaredAliasGatherer();

            gatherer.Visit(source);

            return(gatherer.aliases);
        }
		public static HashSet<string> Gather(Expression source)
		{
			var gatherer = new SqlDeclaredAliasGatherer();

			gatherer.Visit(source);

			return gatherer.aliases;
		}
        protected override Expression VisitJoin(SqlJoinExpression join)
        {
            join = (SqlJoinExpression)base.VisitJoin(join);

            if (join.JoinType == SqlJoinType.CrossApply || join.JoinType == SqlJoinType.OuterApply)
            {
                if (join.Right is SqlTableExpression)
                {
                    return(new SqlJoinExpression(join.Type, SqlJoinType.Cross, join.Left, join.Right, null));
                }
                else
                {
                    var select = join.Right as SqlSelectExpression;

                    if (select != null && select.Take == null && select.Skip == null && !SqlAggregateChecker.HasAggregates(select) && (select.GroupBy == null || select.GroupBy.Count == 0))
                    {
                        var selectWithoutWhere = select.ChangeWhere(null);
                        var referencedAliases  = SqlReferencedAliasGatherer.Gather(selectWithoutWhere);
                        var declaredAliases    = SqlDeclaredAliasGatherer.Gather(join.Left);

                        referencedAliases.IntersectWith(declaredAliases);

                        if (referencedAliases.Count == 0)
                        {
                            var where = select.Where;

                            select = selectWithoutWhere;

                            var pc = ColumnProjector.ProjectColumns(new Nominator(Nominator.CanBeColumn), where, select.Columns, select.Alias, SqlDeclaredAliasGatherer.Gather(select.From));

                            select = select.ChangeColumns(pc.Columns);
                            where  = pc.Projector;

                            var joinType = (where == null) ? SqlJoinType.Cross : (join.JoinType == SqlJoinType.CrossApply ? SqlJoinType.Inner : SqlJoinType.Left);

                            return(new SqlJoinExpression(typeof(void), joinType, join.Left, select, where));
                        }
                    }
                }
            }

            return(join);
        }