예제 #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
        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);
        }