示例#1
0
        /// <summary>
        /// Executes the <see cref="System.Linq.Expressions.Expression"/> and returns the raw result.
        /// </summary>
        /// <remarks>
        /// <see cref="InvalidOperationException"/> get handled for failing
        /// <see cref="Queryable.Single{TSource}(IQueryable{TSource})"/> and
        /// <see cref="Queryable.Single{TSource}(IQueryable{TSource}, System.Linq.Expressions.Expression{Func{TSource, bool}})"/>,
        /// <see cref="Queryable.First{TSource}(IQueryable{TSource})"/>,
        /// <see cref="Queryable.First{TSource}(IQueryable{TSource}, System.Linq.Expressions.Expression{Func{TSource, bool}})"/>,
        /// <see cref="Queryable.Last{TSource}(IQueryable{TSource})"/>,
        /// <see cref="Queryable.Last{TSource}(IQueryable{TSource}, System.Linq.Expressions.Expression{Func{TSource, bool}})"/>.
        /// Instead of throwing an exception, an array with the length of zero respectively two elements is returned.
        /// </remarks>
        /// <param name="expression">The <see cref="System.Linq.Expressions.Expression"/> to be executed.</param>
        /// <returns>Execution result of the <see cref="System.Linq.Expressions.Expression"/> specified.</returns>
        protected virtual object?Execute(System.Linq.Expressions.Expression expression)
        {
            expression.CheckNotNull(nameof(expression));
            try
            {
                return(ExecuteCore(expression));
            }
            catch (InvalidOperationException ex)
            {
                if (string.Equals(ex.Message, "Sequence contains no elements", StringComparison.Ordinal))
                {
                    return(Array.CreateInstance(expression.Type, 0));
                }

                if (string.Equals(ex.Message, "Sequence contains no matching element", StringComparison.Ordinal))
                {
                    return(Array.CreateInstance(expression.Type, 0));
                }

                if (string.Equals(ex.Message, "Sequence contains more than one element", StringComparison.Ordinal))
                {
                    return(Array.CreateInstance(expression.Type, 2));
                }

                if (string.Equals(ex.Message, "Sequence contains more than one matching element", StringComparison.Ordinal))
                {
                    return(Array.CreateInstance(expression.Type, 2));
                }

                throw;
            }
        }
示例#2
0
        public IQueryable CreateQuery(Expression expression)
        {
            var elementType = TypeHelper.GetElementType(expression.CheckNotNull(nameof(expression)).Type)
                              ?? throw new RemoteLinqException($"Failed to get element type of {expression.Type}");

            return(new RemoteQueryable(elementType, this, expression));
        }
示例#3
0
        /// <summary>
        /// Executes the <see cref="System.Linq.Expressions.Expression"/> and returns the raw result.
        /// </summary>
        /// <remarks>
        /// <see cref="InvalidOperationException"/> get handled for failing
        /// <see cref="Queryable.Single{TSource}(IQueryable{TSource})"/> and
        /// <see cref="Queryable.Single{TSource}(IQueryable{TSource}, System.Linq.Expressions.Expression{Func{TSource, bool}})"/>,
        /// <see cref="Queryable.First{TSource}(IQueryable{TSource})"/>,
        /// <see cref="Queryable.First{TSource}(IQueryable{TSource}, System.Linq.Expressions.Expression{Func{TSource, bool}})"/>,
        /// <see cref="Queryable.Last{TSource}(IQueryable{TSource})"/>,
        /// <see cref="Queryable.Last{TSource}(IQueryable{TSource}, System.Linq.Expressions.Expression{Func{TSource, bool}})"/>.
        /// Instead of throwing an exception, an array with the length of zero respectively two elements is returned.
        /// </remarks>
        /// <param name="expression">The <see cref="System.Linq.Expressions.Expression"/> to be executed.</param>
        /// <param name="cancellation">A <see cref="CancellationToken" /> to observe while waiting for the task to complete.</param>
        /// <returns>Execution result of the <see cref="System.Linq.Expressions.Expression"/> specified.</returns>
        protected virtual async Task <object?> ExecuteAsync(System.Linq.Expressions.Expression expression, CancellationToken cancellation)
        {
            expression.CheckNotNull(nameof(expression));
            try
            {
                return(await ExecuteCoreAsync(expression, cancellation).ConfigureAwait(false));
            }
            catch (InvalidOperationException ex)
            {
                if (string.Equals(ex.Message, "Sequence contains no elements", StringComparison.Ordinal))
                {
                    return(Array.CreateInstance(expression.Type, 0));
                }

                if (string.Equals(ex.Message, "Sequence contains no matching element", StringComparison.Ordinal))
                {
                    return(Array.CreateInstance(expression.Type, 0));
                }

                if (string.Equals(ex.Message, "Sequence contains more than one element", StringComparison.Ordinal))
                {
                    return(Array.CreateInstance(expression.Type, 2));
                }

                if (string.Equals(ex.Message, "Sequence contains more than one matching element", StringComparison.Ordinal))
                {
                    return(Array.CreateInstance(expression.Type, 2));
                }

                throw;
            }
        }
