示例#1
0
        private Expression LiftSubQuery(
            IQuerySource querySource, Expression itemsExpression, QueryModel queryModel, Expression expression)
        {
            SelectExpression subSelectExpression;

            if (_subqueriesBySource.TryGetValue(querySource, out subSelectExpression) &&
                (!subSelectExpression.OrderBy.Any() ||
                 subSelectExpression.Limit != null))
            {
                subSelectExpression.PushDownSubquery().QuerySource = querySource;

                AddQuery(querySource, subSelectExpression);

                _subqueriesBySource.Remove(querySource);

                var shapedQueryMethodExpression
                    = new ShapedQueryFindingExpressionVisitor(QueryCompilationContext)
                      .Find(expression);

                var shaperLambda     = (LambdaExpression)shapedQueryMethodExpression.Arguments[2];
                var shaperMethodCall = (MethodCallExpression)shaperLambda.Body;

                var shaperMethod     = shaperMethodCall.Method;
                var shaperMethodArgs = shaperMethodCall.Arguments.ToList();

                if (!QueryCompilationContext.QuerySourceRequiresMaterialization(querySource) &&
                    shaperMethod.MethodIsClosedFormOf(RelationalEntityQueryableExpressionVisitor.CreateEntityMethodInfo))
                {
                    shaperMethod = RelationalEntityQueryableExpressionVisitor.CreateValueBufferMethodInfo;
                    shaperMethodArgs.RemoveRange(5, 5);
                }
                else
                {
                    subSelectExpression.ExplodeStarProjection();
                }

                var innerQuerySource = (IQuerySource)((ConstantExpression)shaperMethodArgs[0]).Value;

                foreach (var queryAnnotation
                         in QueryCompilationContext.QueryAnnotations
                         .Where(qa => qa.QuerySource == innerQuerySource))
                {
                    queryAnnotation.QuerySource = querySource;
                }

                shaperMethodArgs[0] = Expression.Constant(querySource);

                var querySourceReferenceExpression
                    = queryModel.SelectClause.Selector as QuerySourceReferenceExpression;

                if (querySourceReferenceExpression != null &&
                    querySourceReferenceExpression.ReferencedQuerySource == querySource)
                {
                    var subQueryModel = (itemsExpression as SubQueryExpression)?.QueryModel;

                    if (subQueryModel != null)
                    {
                        queryModel.SelectClause.Selector = subQueryModel.SelectClause.Selector;

                        QueryCompilationContext.QuerySourceMapping
                        .ReplaceMapping(
                            subQueryModel.MainFromClause,
                            QueryResultScope.GetResult(
                                QueryResultScopeParameter,
                                querySource,
                                shaperMethod.ReturnType.GenericTypeArguments[0]));
                    }
                }

                return(Expression.Call(
                           QueryCompilationContext.QueryMethodProvider.ShapedQueryMethod
                           .MakeGenericMethod(shaperMethod.ReturnType),
                           shapedQueryMethodExpression.Arguments[0],
                           shapedQueryMethodExpression.Arguments[1],
                           Expression.Lambda(
                               Expression.Call(shaperMethod, shaperMethodArgs),
                               shaperLambda.Parameters[0])));
            }

            return(expression);
        }
示例#2
0
        public override void VisitJoinClause(JoinClause joinClause, QueryModel queryModel, int index)
        {
            Check.NotNull(joinClause, nameof(joinClause));
            Check.NotNull(queryModel, nameof(queryModel));

            var previousQuerySource = FindPreviousQuerySource(queryModel, index);

            var previousSelectExpression
                = previousQuerySource != null
                    ? TryGetQuery(previousQuerySource)
                    : null;

            var previousSelectProjectionCount
                = previousSelectExpression?.Projection.Count ?? -1;

            base.VisitJoinClause(joinClause, queryModel, index);

            if (previousSelectExpression != null)
            {
                var selectExpression = TryGetQuery(joinClause);

                if (selectExpression != null)
                {
                    var filteringExpressionVisitor
                        = new SqlTranslatingExpressionVisitor(this, targetSelectExpression: null);

                    var predicate
                        = filteringExpressionVisitor
                          .Visit(
                              Expression.Equal(
                                  joinClause.OuterKeySelector,
                                  joinClause.InnerKeySelector));

                    if (predicate != null)
                    {
                        _queriesBySource.Remove(joinClause);

                        previousSelectExpression.RemoveRangeFromProjection(previousSelectProjectionCount);

                        var innerJoinExpression
                            = previousSelectExpression
                              .AddInnerJoin(
                                  selectExpression.Tables.Single(),
                                  QueryCompilationContext
                                  .QuerySourceRequiresMaterialization(joinClause)
                                        ? selectExpression.Projection
                                        : Enumerable.Empty <Expression>());

                        innerJoinExpression.Predicate = predicate;

                        Expression
                            = new QueryFlatteningExpressionVisitor(
                                  previousQuerySource,
                                  joinClause,
                                  QueryCompilationContext,
                                  previousSelectProjectionCount,
                                  LinqOperatorProvider.Join)
                              .Visit(Expression);
                    }
                    else
                    {
                        previousSelectExpression.RemoveRangeFromProjection(previousSelectProjectionCount);
                    }
                }
            }
        }
