protected override Expression VisitAggregate(AggregateExpression aggregate)
 {
     sb.Append(GetAggregateName(aggregate.AggregateType));
     sb.Append("(");
     if (aggregate.Argument != null)
     {
         this.Visit(aggregate.Argument);
     }
     else if (RequiresAsteriskWhenNoArgument(aggregate.AggregateType))
     {
         sb.Append("*");
     }
     sb.Append(")");
     return(aggregate);
 }
示例#2
0
        private Expression BindAggregate(Expression source, MethodInfo method, LambdaExpression argument, bool isRoot)
        {
            Type          returnType           = method.ReturnType;
            AggregateType aggType              = this.GetAggregateType(method.Name);
            bool          hasPredicateArg      = this.HasPredicateArg(aggType);
            bool          argumentWasPredicate = false;

            if (argument != null && hasPredicateArg)
            {
                // convert query.Count(predicate) into query.Where(predicate).Count()
                source               = Expression.Call(typeof(Queryable), "Where", method.GetGenericArguments(), source, argument);
                argument             = null;
                argumentWasPredicate = true;
            }

            ProjectionExpression projection = this.VisitSequence(source);

            Expression argExpr = null;

            if (argument != null)
            {
                this.map[argument.Parameters[0]] = projection.Projector;
                argExpr = this.Visit(argument.Body);
            }
            else if (!hasPredicateArg)
            {
                argExpr = projection.Projector;
            }

            string           alias      = this.GetNextAlias();
            var              pc         = this.ProjectColumns(projection.Projector, alias, projection.Source.Alias);
            Expression       aggExpr    = new AggregateExpression(returnType, aggType, argExpr);
            Type             selectType = typeof(IEnumerable <>).MakeGenericType(returnType);
            SelectExpression select     = new SelectExpression(selectType, alias, new ColumnDeclaration[] { new ColumnDeclaration("", aggExpr) }, projection.Source, null);

            if (isRoot)
            {
                ParameterExpression p     = Expression.Parameter(selectType, "p");
                LambdaExpression    gator = Expression.Lambda(Expression.Call(typeof(Enumerable), "Single", new Type[] { returnType }, p), p);
                return(new ProjectionExpression(select, new ColumnExpression(returnType, alias, ""), gator));
            }

            SubqueryExpression subquery = new SubqueryExpression(returnType, select);

            // if we can find the corresponding group-info we can build a special AggregateSubquery node that will enable us to
            // optimize the aggregate expression later using AggregateRewriter
            GroupByInfo info;

            if (!argumentWasPredicate && this.groupByMap.TryGetValue(projection, out info))
            {
                // use the element expression from the group-by info to rebind the argument so the resulting expression is one that
                // would be legal to add to the columns in the select expression that has the corresponding group-by clause.
                if (argument != null)
                {
                    this.map[argument.Parameters[0]] = info.Element;
                    argExpr = this.Visit(argument.Body);
                }
                else if (!hasPredicateArg)
                {
                    argExpr = info.Element;
                }
                aggExpr = new AggregateExpression(returnType, aggType, argExpr);

                // check for easy to optimize case.  If the projection that our aggregate is based on is really the 'group' argument from
                // the query.GroupBy(xxx, (key, group) => yyy) method then whatever expression we return here will automatically
                // become part of the select expression that has the group-by clause, so just return the simple aggregate expression.
                if (projection == this.currentGroupElement)
                {
                    return(aggExpr);
                }

                return(new AggregateSubqueryExpression(info.Alias, aggExpr, subquery));
            }

            return(subquery);
        }