示例#4
0
        internal static Expressions.Expression TranslateExpression(Expression expression, ITypeInfoProvider?typeInfoProvider, Func <Expression, bool>?canBeEvaluatedLocally)
        {
            var slinq1 = expression.CheckNotNull(nameof(expression)).SimplifyIncorporationOfRemoteQueryables();
            var rlinq1 = slinq1.ToRemoteLinqExpression(typeInfoProvider, canBeEvaluatedLocally);
            var rlinq2 = rlinq1.ReplaceQueryableByResourceDescriptors(typeInfoProvider);
            var rlinq3 = rlinq2.ReplaceGenericQueryArgumentsByNonGenericArguments();

            return(rlinq3);
        }
示例#5
0
        /// <summary>
        /// Executes the <see cref="System.Linq.Expressions.Expression"/> and returns the raw result.
        /// </summary>
        /// <param name="expression">The <see cref="System.Linq.Expressions.Expression"/> to be executed.</param>
        /// <param name="cancellation">A <see cref="CancellationToken" /> to observe while waiting for the task to complete.</param>
        /// <returns>Execution result of the <see cref="System.Linq.Expressions.Expression"/> specified.</returns>
        protected override async Task <object?> ExecuteCoreAsync(System.Linq.Expressions.Expression expression, CancellationToken cancellation)
        {
            cancellation.ThrowIfCancellationRequested();

            var queryResult = expression.CheckNotNull(nameof(expression)).CompileAndInvokeExpression();

            if (queryResult is Task task)
            {
                if (!expression.Type.Implements(typeof(Task <>), out var resultType))
                {
                    resultType = task
                                 .GetType()
                                 .GetGenericArguments()
                                 .Where(x => x != typeof(CancellationToken))
                                 .ToArray();
                }

                if (resultType.Length != 1)
                {
                    throw new RemoteLinqException($"Failed to retrieve the result type for async query result {task.GetType()}");
                }

                try
                {
                    queryResult = await GetTaskResultAsync(task, resultType[0]).ConfigureAwait(false);
                }
                catch (InvalidOperationException ex)
                {
                    // workarround for issue https://github.com/dotnet/efcore/issues/18742 (relevant for ef core prior version 5.0)
                    if (string.Equals(ex.Message, "Enumerator failed to MoveNextAsync.", StringComparison.Ordinal))
                    {
                        throw new InvalidOperationException("Sequence contains no elements", ex);
                    }

                    throw;
                }
            }

            if (queryResult is null)
            {
                return(null);
            }

            cancellation.ThrowIfCancellationRequested();

            if (queryResult is IQueryable queryable)
            {
                // force query execution
                task        = Helper.ToListAsync(queryable, cancellation);
                queryResult = await GetTaskResultAsync(task, typeof(List <>).MakeGenericType(queryable.ElementType)).ConfigureAwait(false);
            }

            return(queryResult);
        }
