Example #1
0
 protected AggregateExpression UpdateAggregate(AggregateExpression aggregate, Type type, string aggType, Expression arg, bool isDistinct)
 {
     if (type != aggregate.Type || aggType != aggregate.AggregateName || arg != aggregate.Argument || isDistinct != aggregate.IsDistinct)
     {
         return new AggregateExpression(type, aggType, arg, isDistinct);
     }
     return aggregate;
 }
Example #2
0
 protected override Expression VisitAggregate(AggregateExpression aggregate)
 {
     // COUNT(*) forces all fields to be retained in subquery
     if (aggregate.AggregateName == "Count" && aggregate.Argument == null)
     {
         this.retainAllFields = true;
     }
     return base.VisitAggregate(aggregate);
 }
Example #3
0
 protected virtual Expression VisitAggregate(AggregateExpression aggregate)
 {
     var arg = this.Visit(aggregate.Argument);
     return this.UpdateAggregate(aggregate, aggregate.Type, aggregate.AggregateName, arg, aggregate.IsDistinct);
 }
Example #4
0
 protected override Expression VisitAggregate(AggregateExpression aggregate)
 {
     this.hasAggregate = true;
     return aggregate;
 }
Example #5
0
 protected override Expression VisitAggregate(AggregateExpression aggregate)
 {
     this.WriteAggregateName(aggregate.AggregateName);
     this.Write("(");
     if (aggregate.IsDistinct)
     {
         this.Write("DISTINCT ");
     }
     if (aggregate.Argument != null)
     {
         this.VisitValue(aggregate.Argument);
     }
     else if (RequiresAsteriskWhenNoArgument(aggregate.AggregateName))
     {
         this.Write("*");
     }
     this.Write(")");
     return aggregate;
 }
 protected virtual bool CompareAggregate(AggregateExpression a, AggregateExpression b)
 {
     return a.AggregateName == b.AggregateName && this.Compare(a.Argument, b.Argument);
 }
Example #7
0
        protected virtual Expression BindAggregate(Expression source, string aggName, Type returnType, LambdaExpression argument, bool isRoot)
        {
            bool hasPredicateArg = this.language.AggregateArgumentIsPredicate(aggName);
            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.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", new[] { TypeHelper.GetElementType(source.Type) }, 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 || useAlternateArg)
            {
                argExpr = projection.Projector;
            }

            var alias = this.GetNextAlias();
            Expression aggExpr = new AggregateExpression(returnType, aggName, argExpr, isDistinct);
            var colType = this.language.TypeSystem.GetStorageType(returnType);
            SelectExpression select = new SelectExpression(alias, new FieldDeclaration[] { new FieldDeclaration("", aggExpr, colType) }, 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 ProjectionExpression(select, new FieldExpression(
                    returnType,
                    this.language.TypeSystem.GetStorageType(returnType),
                    alias,
                    ""),
                    gator);
            }

            ScalarExpression subquery = new ScalarExpression(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 fields 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 AggregateExpression(returnType, aggName, 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 AggregateSubqueryExpression(info.Alias, aggExpr, subquery);
            }

            return subquery;
        }