protected override Expression VisitJoin(DbJoinExpression join)
        {
            join = (DbJoinExpression)base.VisitJoin(join);

            if (join.Join == DbJoinType.CrossApply || join.Join == DbJoinType.OuterApply)
            {
                if (join.Right is DbTableExpression)
                {
                    return(new DbJoinExpression(DbJoinType.CrossJoin, join.Left, join.Right, null));
                }
                else
                {
                    DbSelectExpression select = join.Right as DbSelectExpression;
                    // Only consider rewriting cross apply if
                    //   1) right side is a select
                    //   2) other than in the where clause in the right-side select, no left-side declared aliases are referenced
                    //   3) and has no behavior that would change semantics if the where clause is removed (like groups, aggregates, take, skip, etc).
                    // Note: it is best to attempt this after redundant subqueries have been removed.
                    if (select != null &&
                        select.Take == null &&
                        select.Skip == null &&
                        !AggregateChecker.HasAggregates(select) &&
                        (select.GroupBy == null || select.GroupBy.Count == 0))
                    {
                        DbSelectExpression     selectWithoutWhere = select.SetWhere(null);
                        HashSet <DbTableAlias> referencedAliases  = ReferencedAliasGatherer.Gather(selectWithoutWhere);
                        HashSet <DbTableAlias> declaredAliases    = DeclaredAliasGatherer.Gather(join.Left);
                        referencedAliases.IntersectWith(declaredAliases);
                        if (referencedAliases.Count == 0)
                        {
                            Expression where = select.Where;
                            select           = selectWithoutWhere;
                            var pc = ColumnProjector.ProjectColumns(this.CanBeColumn, where, select.Columns, select.Alias, DeclaredAliasGatherer.Gather(select.From));
                            select = select.SetColumns(pc.Columns);
                            where  = pc.Projector;
                            DbJoinType jt = (where == null) ? DbJoinType.CrossJoin :
                                            (join.Join == DbJoinType.CrossApply ? DbJoinType.InnerJoin : DbJoinType.LeftOuter);
                            return(new DbJoinExpression(jt, join.Left, select, where));
                        }
                    }
                }
            }

            return(join);
        }
예제 #2
0
        protected override Expression VisitSelect(DbSelectExpression select)
        {
            select = (DbSelectExpression)base.VisitSelect(select);
            if (select.Skip != null)
            {
                DbSelectExpression newSelect = select.SetSkip(null).SetTake(null);
                bool canAddColumn            = !select.IsDistinct && (select.GroupBy == null || select.GroupBy.Count == 0);
                if (!canAddColumn)
                {
                    newSelect = newSelect.AddRedundantSelect(new DbTableAlias());
                }
                newSelect = newSelect.AddColumn(new DbColumnDeclaration("rownum", new DbRowNumberExpression(select.OrderBy)));

                // add layer for WHERE clause that references new rownum column
                newSelect = newSelect.AddRedundantSelect(new DbTableAlias());
                newSelect = newSelect.RemoveColumn(newSelect.Columns.Single(c => c.Name == "rownum"));

                var newAlias             = ((DbSelectExpression)newSelect.From).Alias;
                DbColumnExpression rnCol = new DbColumnExpression(typeof(int), null, newAlias, "rownum");
                Expression where;
                if (select.Take != null)
                {
                    where = new DbBetweenExpression(rnCol, Expression.Add(select.Skip, Expression.Constant(1)),
                                                    Expression.Add(select.Skip, select.Take));
                }
                else
                {
                    where = rnCol.GreaterThan(select.Skip);
                }
                if (newSelect.Where != null)
                {
                    where = newSelect.Where.And(where);
                }
                newSelect = newSelect.SetWhere(where);

                select = newSelect;
            }
            return(select);
        }