Exemplo n.º 1
0
        protected override Expression VisitMethodCall(MethodCallExpression node)
        {
            Check.NotNull(node, nameof(node));

            if (node.Method.MethodIsClosedFormOf(
                    _relationalQueryCompilationContext.QueryMethodProvider.ShapedQueryMethod))
            {
                var queryArguments = node.Arguments.ToList();

                queryArguments[2] = Expression.Default(typeof(int?));

                return(ResultOperatorHandler
                       .CallWithPossibleCancellationToken(
                           _relationalQueryCompilationContext.QueryMethodProvider
                           .GetResultMethod.MakeGenericMethod(typeof(TResult)),
                           Expression.Call(
                               _relationalQueryCompilationContext.QueryMethodProvider.QueryMethod,
                               queryArguments)));
            }

            // ReSharper disable once LoopCanBePartlyConvertedToQuery
            foreach (var expression in node.Arguments)
            {
                var newExpression = Visit(expression);

                if (newExpression != expression)
                {
                    return(newExpression);
                }
            }

            return(node);
        }
        /// <summary>
        ///     This API supports the Entity Framework Core infrastructure and is not intended to be used
        ///     directly from your code. This API may change or be removed in future releases.
        /// </summary>
        protected override Expression VisitMethodCall(MethodCallExpression node)
        {
            Check.NotNull(node, nameof(node));

            if (node.Method.MethodIsClosedFormOf(
                    _relationalQueryCompilationContext.QueryMethodProvider.ShapedQueryMethod))
            {
                var queryArguments = node.Arguments.Take(2).ToList();

                return(ResultOperatorHandler
                       .CallWithPossibleCancellationToken(
                           _relationalQueryCompilationContext.QueryMethodProvider
                           .GetResultMethod.MakeGenericMethod(typeof(TResult)),
                           Expression.Call(
                               _relationalQueryCompilationContext.QueryMethodProvider.QueryMethod,
                               queryArguments),
                           Expression.Constant(_throwOnNullResult)));
            }

            if (node.Method.MethodIsClosedFormOf(
                    _relationalQueryCompilationContext.QueryMethodProvider.InjectParametersMethod))
            {
                var sourceArgument = (MethodCallExpression)Visit(node.Arguments[1]);

                if (sourceArgument.Method.MethodIsClosedFormOf(
                        _relationalQueryCompilationContext.QueryMethodProvider.GetResultMethod))
                {
                    var getResultArgument = sourceArgument.Arguments[0];

                    var newGetResultArgument
                        = Expression.Call(
                              _relationalQueryCompilationContext.QueryMethodProvider.InjectParametersMethod
                              .MakeGenericMethod(typeof(ValueBuffer)),
                              node.Arguments[0],
                              getResultArgument,
                              node.Arguments[2],
                              node.Arguments[3]);

                    return(ResultOperatorHandler.CallWithPossibleCancellationToken(
                               sourceArgument.Method,
                               newGetResultArgument,
                               sourceArgument.Arguments[1]));
                }

                return(sourceArgument);
            }

            // ReSharper disable once LoopCanBePartlyConvertedToQuery
            foreach (var expression in node.Arguments)
            {
                var newExpression = Visit(expression);

                if (newExpression != expression)
                {
                    return(newExpression);
                }
            }

            return(node);
        }
        protected override Expression VisitMethodCallExpression([NotNull] MethodCallExpression methodCallExpression)
        {
            Check.NotNull(methodCallExpression, "methodCallExpression");

            var newObject = VisitExpression(methodCallExpression.Object);

            if (newObject != methodCallExpression.Object)
            {
                return(newObject);
            }

            var newArguments = VisitAndConvert(methodCallExpression.Arguments, "VisitMethodCallExpression");

            if ((methodCallExpression.Method.MethodIsClosedFormOf(RelationalQueryModelVisitor.CreateEntityMethodInfo) ||
                 ReferenceEquals(methodCallExpression.Method, RelationalQueryModelVisitor.CreateValueReaderMethodInfo)) &&
                ((ConstantExpression)methodCallExpression.Arguments[0]).Value == _outerQuerySource)
            {
                return(methodCallExpression.Arguments[3]);
            }

            if (newArguments != methodCallExpression.Arguments)
            {
                if (methodCallExpression.Method.MethodIsClosedFormOf(
                        _relationalQueryCompilationContext.QueryMethodProvider.QueryMethod))
                {
                    return(Expression.Call(
                               _relationalQueryCompilationContext.QueryMethodProvider.QueryMethod
                               .MakeGenericMethod(typeof(DbDataReader)),
                               newArguments));
                }

                if (methodCallExpression.Method.MethodIsClosedFormOf(
                        _relationalQueryCompilationContext.LinqOperatorProvider.Select))
                {
                    return(ResultOperatorHandler.CallWithPossibleCancellationToken(
                               _relationalQueryCompilationContext.QueryMethodProvider.GetResultMethod
                               .MakeGenericMethod(typeof(TResult)),
                               newArguments[0]));
                }

                if (methodCallExpression.Method.MethodIsClosedFormOf(
                        _relationalQueryCompilationContext.LinqOperatorProvider.SelectMany))
                {
                    return(Expression.Call(
                               _relationalQueryCompilationContext.LinqOperatorProvider.SelectMany
                               .MakeGenericMethod(typeof(QuerySourceScope), typeof(DbDataReader)),
                               newArguments));
                }

                return(Expression.Call(methodCallExpression.Method, newArguments));
            }

            return(methodCallExpression);
        }
 /// <summary>
 ///     This API supports the Entity Framework Core infrastructure and is not intended to be used
 ///     directly from your code. This API may change or be removed in future releases.
 /// </summary>
 public RelationalResultOperatorHandler(
     [NotNull] IModel model,
     [NotNull] IRelationalAnnotationProvider relationalAnnotationProvider,
     [NotNull] ISqlTranslatingExpressionVisitorFactory sqlTranslatingExpressionVisitorFactory,
     [NotNull] ISelectExpressionFactory selectExpressionFactory,
     [NotNull] ResultOperatorHandler resultOperatorHandler)
 {
     _model = model;
     _relationalAnnotationProvider           = relationalAnnotationProvider;
     _sqlTranslatingExpressionVisitorFactory = sqlTranslatingExpressionVisitorFactory;
     _selectExpressionFactory = selectExpressionFactory;
     _resultOperatorHandler   = resultOperatorHandler;
 }
