protected DbAggregateExpression UpdateAggregate(DbAggregateExpression aggregate, Type type, 
     DbAggregateType aggType, Expression arg, bool isDistinct)
 {
     if (type != aggregate.Type || aggType != aggregate.AggregateType || 
         arg != aggregate.Argument || isDistinct != aggregate.IsDistinct)
         return new DbAggregateExpression(type, aggType, arg, isDistinct);
     
     return aggregate;
 }
 protected virtual Expression VisitAggregate(DbAggregateExpression aggregate)
 {
     Expression arg = Visit(aggregate.Argument);
     return UpdateAggregate(aggregate, aggregate.Type, 
         aggregate.AggregateType, arg, aggregate.IsDistinct);
 }
 protected override Expression VisitAggregate(DbAggregateExpression aggregate)
 {
     this.hasAggregate = true;
     return aggregate;
 }
Ejemplo n.º 4
0
        private Expression BindAggregate(Expression source, MethodInfo method, LambdaExpression argument, bool isRoot)
        {
            Type returnType = method.ReturnType;
            DbAggregateType aggType = this.GetAggregateType(method.Name);
            bool hasPredicateArg = this.HasPredicateArg(aggType);
            bool isDistinct = false;
            bool argumentWasPredicate = false;
            bool useAlternateArg = false;

            // check for distinct
            MethodCallExpression mcs = source as MethodCallExpression;
            if (mcs != null && !hasPredicateArg && argument == null)
            {
                if (mcs.Method.Name == "Distinct" && mcs.Arguments.Count == 1 &&
                    (mcs.Method.DeclaringType == typeof(Queryable) || mcs.Method.DeclaringType == typeof(Enumerable))
                    && this.mapping.Language.AllowDistinctInAggregates)
                {
                    source = mcs.Arguments[0];
                    isDistinct = true;
                }
            }

            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;
            }

            DbProjectionExpression 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 || useAlternateArg)
            {
                argExpr = projection.Projector;
            }

            var alias = this.GetNextAlias();
            var pc = this.ProjectColumns(projection.Projector, alias, projection.Select.Alias);
            Expression aggExpr = new DbAggregateExpression(returnType, aggType, argExpr, isDistinct);
            DbSelectExpression select = new DbSelectExpression(alias, new DbColumnDeclaration[] { new DbColumnDeclaration("", aggExpr) }, projection.Select, null);

            if (isRoot)
            {
                ParameterExpression p = Expression.Parameter(typeof(IEnumerable<>).MakeGenericType(aggExpr.Type), "p");
                LambdaExpression gator = Expression.Lambda(Expression.Call(typeof(Enumerable), "Single", new Type[] { returnType }, p), p);
                return new DbProjectionExpression(select, new DbColumnExpression(returnType, null, alias, ""), gator);
            }

            DbScalarExpression subquery = new DbScalarExpression(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 || useAlternateArg)
                {
                    argExpr = info.Element;
                }
                aggExpr = new DbAggregateExpression(returnType, aggType, argExpr, isDistinct);

                // 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 DbAggregateSubqueryExpression(info.Alias, aggExpr, subquery);
            }

            return subquery;
        }
Ejemplo n.º 5
0
 protected override Expression VisitAggregate(DbAggregateExpression aggregate)
 {
     this.Write(GetAggregateName(aggregate.AggregateType));
     this.Write("(");
     if (aggregate.IsDistinct)
     {
         this.Write("DISTINCT ");
     }
     if (aggregate.Argument != null)
     {
         this.VisitValue(aggregate.Argument);
     }
     else if (RequiresAsteriskWhenNoArgument(aggregate.AggregateType))
     {
         this.Write("*");
     }
     this.Write(")");
     return aggregate;
 }
 protected virtual bool CompareAggregate(DbAggregateExpression a, DbAggregateExpression b)
 {
     return (a.AggregateType == b.AggregateType && Compare(a.Argument, b.Argument));
 }