示例#6
0
        protected override IAsyncEnumerable <object?> ExecuteAsyncStream(System.Linq.Expressions.Expression expression)
        {
            if (!expression.CheckNotNull(nameof(expression)).Type.Implements(typeof(IQueryable <>)))
            {
                throw new ArgumentException("Expression must be of type IQueryable<>");
            }

            var queryable = (IQueryable)expression.CompileAndInvokeExpression() !;

            return(queryable.ExecuteAsAsyncStream());
        }
示例#7
0
        /// <summary>
        /// Executes the <see cref="System.Linq.Expressions.Expression"/> and returns the raw result.
        /// </summary>
        /// <param name="expression">The <see cref="System.Linq.Expressions.Expression"/> to be executed.</param>
        /// <returns>Execution result of the <see cref="System.Linq.Expressions.Expression"/> specified.</returns>
        protected static object?ExecuteCore(System.Linq.Expressions.Expression expression)
        {
            var queryResult = expression.CheckNotNull(nameof(expression)).CompileAndInvokeExpression();

            if (queryResult is null)
            {
                return(null);
            }

            var queryableType = queryResult.GetType();

            if (queryableType.Implements(typeof(IQueryable <>)))
            {
                // force query execution
                var elementType = TypeHelper.GetElementType(queryableType);
                queryResult = MethodInfos.Enumerable.ToArray.MakeGenericMethod(elementType).InvokeAndUnwrap(null, queryResult);
            }

            return(queryResult);
        }
示例#8
0
        /// <summary>
        /// Executes the <see cref="System.Linq.Expressions.Expression"/> and returns the raw result.
        /// </summary>
        /// <param name="expression">The <see cref="System.Linq.Expressions.Expression"/> to be executed.</param>
        /// <param name="cancellation">A <see cref="CancellationToken" /> to observe while waiting for the task to complete.</param>
        /// <returns>Execution result of the <see cref="System.Linq.Expressions.Expression"/> specified.</returns>
        protected override async Task <object?> ExecuteCoreAsync(System.Linq.Expressions.Expression expression, CancellationToken cancellation)
        {
            cancellation.ThrowIfCancellationRequested();

            var queryResult = expression.CheckNotNull(nameof(expression)).CompileAndInvokeExpression();

            if (queryResult is Task task)
            {
                if (!expression.Type.Implements(typeof(Task <>), out var resultType))
                {
                    resultType = task
                                 .GetType()
                                 .GetGenericArguments()
                                 .Where(x => x != typeof(CancellationToken))
                                 .ToArray();
                }

                if (resultType.Length != 1)
                {
                    throw new RemoteLinqException($"Failed to retrieve the result type for async query result {task.GetType()}");
                }

                queryResult = await GetTaskResultAsync(task, resultType[0]).ConfigureAwait(false);
            }

            if (queryResult is null)
            {
                return(null);
            }

            cancellation.ThrowIfCancellationRequested();

            if (queryResult is IQueryable queryable)
            {
                // force query execution
                task        = Helper.ToListAsync(queryable, cancellation);
                queryResult = await GetTaskResultAsync(task, typeof(List <>).MakeGenericType(queryable.ElementType)).ConfigureAwait(false);
            }

            return(queryResult);
        }
示例#9
0
        /// <summary>
        /// Checks whether the give <see cref="SystemExpression"/> is assignable to the given <typeparamref name="TResult"/> type in any form, throws an <see cref="ArgumentException"/> otherwise.
        /// </summary>
        public static void CheckExpressionResultType <TResult>(SystemExpression expression)
        {
            var expressionType = expression.CheckNotNull(nameof(expression)).Type;

            if (typeof(TResult).IsAssignableFrom(expressionType))
            {
                return;
            }

            if (typeof(IRemoteLinqQueryable).IsAssignableFrom(expressionType))
            {
                return;
            }

            if (expressionType.Implements(typeof(IQueryable <>), out var typeArgs) &&
                typeArgs.Length == 1 &&
                typeof(TResult).IsAssignableFrom(typeArgs[0]))
            {
                return;
            }

            throw new ArgumentException("The specified expression is not assignable to the result type.", nameof(expression));
        }