Exemplo n.º 5
0
        /// <summary>
        ///     Visits the children of the <see cref="T:System.Linq.Expressions.MethodCallExpression"></see>.
        /// </summary>
        /// <param name="methodCallExpression">The expression to visit.</param>
        /// <returns>
        ///     The modified expression, if it or any subexpression was modified; otherwise, returns the original expression.
        /// </returns>
        protected override Expression VisitMethodCall(MethodCallExpression methodCallExpression)
        {
            var newExpression = base.VisitMethodCall(methodCallExpression);

            if (QueryModelVisitor.QueryCompilationContext.IsAsyncQuery)
            {
                switch (newExpression)
                {
                case MethodCallExpression sequenceMaterializingLinqMethodCallExpression
                    when sequenceMaterializingLinqMethodCallExpression.Arguments.Count > 0 &&
                    sequenceMaterializingLinqMethodCallExpression.Arguments[0] is MethodCallExpression toMethodCallExpression &&
                    TryFindAsyncMethod(sequenceMaterializingLinqMethodCallExpression.Method.Name, out var asyncMethodInfo):
                {
                    // Transforms a sync method inside an async projector into the corresponding async version (if one exists).
                    // We call .Result here so that the types still line up (we remove the .Result in TaskLiftingExpressionVisitor).

                    Expression[] args = null;

                    if (toMethodCallExpression.Method.MethodIsClosedFormOf(QueryModelVisitor.LinqOperatorProvider.ToEnumerable))
                    {
                        args = toMethodCallExpression.Arguments.ToArray();
                    }
                    else if (toMethodCallExpression.Method.MethodIsClosedFormOf(QueryModelVisitor.LinqOperatorProvider.ToQueryable))
                    {
                        args = new[] { toMethodCallExpression.Arguments[0] };
                    }

                    if (args != null)
                    {
                        return
                            (Expression.Property(
                                 ResultOperatorHandler.CallWithPossibleCancellationToken(
                                     asyncMethodInfo.MakeGenericMethod(
                                         sequenceMaterializingLinqMethodCallExpression.Method.GetGenericArguments()),
                                     args),
                                 nameof(Task <object> .Result)));
                    }

                    break;
                }

                case MethodCallExpression materializeCollectionNavigationMethodCallExpression
                    when materializeCollectionNavigationMethodCallExpression.Method
                    .MethodIsClosedFormOf(CollectionNavigationSubqueryInjector.MaterializeCollectionNavigationMethodInfo) &&
                    materializeCollectionNavigationMethodCallExpression.Arguments[1] is MethodCallExpression toQueryableMethodCallExpression &&
                    toQueryableMethodCallExpression.Method.MethodIsClosedFormOf(QueryModelVisitor.LinqOperatorProvider.ToQueryable):
                {
                    // Transforms a sync method inside a MaterializeCollectionNavigation call into a corresponding async version.
                    // We call .Result here so that the types still line up (we remove the .Result in TaskLiftingExpressionVisitor).

                    return
                        (toQueryableMethodCallExpression.Arguments[0].Type.IsGenericType &&
                         toQueryableMethodCallExpression.Arguments[0].Type.GetGenericTypeDefinition() == typeof(IAsyncEnumerable <>)
                                    ? (Expression)Expression.Property(
                             ResultOperatorHandler.CallWithPossibleCancellationToken(
                                 _materializeCollectionNavigationAsyncMethodInfo
                                 .MakeGenericMethod(
                                     materializeCollectionNavigationMethodCallExpression.Method
                                     .GetGenericArguments()[0]),
                                 materializeCollectionNavigationMethodCallExpression.Arguments[0],
                                 toQueryableMethodCallExpression.Arguments[0]),
                             nameof(Task <object> .Result))
                                    : Expression.Call(
                             materializeCollectionNavigationMethodCallExpression.Method,
                             materializeCollectionNavigationMethodCallExpression.Arguments[0],
                             toQueryableMethodCallExpression.Arguments[0]));
                }

                case MethodCallExpression newMethodCallExpression
                    when newMethodCallExpression.Method.Equals(methodCallExpression.Method) &&
                    newMethodCallExpression.Arguments.Count > 0:
                {
                    // Transforms a sync sequence argument to an async buffered version
                    // We call .Result here so that the types still line up (we remove the .Result in TaskLiftingExpressionVisitor).

                    var newArguments = newMethodCallExpression.Arguments.ToList();

                    for (var i = 0; i < newArguments.Count; i++)
                    {
                        var argument = newArguments[i];

                        if (argument is MethodCallExpression argumentMethodCallExpression &&
                            argumentMethodCallExpression.Method
                            .MethodIsClosedFormOf(QueryModelVisitor.LinqOperatorProvider.ToEnumerable))
                        {
                            newArguments[i]
                                = Expression.Property(
                                      ResultOperatorHandler.CallWithPossibleCancellationToken(
                                          _toArrayAsync.MakeGenericMethod(
                                              argumentMethodCallExpression.Method.GetGenericArguments()),
                                          argumentMethodCallExpression.Arguments.ToArray()),
                                      nameof(Task <object> .Result));
                        }
                    }

                    return(newMethodCallExpression.Update(newMethodCallExpression.Object, newArguments));
                }
                }
            }

            return(newExpression);
        }