コード例 #1
0
        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
                       ));
        }
コード例 #2
0
        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
                       ));
        }
コード例 #3
0
        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));
        }
コード例 #4
0
        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
                       ));
        }
コード例 #5
0
        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
                       ));
        }
コード例 #6
0
        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
                       ));
        }
コード例 #7
0
        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));
            }
        }
コード例 #8
0
        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
                       ));
        }
コード例 #9
0
        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
                       ));
        }