private Expression BindJoin(MethodCallExpression call) { Expression outerSource = call.Arguments[0]; Expression innerSource = call.Arguments[1]; LambdaExpression outerKey = GetLambda(call.Arguments[2]); LambdaExpression innerKey = GetLambda(call.Arguments[3]); LambdaExpression resultSelector = GetLambda(call.Arguments[4]); ProjectionExpression outerProjection = VisitSequence(outerSource); ProjectionExpression innerProjection = VisitSequence(innerSource); _map[outerKey.Parameters[0]] = outerProjection.Projector; Expression outerKeyExpr = Visit(outerKey.Body); _map[innerKey.Parameters[0]] = innerProjection.Projector; Expression innerKeyExpr = Visit(innerKey.Body); _map[resultSelector.Parameters[0]] = outerProjection.Projector; _map[resultSelector.Parameters[1]] = innerProjection.Projector; Expression resultExpr = Visit(resultSelector.Body); string alias = GetNewAlias(); ProjectedColumns pc = ProjectColumns(resultExpr, alias, outerProjection.Source.Alias, innerProjection.Source.Alias); return(new ProjectionExpression( new SelectExpression( alias, pc.Columns, new JoinExpression(JoinType.InnerJoin, outerProjection.Source, innerProjection.Source, Expression.Equal(outerKeyExpr, innerKeyExpr)) ), pc.Projector )); }
private Expression BindDistinct(MethodCallExpression call) { Expression source = call.Arguments[0]; ProjectionExpression projection = VisitSequence(source); var alias = GetNewAlias(); ProjectedColumns pc = ProjectColumns(projection.Projector, alias, projection.Source.Alias); return(new ProjectionExpression( new SelectExpression(alias, pc.Columns, projection.Source, isDistinct: true), pc.Projector )); }
private Expression BindElementAt(MethodCallExpression call) { Expression source = call.Arguments[0]; Expression index = call.Arguments[1]; ProjectionExpression projection = VisitSequence(source); string alias = GetNewAlias(); ProjectedColumns pc = ProjectColumns(projection.Projector, alias, projection.Source.Alias); return(HandleAggregate( call, new SelectExpression(alias, pc.Columns, projection.Source, offset: Visit(index), limit: Expression.Constant(1)), pc.Projector)); }
private Expression BindSkip(MethodCallExpression call) { Expression source = call.Arguments[0]; Expression skip = call.Arguments[1]; ProjectionExpression projection = VisitSequence(source); Expression visitedSkip = Visit(skip); var alias = GetNewAlias(); ProjectedColumns pc = ProjectColumns(projection.Projector, alias, projection.Source.Alias); return(new ProjectionExpression( new SelectExpression(alias, pc.Columns, projection.Source, offset: visitedSkip), pc.Projector )); }
private Expression BindWhere(MethodCallExpression call) { Expression source = call.Arguments[0]; LambdaExpression predicate = GetLambda(call.Arguments[1]); ProjectionExpression projection = VisitSequence(source); _map[predicate.Parameters[0]] = projection.Projector; Expression where = Visit(predicate.Body); string alias = GetNewAlias(); ProjectedColumns pc = ProjectColumns(projection.Projector, alias, projection.Source.Alias); return(new ProjectionExpression( new SelectExpression(alias, pc.Columns, projection.Source, where), pc.Projector )); }
private Expression BindOrderBy(MethodCallExpression call) { Expression source = call.Arguments[0]; LambdaExpression orderSelector = GetLambda(call.Arguments[1]); OrderType orderType = call.Method.Name.EndsWith("Descending") ? OrderType.Descending : OrderType.Ascending; List <OrderExpression> myThenBys = _thenBys; _thenBys = null; ProjectionExpression projection = VisitSequence(source); _map[orderSelector.Parameters[0]] = projection.Projector; List <OrderExpression> orderings = new List <OrderExpression> { new OrderExpression(orderType, Visit(orderSelector.Body)) }; if (myThenBys != null) { for (int i = myThenBys.Count - 1; i >= 0; i--) { OrderExpression tb = myThenBys[i]; LambdaExpression lambda = (LambdaExpression)tb.Expression; _map[lambda.Parameters[0]] = projection.Projector; orderings.Add(new OrderExpression(tb.OrderType, Visit(lambda.Body))); } } string alias = GetNewAlias(); ProjectedColumns pc = ProjectColumns(projection.Projector, alias, projection.Source.Alias); return(new ProjectionExpression( new SelectExpression( alias, pc.Columns, projection.Source, orderBy: orderings.AsReadOnly() ), pc.Projector )); }
private Expression BindSingle(MethodCallExpression call) { Expression source = call.Arguments[0]; LambdaExpression predicate = call.Arguments.Count == 2 ? GetLambda(call.Arguments[1]) : null; ProjectionExpression projection = VisitSequence(source); if (predicate != null) { _map[predicate.Parameters[0]] = projection.Projector; Expression where = Visit(predicate.Body); string alias = GetNewAlias(); ProjectedColumns pc = ProjectColumns(projection.Projector, alias, projection.Source.Alias); return(HandleAggregate( call, new SelectExpression(alias, pc.Columns, projection.Source, where), pc.Projector )); } else { return(HandleAggregate(call, projection.Source, projection.Projector)); } }
private Expression BindGroupJoin(MethodCallExpression call) { Expression outerSource = call.Arguments[0]; Expression innerSource = call.Arguments[1]; LambdaExpression outerKey = GetLambda(call.Arguments[2]); LambdaExpression innerKey = GetLambda(call.Arguments[3]); LambdaExpression resultSelector = GetLambda(call.Arguments[4]); ProjectionExpression outerProjection = VisitSequence(outerSource); ProjectionExpression innerProjection = VisitSequence(innerSource); _map[outerKey.Parameters[0]] = outerProjection.Projector; Expression outerKeyExpr = Visit(outerKey.Body); _map[innerKey.Parameters[0]] = innerProjection.Projector; Expression innerKeyExpr = Visit(innerKey.Body); LambdaExpression predicate = Expression.Lambda(Expression.Equal(innerKey.Body, outerKey.Body), innerKey.Parameters[0]); Expression subquery = Expression.Call(typeof(Queryable), nameof(Queryable.Where), new[] { innerKey.Parameters[0].Type }, innerSource, predicate); _map[resultSelector.Parameters[0]] = outerProjection.Projector; _map[resultSelector.Parameters[1]] = Visit(subquery); Expression resultExpr = Visit(resultSelector.Body); JoinExpression join = new JoinExpression(JoinType.InnerJoin, outerProjection.Source, innerProjection.Source, Expression.Equal(outerKeyExpr, innerKeyExpr)); var groupedColumns = ProjectColumns(outerKeyExpr, outerProjection.Source.Alias, outerProjection.Source.Alias); IEnumerable <Expression> groupExprs = groupedColumns.Columns.Select(c => c.Expression); string alias = GetNewAlias(); ProjectedColumns pc = ProjectColumns(resultExpr, alias, outerProjection.Source.Alias, innerProjection.Source.Alias); return(new ProjectionExpression( new SelectExpression(alias, pc.Columns, join, groupBy: groupExprs), pc.Projector )); }
private Expression BindGroupBy(MethodCallExpression call) { Expression source = call.Arguments[0]; LambdaExpression keySelector = GetLambda(call.Arguments[1]); LambdaExpression elementSelector = null; LambdaExpression resultSelector = null; switch (call.Arguments.Count) { case 3: LambdaExpression lambda2 = GetLambda(call.Arguments[2]); switch (lambda2.Parameters.Count) { case 1: // second lambda is element selector elementSelector = lambda2; break; case 2: // second lambda is result selector resultSelector = lambda2; break; } break; case 4: elementSelector = GetLambda(call.Arguments[2]); resultSelector = GetLambda(call.Arguments[3]); break; } ProjectionExpression projection = VisitSequence(source); _map[keySelector.Parameters[0]] = projection.Projector; Expression keyExpr = Visit(keySelector.Body); // Use ProjectColumns to get group-by expressions from key expression ProjectedColumns keyProjection = ProjectColumns(keyExpr, projection.Source.Alias, projection.Source.Alias); IList <Expression> groupExprs = keyProjection.Columns.Select(c => c.Expression).ToList(); // 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 ProjectedColumns subqueryKeyProjection = ProjectColumns(subqueryKey, subqueryBasis.Source.Alias, subqueryBasis.Source.Alias); Expression subqueryCorrelation = subqueryKeyProjection.Columns.Select(c => c.Expression).Zip(groupExprs, Expression.Equal).Aggregate(Expression.AndAlso); // 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 string elementAlias = GetNewAlias(); ProjectedColumns elementProjection = ProjectColumns(subqueryElemExpr, elementAlias, subqueryBasis.Source.Alias); ProjectionExpression elementSubquery = new ProjectionExpression( new SelectExpression( elementAlias, elementProjection.Columns, subqueryBasis.Source, subqueryCorrelation ), elementProjection.Projector ); string alias = GetNewAlias(); Expression resultExpr; if (resultSelector != null) // compute result expression based on key & element-subquery { _map[resultSelector.Parameters[0]] = keyProjection.Projector; _map[resultSelector.Parameters[1]] = elementSubquery; resultExpr = Visit(resultSelector.Body); } else // result must be IGrouping<K,E> { Type groupingType = typeof(Grouping <,>).MakeGenericType(keyExpr.Type, subqueryElemExpr.Type); resultExpr = Expression.New(groupingType.GetTypeInfo().DeclaredConstructors.First(), keyExpr, elementSubquery); } ProjectedColumns pc = ProjectColumns(resultExpr, alias, projection.Source.Alias); return(new ProjectionExpression( new SelectExpression( alias, pc.Columns, projection.Source, groupBy: groupExprs ), pc.Projector )); }