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; }
/// <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); }