How to return empty IQueryable in an async repository method

后端 未结 2 1134
情歌与酒
情歌与酒 2021-01-05 01:55

Lets say I have a simple repository class, with one GetByNames method

public class MyRepo
{
    private readonly MyDbContext _db;

    public My         


        
2条回答
  •  借酒劲吻你
    2021-01-05 02:29

    I ended up implementing an extension method that returns wrapper which implements IDbAsyncEnumerable. It is based on this boilerplate implementation for mocking async code.

    With this extension method I can use

    return Enumerable.Empty().AsAsyncQueryable();
    

    which works great.

    Implementation:

    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Data.Entity.Infrastructure;
    using System.Linq;
    using System.Linq.Expressions;
    using System.Threading;
    using System.Threading.Tasks;
    
    namespace MyProject.MyDatabase.Extensions
    {
        public static class EnumerableExtensions
        {
            public static IQueryable AsAsyncQueryable(this IEnumerable source)
            {
                return new AsyncQueryableWrapper(source);
            }
    
            public static IQueryable AsAsyncQueryable(this IQueryable source)
            {
                return new AsyncQueryableWrapper(source);
            }
        }
    
        internal class AsyncQueryableWrapper: IDbAsyncEnumerable, IQueryable
        {
            private readonly IQueryable _source;
    
            public AsyncQueryableWrapper(IQueryable source)
            {
                _source = source;
            }
    
            public AsyncQueryableWrapper(IEnumerable source)
            {
                _source = source.AsQueryable();
            }
    
            public IDbAsyncEnumerator GetAsyncEnumerator()
            {
                return new AsyncEnumerator(this.AsEnumerable().GetEnumerator());
            }
    
            IDbAsyncEnumerator IDbAsyncEnumerable.GetAsyncEnumerator()
            {
                return GetAsyncEnumerator();
            }
    
            public IEnumerator GetEnumerator()
            {
                return _source.GetEnumerator();
            }
    
            IEnumerator IEnumerable.GetEnumerator()
            {
                return GetEnumerator();
            }
    
            public Expression Expression => _source.Expression;
            public Type ElementType => _source.ElementType;
            public IQueryProvider Provider => new AsyncQueryProvider(_source.Provider);
        }
    
        internal class AsyncEnumerable : EnumerableQuery, IDbAsyncEnumerable, IQueryable
        {
            public AsyncEnumerable(IEnumerable enumerable)
                : base(enumerable)
            { }
    
            public AsyncEnumerable(Expression expression)
                : base(expression)
            { }
    
            public IDbAsyncEnumerator GetAsyncEnumerator()
            {
                return new AsyncEnumerator(this.AsEnumerable().GetEnumerator());
            }
    
            IDbAsyncEnumerator IDbAsyncEnumerable.GetAsyncEnumerator()
            {
                return GetAsyncEnumerator();
            }
    
            IQueryProvider IQueryable.Provider => new AsyncQueryProvider(this);
        }
    
        internal class AsyncQueryProvider : IDbAsyncQueryProvider
        {
            private readonly IQueryProvider _inner;
    
            internal AsyncQueryProvider(IQueryProvider inner)
            {
                _inner = inner;
            }
    
            public IQueryable CreateQuery(Expression expression)
            {
                var t = expression.Type;
                if (!t.IsGenericType)
                {
                    return new AsyncEnumerable(expression);
                }
    
                var genericParams = t.GetGenericArguments();
                var genericParam = genericParams[0];
                var enumerableType = typeof(AsyncEnumerable<>).MakeGenericType(genericParam);
    
                return (IQueryable)Activator.CreateInstance(enumerableType, expression);
            }
    
            public IQueryable CreateQuery(Expression expression)
            {
                return new AsyncEnumerable(expression);
            }
    
            public object Execute(Expression expression)
            {
                return _inner.Execute(expression);
            }
    
            public TResult Execute(Expression expression)
            {
                return _inner.Execute(expression);
            }
    
            public Task ExecuteAsync(Expression expression, CancellationToken cancellationToken)
            {
                return Task.FromResult(Execute(expression));
            }
    
            public Task ExecuteAsync(Expression expression, CancellationToken cancellationToken)
            {
                return Task.FromResult(Execute(expression));
            }
        }
    
        internal class AsyncEnumerator : IDbAsyncEnumerator
        {
            private readonly IEnumerator _inner;
    
            public AsyncEnumerator(IEnumerator inner)
            {
                _inner = inner;
            }
    
            public void Dispose()
            {
                _inner.Dispose();
            }
    
            public Task MoveNextAsync(CancellationToken cancellationToken)
            {
                return Task.FromResult(_inner.MoveNext());
            }
    
            public T Current => _inner.Current;
    
            object IDbAsyncEnumerator.Current => Current;
        }
    }
    
        

    提交回复
    热议问题