protected override Expression VisitProjection(ProjectionExpression node) { // visit mapping in reverse order Expression projector = Visit(node.Projector); var source = (SelectExpression) Visit(node.Source); if (projector != node.Projector || source != node.Source) { return new ProjectionExpression(source, projector, node.Aggregator); } return node; }
protected override Expression VisitProjection(ProjectionExpression node) { node = (ProjectionExpression) base.VisitProjection(node); if (node.Source.From is SelectExpression) { List<SelectExpression> redundant = RedundantSubqueryGatherer.Gather(node.Source); if (redundant != null) { node = SubqueryRemover.Remove(node, redundant); } } return node; }
protected virtual Expression VisitProjection(ProjectionExpression node) { var source = (SelectExpression) Visit(node.Source); Expression projector = Visit(node.Projector); if (source != node.Source || projector != node.Projector) { return new ProjectionExpression(source, projector); } return node; }
private Expression BindGroupBy(Expression source, LambdaExpression keySelector, LambdaExpression elementSelector, LambdaExpression resultSelector) { ProjectionExpression projection = VisitSequence(source); _map[keySelector.Parameters[0]] = projection.Projector; Expression keyExpr = Visit(keySelector.Body); Expression elemExpr = projection.Projector; if (elementSelector != null) { _map[elementSelector.Parameters[0]] = projection.Projector; elemExpr = Visit(elementSelector.Body); } // Use ProjectColumns to get group-by expressions from key expression ProjectedColumns keyProjection = 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 = VisitSequence(source); // recompute key _columns for group expressions relative to subquery (need these for doing the correlation predicate) _map[keySelector.Parameters[0]] = subqueryBasis.Projector; Expression subqueryKey = Visit(keySelector.Body); // use same projection trick to get group-by expressions based on subquery var subqueryKeyPc = ProjectColumns(subqueryKey, subqueryBasis.Source.Alias, subqueryBasis.Source.Alias); IEnumerable<Expression> subqueryGroupExprs = subqueryKeyPc.Columns.Select(c => c.Expression); Expression subqueryCorrelation = BuildPredicateWithNullsEqual(subqueryGroupExprs, groupExprs); // compute element based on duplicated subquery Expression subqueryElemExpr = subqueryBasis.Projector; if (elementSelector != null) { _map[elementSelector.Parameters[0]] = subqueryBasis.Projector; subqueryElemExpr = Visit(elementSelector.Body); } // build subquery that projects the desired element SourceAlias elementAlias = GetNextAlias(); ProjectedColumns elementPc = ProjectColumns(subqueryElemExpr, elementAlias, subqueryBasis.Source.Alias); var elementSubquery = new ProjectionExpression( new SelectExpression(elementAlias, elementPc.Columns, subqueryBasis.Source, subqueryCorrelation), elementPc.Projector ); SourceAlias alias = GetNextAlias(); // make it possible to tie _aggregates back to this group-by var info = new GroupByInfo(alias, elemExpr); _groupByMap.Add(elementSubquery, info); Expression resultExpr; if (resultSelector != null) { Expression saveGroupElement = _currentGroupElement; _currentGroupElement = elementSubquery; // compute result expression based on key & element-subquery _map[resultSelector.Parameters[0]] = keyProjection.Projector; _map[resultSelector.Parameters[1]] = elementSubquery; resultExpr = Visit(resultSelector.Body); _currentGroupElement = saveGroupElement; } else { // result must be IGrouping<K,E> resultExpr = Expression.New( typeof (Grouping<,>).MakeGenericType(keyExpr.Type, subqueryElemExpr.Type).GetConstructors()[0], new[] {keyExpr, elementSubquery} ); } ProjectedColumns pc = ProjectColumns(resultExpr, alias, projection.Source.Alias); // make it possible to tie _aggregates back to this group-by //Expression projectedElementSubquery = ((NewExpression)pc.Projector).Arguments[1]; //_groupByMap.Add(projectedElementSubquery, info); return new ProjectionExpression( new SelectExpression(alias, pc.Columns, projection.Source, null, null, groupExprs), pc.Projector ); }
internal static ProjectionExpression Remove(ProjectionExpression projection, IEnumerable<SelectExpression> selectsToRemove) { return (ProjectionExpression) new SubqueryRemover(selectsToRemove).Visit(projection); }