示例#1
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);
        }
示例#2
0
 internal static ProjectionExpression Remove(ProjectionExpression projection, IEnumerable <SelectExpression> selectsToRemove, TextWriter logger)
 {
     return((ProjectionExpression) new SubqueryRemover(selectsToRemove, logger).Visit(projection));
 }
示例#3
0
        protected virtual Expression BindGroupBy(Expression source, LambdaExpression keySelector, LambdaExpression elementSelector, LambdaExpression resultSelector)
        {
            ProjectionExpression projection = this.VisitSequence(source);



            this.map[keySelector.Parameters[0]] = projection.Projector;

            Expression keyExpr = this.Visit(keySelector.Body);

            Expression elemExpr = projection.Projector;

            if (elementSelector != null)
            {
                this.map[elementSelector.Parameters[0]] = projection.Projector;

                elemExpr = this.Visit(elementSelector.Body);
            }



            // Use ProjectColumns to get group-by expressions from key expression

            ProjectedColumns keyProjection = this.ProjectColumns(keyExpr, projection.Source.Alias, projection.Source.Alias);

            IEnumerable <Expression> groupExprs = keyProjection.Columns.Select(c => c.Expression);

            // make duplicate of source query as basis of element subquery by visiting the source again

            ProjectionExpression subqueryBasis = this.VisitSequence(source);

            // recompute key columns for group expressions relative to subquery (need these for doing the correlation predicate)

            this.map[keySelector.Parameters[0]] = subqueryBasis.Projector;

            Expression subqueryKey = this.Visit(keySelector.Body);



            // use same projection trick to get group-by expressions based on subquery

            ProjectedColumns subqueryKeyPC = this.ProjectColumns(subqueryKey, subqueryBasis.Source.Alias, subqueryBasis.Source.Alias);

            IEnumerable <Expression> subqueryGroupExprs = subqueryKeyPC.Columns.Select(c => c.Expression);

            Expression subqueryCorrelation = this.BuildPredicateWithNullsEqual(subqueryGroupExprs, groupExprs);



            // compute element based on duplicated subquery

            Expression subqueryElemExpr = subqueryBasis.Projector;

            if (elementSelector != null)
            {
                this.map[elementSelector.Parameters[0]] = subqueryBasis.Projector;

                subqueryElemExpr = this.Visit(elementSelector.Body);
            }



            // build subquery that projects the desired element

            string elementAlias = this.GetNextAlias();

            ProjectedColumns elementPC = this.ProjectColumns(subqueryElemExpr, elementAlias, subqueryBasis.Source.Alias);

            ProjectionExpression elementSubquery =

                new ProjectionExpression(

                    new SelectExpression(TypeSystem.GetSequenceType(subqueryElemExpr.Type), elementAlias, elementPC.Columns, subqueryBasis.Source, subqueryCorrelation),

                    elementPC.Projector

                    );

            string alias = this.GetNextAlias();

            // make it possible to tie aggregates back to this group-by

            GroupByInfo info = new GroupByInfo(alias, elemExpr);

            this.groupByMap.Add(elementSubquery, info);

            Expression resultExpr;

            if (resultSelector != null)
            {
                Expression saveGroupElement = this.currentGroupElement;

                this.currentGroupElement = elementSubquery;

                // compute result expression based on key & element-subquery

                this.map[resultSelector.Parameters[0]] = keyProjection.Projector;

                this.map[resultSelector.Parameters[1]] = elementSubquery;

                resultExpr = this.Visit(resultSelector.Body);

                this.currentGroupElement = saveGroupElement;
            }

            else
            {
                // result must be IGrouping<K,E>

                resultExpr = Expression.New(

                    typeof(Grouping <,>).MakeGenericType(keyExpr.Type, subqueryElemExpr.Type).GetConstructors()[0],

                    new Expression[] { keyExpr, elementSubquery }

                    );
            }

            ProjectedColumns pc = this.ProjectColumns(resultExpr, alias, projection.Source.Alias);

            // make it possible to tie aggregates back to this group-by

            Expression projectedElementSubquery = ((NewExpression)pc.Projector).Arguments[1];

            this.groupByMap.Add(projectedElementSubquery, info);

            return(new ProjectionExpression(

                       new SelectExpression(TypeSystem.GetSequenceType(resultExpr.Type), alias, pc.Columns, projection.Source, null, null, groupExprs),

                       pc.Projector

                       ));
        }
示例#4
0
 internal static ProjectionExpression Remove(ProjectionExpression projection, TextWriter logger, params SelectExpression[] selectsToRemove)
 {
     return(Remove(projection, (IEnumerable <SelectExpression>)selectsToRemove, logger));
 }