示例#3
0
        protected virtual void OptimizeJoinClause(
            [NotNull] JoinClause joinClause,
            [NotNull] QueryModel queryModel,
            int index,
            [NotNull] Action baseVisitAction,
            [NotNull] MethodInfo operatorToFlatten,
            bool outerJoin = false)
        {
            Check.NotNull(joinClause, nameof(joinClause));
            Check.NotNull(queryModel, nameof(queryModel));
            Check.NotNull(baseVisitAction, nameof(baseVisitAction));
            Check.NotNull(operatorToFlatten, nameof(operatorToFlatten));

            var previousQuerySource = FindPreviousQuerySource(queryModel, index);

            var previousSelectExpression
                = previousQuerySource != null
                    ? TryGetQuery(previousQuerySource)
                    : null;

            var previousSelectProjectionCount
                = previousSelectExpression?.Projection.Count ?? -1;

            baseVisitAction();

            if (previousSelectExpression != null)
            {
                var selectExpression = TryGetQuery(joinClause);

                if (selectExpression != null)
                {
                    var sqlTranslatingExpressionVisitor = new SqlTranslatingExpressionVisitor(this);

                    var predicate
                        = sqlTranslatingExpressionVisitor
                          .Visit(
                              Expression.Equal(
                                  joinClause.OuterKeySelector,
                                  joinClause.InnerKeySelector));

                    if (predicate != null)
                    {
                        _queriesBySource.Remove(joinClause);

                        previousSelectExpression.RemoveRangeFromProjection(previousSelectProjectionCount);

                        var tableExpression = selectExpression.Tables.Single();

                        var projection
                            = QueryCompilationContext
                              .QuerySourceRequiresMaterialization(joinClause)
                                ? selectExpression.Projection
                                : Enumerable.Empty <Expression>();

                        var joinExpression
                            = !outerJoin
                                ? previousSelectExpression.AddInnerJoin(tableExpression, projection)
                                : previousSelectExpression.AddOuterJoin(tableExpression, projection);

                        joinExpression.Predicate = predicate;

                        Expression
                            = new QueryFlatteningExpressionVisitor(
                                  previousQuerySource,
                                  joinClause,
                                  QueryCompilationContext,
                                  previousSelectProjectionCount,
                                  operatorToFlatten)
                              .Visit(Expression);
                    }
                    else
                    {
                        previousSelectExpression
                        .RemoveRangeFromProjection(previousSelectProjectionCount);
                    }
                }
            }
        }
示例#4
0
        private Expression LiftSubQuery(
            IQuerySource querySource, Expression itemsExpression, QueryModel queryModel, Expression expression)
        {
            var subQueryExpression = itemsExpression as SubQueryExpression;

            if (subQueryExpression == null)
            {
                return(expression);
            }

            var subQueryModelVisitor
                = (RelationalQueryModelVisitor)QueryCompilationContext.CreateQueryModelVisitor(this);

            subQueryModelVisitor.VisitSubQueryModel(subQueryExpression.QueryModel);

            SelectExpression subSelectExpression = null;

            if (subQueryModelVisitor.Queries.Count == 1 &&
                !subQueryModelVisitor.RequiresClientFilter &&
                !subQueryModelVisitor.RequiresClientSelectMany &&
                !subQueryModelVisitor.RequiresClientProjection &&
                !subQueryModelVisitor.RequiresClientResultOperator)
            {
                subSelectExpression = subQueryModelVisitor.Queries.First();
            }

            if (subSelectExpression != null &&
                (!subSelectExpression.OrderBy.Any() ||
                 subSelectExpression.Limit != null) &&
                (QueryCompilationContext.IsCrossApplySupported ||
                 (!subSelectExpression.IsCorrelated() ||
                  !(querySource is AdditionalFromClause))))
            {
                subSelectExpression.PushDownSubquery().QuerySource = querySource;

                AddQuery(querySource, subSelectExpression);

                var shapedQueryMethodExpression
                    = new ShapedQueryFindingExpressionVisitor(QueryCompilationContext)
                      .Find(subQueryModelVisitor.Expression);

                var shaperLambda     = (LambdaExpression)shapedQueryMethodExpression.Arguments[2];
                var shaperMethodCall = (MethodCallExpression)shaperLambda.Body;

                var shaperMethod     = shaperMethodCall.Method;
                var shaperMethodArgs = shaperMethodCall.Arguments.ToList();

                if (!QueryCompilationContext.QuerySourceRequiresMaterialization(querySource) &&
                    shaperMethod.MethodIsClosedFormOf(RelationalEntityQueryableExpressionVisitor.CreateEntityMethodInfo))
                {
                    shaperMethod = RelationalEntityQueryableExpressionVisitor.CreateValueBufferMethodInfo;
                    shaperMethodArgs.RemoveRange(5, 5);
                }
                else
                {
                    subSelectExpression.ExplodeStarProjection();
                }

                var innerQuerySource = (IQuerySource)((ConstantExpression)shaperMethodArgs[0]).Value;

                foreach (var queryAnnotation
                         in QueryCompilationContext.QueryAnnotations
                         .Where(qa => qa.QuerySource == innerQuerySource))
                {
                    queryAnnotation.QuerySource = querySource;
                }

                shaperMethodArgs[0] = Expression.Constant(querySource);

                var querySourceReferenceExpression
                    = queryModel.SelectClause.Selector as QuerySourceReferenceExpression;

                if (querySourceReferenceExpression != null &&
                    querySourceReferenceExpression.ReferencedQuerySource == querySource)
                {
                    if (subQueryExpression.QueryModel != null)
                    {
                        queryModel.SelectClause.Selector = subQueryExpression.QueryModel.SelectClause.Selector;

                        QueryCompilationContext.QuerySourceMapping
                        .ReplaceMapping(
                            subQueryExpression.QueryModel.MainFromClause,
                            QueryResultScope.GetResult(
                                QueryResultScopeParameter,
                                querySource,
                                shaperMethod.ReturnType.GenericTypeArguments[0]));
                    }
                }

                return(Expression.Call(
                           QueryCompilationContext.QueryMethodProvider.ShapedQueryMethod
                           .MakeGenericMethod(shaperMethod.ReturnType),
                           shapedQueryMethodExpression.Arguments[0],
                           shapedQueryMethodExpression.Arguments[1],
                           Expression.Lambda(
                               Expression.Call(shaperMethod, shaperMethodArgs),
                               shaperLambda.Parameters[0])));
            }

            return(expression);
        }
