protected virtual Expression BindOrderBy(Type resultType, Expression source, LambdaExpression orderSelector, OrderType orderType) { List <OrderExpression> myThenBys = this.thenBys; this.thenBys = null; ProjectionExpression projection = this.VisitSequence(source); this.map[orderSelector.Parameters[0]] = projection.Projector; List <OrderExpression> orderings = new List <OrderExpression>(); orderings.Add(new OrderExpression(orderType, this.Visit(orderSelector.Body))); if (myThenBys != null) { for (int i = myThenBys.Count - 1; i >= 0; i--) { OrderExpression tb = myThenBys[i]; LambdaExpression lambda = (LambdaExpression)tb.Expression; this.map[lambda.Parameters[0]] = projection.Projector; orderings.Add(new OrderExpression(tb.OrderType, this.Visit(lambda.Body))); } } var alias = this.GetNextAlias(); ProjectedColumns pc = this.ProjectColumns(projection.Projector, alias, projection.Select.Alias); return(new ProjectionExpression(new SelectExpression(alias, pc.Columns, projection.Select, null, orderings.AsReadOnly(), null), pc.Projector)); }
private Expression BindFirst(Expression source, LambdaExpression predicate, string kind, bool isRoot) { ProjectionExpression projection = this.VisitSequence(source); Expression where = null; if (predicate != null) { this.map[predicate.Parameters[0]] = projection.Projector; where = this.Visit(predicate.Body); } bool isFirst = kind.StartsWith("First"); bool isLast = kind.StartsWith("Last"); Expression take = (isFirst || isLast) ? Expression.Constant(1) : null; if (take != null || where != null) { var alias = this.GetNextAlias(); ProjectedColumns pc = this.ProjectColumns(projection.Projector, alias, projection.Select.Alias); projection = new ProjectionExpression(new SelectExpression(alias, pc.Columns, projection.Select, where, null, null, false, null, take, isLast), pc.Projector); } if (isRoot) { Type elementType = projection.Projector.Type; ParameterExpression p = Expression.Parameter(typeof(IEnumerable <>).MakeGenericType(elementType), "p"); LambdaExpression gator = Expression.Lambda(Expression.Call(typeof(Enumerable), kind, new Type[] { elementType }, p), p); return(new ProjectionExpression(projection.Select, projection.Projector, gator)); } return(projection); }
private Expression BindDistinct(Expression source) { ProjectionExpression projection = this.VisitSequence(source); var alias = this.GetNextAlias(); ProjectedColumns pc = this.ProjectColumns(projection.Projector, alias, projection.Select.Alias); return(new ProjectionExpression(new SelectExpression(alias, pc.Columns, projection.Select, null, null, null, true, null, null, false), pc.Projector)); }
private Expression BindSelect(Type resultType, Expression source, LambdaExpression selector) { ProjectionExpression projection = this.VisitSequence(source); this.map[selector.Parameters[0]] = projection.Projector; Expression expression = this.Visit(selector.Body); var alias = this.GetNextAlias(); ProjectedColumns pc = this.ProjectColumns(expression, alias, projection.Select.Alias); return(new ProjectionExpression(new SelectExpression(alias, pc.Columns, projection.Select, null), pc.Projector)); }
private Expression BindWhere(Type resultType, Expression source, LambdaExpression predicate) { ProjectionExpression projection = this.VisitSequence(source); this.map[predicate.Parameters[0]] = projection.Projector; Expression where = this.Visit(predicate.Body); var alias = this.GetNextAlias(); ProjectedColumns pc = this.ProjectColumns(projection.Projector, alias, projection.Select.Alias); return(new ProjectionExpression(new SelectExpression(alias, pc.Columns, projection.Select, where), pc.Projector)); }
protected virtual Expression BindIntersect(Expression outerSource, Expression innerSource, bool negate) { ProjectionExpression outerProjection = this.VisitSequence(outerSource); ProjectionExpression innerProjection = this.VisitSequence(innerSource); Expression exists = new ExistsExpression(new SelectExpression(new TableAlias(), null, innerProjection.Select, innerProjection.Projector.Equal(outerProjection.Projector))); if (negate) { exists = Expression.Not(exists); } var alias = this.GetNextAlias(); ProjectedColumns pc = this.ProjectColumns(outerProjection.Projector, alias, outerProjection.Select.Alias); return(new ProjectionExpression(new SelectExpression(alias, pc.Columns, outerProjection.Select, exists), pc.Projector, outerProjection.Aggregator)); }
protected virtual Expression BindJoin(Type resultType, Expression outerSource, Expression innerSource, LambdaExpression outerKey, LambdaExpression innerKey, LambdaExpression resultSelector) { ProjectionExpression outerProjection = this.VisitSequence(outerSource); ProjectionExpression innerProjection = this.VisitSequence(innerSource); this.map[outerKey.Parameters[0]] = outerProjection.Projector; Expression outerKeyExpr = this.Visit(outerKey.Body); this.map[innerKey.Parameters[0]] = innerProjection.Projector; Expression innerKeyExpr = this.Visit(innerKey.Body); this.map[resultSelector.Parameters[0]] = outerProjection.Projector; this.map[resultSelector.Parameters[1]] = innerProjection.Projector; Expression resultExpr = this.Visit(resultSelector.Body); JoinExpression join = new JoinExpression(JoinType.InnerJoin, outerProjection.Select, innerProjection.Select, outerKeyExpr.Equal(innerKeyExpr)); var alias = this.GetNextAlias(); ProjectedColumns pc = this.ProjectColumns(resultExpr, alias, outerProjection.Select.Alias, innerProjection.Select.Alias); return(new ProjectionExpression(new SelectExpression(alias, pc.Columns, join, null), pc.Projector)); }
protected virtual Expression BindGroupJoin(MethodInfo groupJoinMethod, Expression outerSource, Expression innerSource, LambdaExpression outerKey, LambdaExpression innerKey, LambdaExpression resultSelector) { // A database will treat this no differently than a SelectMany w/ result selector, so just use that translation instead Type[] args = groupJoinMethod.GetGenericArguments(); ProjectionExpression outerProjection = this.VisitSequence(outerSource); this.map[outerKey.Parameters[0]] = outerProjection.Projector; var predicateLambda = Expression.Lambda(innerKey.Body.Equal(outerKey.Body), innerKey.Parameters[0]); var callToWhere = Expression.Call(typeof(Enumerable), "Where", new Type[] { args[1] }, innerSource, predicateLambda); Expression group = this.Visit(callToWhere); this.map[resultSelector.Parameters[0]] = outerProjection.Projector; this.map[resultSelector.Parameters[1]] = group; Expression resultExpr = this.Visit(resultSelector.Body); var alias = this.GetNextAlias(); ProjectedColumns pc = this.ProjectColumns(resultExpr, alias, outerProjection.Select.Alias); return(new ProjectionExpression(new SelectExpression(alias, pc.Columns, outerProjection.Select, null), pc.Projector)); }
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.Select.Alias, projection.Select.Alias); var groupExprs = keyProjection.Columns.Select(c => c.Expression).ToArray(); // 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.Select.Alias, subqueryBasis.Select.Alias); var subqueryGroupExprs = subqueryKeyPC.Columns.Select(c => c.Expression).ToArray(); 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 var elementAlias = this.GetNextAlias(); ProjectedColumns elementPC = this.ProjectColumns(subqueryElemExpr, elementAlias, subqueryBasis.Select.Alias); ProjectionExpression elementSubquery = new ProjectionExpression(new SelectExpression(elementAlias, elementPC.Columns, subqueryBasis.Select, subqueryCorrelation), elementPC.Projector); var 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 }); resultExpr = Expression.Convert(resultExpr, typeof(IGrouping <,>).MakeGenericType(keyExpr.Type, subqueryElemExpr.Type)); } ProjectedColumns pc = this.ProjectColumns(resultExpr, alias, projection.Select.Alias); // make it possible to tie aggregates back to this group-by NewExpression newResult = this.GetNewExpression(pc.Projector); if (newResult != null && newResult.Type.IsGenericType && newResult.Type.GetGenericTypeDefinition() == typeof(Grouping <,>)) { Expression projectedElementSubquery = newResult.Arguments[1]; this.groupByMap.Add(projectedElementSubquery, info); } return(new ProjectionExpression(new SelectExpression(alias, pc.Columns, projection.Select, null, null, groupExprs), pc.Projector)); }