示例#5
0
        protected virtual void OptimizeJoinClause(
            [NotNull] JoinClause joinClause,
            [NotNull] QueryModel queryModel,
            int index,
            [NotNull] Action baseVisitAction,
            [NotNull] MethodInfo operatorToFlatten,
            bool outerJoin = false)
        {
            Check.NotNull(joinClause, nameof(joinClause));
            Check.NotNull(queryModel, nameof(queryModel));
            Check.NotNull(baseVisitAction, nameof(baseVisitAction));
            Check.NotNull(operatorToFlatten, nameof(operatorToFlatten));

            RequiresClientJoin = true;

            var previousQuerySource = FindPreviousQuerySource(queryModel, index);

            var previousSelectExpression
                = previousQuerySource != null
                    ? TryGetQuery(previousQuerySource)
                    : null;

            var previousSelectProjectionCount
                = previousSelectExpression?.Projection.Count ?? -1;

            baseVisitAction();

            if (previousSelectExpression != null)
            {
                var selectExpression = TryGetQuery(joinClause);

                if (selectExpression != null)
                {
                    var sqlTranslatingExpressionVisitor
                        = _sqlTranslatingExpressionVisitorFactory.Create(this);

                    var predicate
                        = sqlTranslatingExpressionVisitor
                          .Visit(
                              Expression.Equal(
                                  joinClause.OuterKeySelector,
                                  joinClause.InnerKeySelector));

                    if (predicate != null)
                    {
                        QueriesBySource.Remove(joinClause);

                        previousSelectExpression.RemoveRangeFromProjection(previousSelectProjectionCount);

                        var tableExpression = selectExpression.Tables.Single();

                        var projection
                            = QueryCompilationContext
                              .QuerySourceRequiresMaterialization(joinClause)
                                ? selectExpression.Projection
                                : Enumerable.Empty <Expression>();

                        var joinExpression
                            = !outerJoin
                                ? previousSelectExpression.AddInnerJoin(tableExpression, projection)
                                : previousSelectExpression.AddOuterJoin(tableExpression, projection);

                        joinExpression.Predicate = predicate;

                        if (outerJoin)
                        {
                            var outerJoinOrderingExtractor = new OuterJoinOrderingExtractor();

                            outerJoinOrderingExtractor.Visit(predicate);

                            foreach (var expression in outerJoinOrderingExtractor.Expressions)
                            {
                                previousSelectExpression
                                .AddToOrderBy(new Ordering(expression, OrderingDirection.Asc));
                            }
                        }

                        Expression
                            = _queryFlattenerFactory
                              .Create(
                                  joinClause,
                                  QueryCompilationContext,
                                  operatorToFlatten,
                                  previousSelectProjectionCount)
                              .Flatten((MethodCallExpression)Expression);

                        RequiresClientJoin = false;
                    }
                }
            }

            if (RequiresClientJoin)
            {
                CheckClientEval(joinClause);
            }
        }