如何将可枚举变为AsyncEnumerable?

时间:2017-03-27 02:09:08

标签: c# .net linq entity-framework-core

我有一些代码使用Entity Framework Core中提供的异步扩展方法:

let arrayOfArrays = [[['firstName', 'Joe'], ['lastName', 'Blow'], ['age', 42], ['role', 'clerk']],
[['firstName', 'Mary'], ['lastName', 'Jenkins'], ['age', 36], ['role', 'manager']]];

let arrayOfObjects = arrayOfArrays.map(array => array.reduce((acc, val) => {
  acc[val[0]] = val[1];
  return acc;
}, {}));

console.log(arrayOfObjects);

public async Task<MyResult> DoQuery<T>(IQueryable<T> queryable) { var count = await queryable.CountAsync(); var firstItems = await queryable .Take(5) .ToArrayAsync(); return new MyResult(count, firstItems); } 我直接从EF提供函数时,这很有用。我还想重用这段代码来对LINQ-to-objects“查询”做一些逻辑:

IQueryable

这失败了(这并不太令人惊讶):

  

System.InvalidOperationException:源IQueryable的提供程序未实现IAsyncQueryProvider。只有实现IEntityQueryProvider的提供程序才能用于Entity Framework异步操作。

它看起来像一个重构器,但我很好奇:有没有办法将一个简单的可枚举变成一个对待var evens = Enumerable.Range(0, 10).Where(i => i % 2 == 0); var result = DoQuery(evens.AsQueryable()); 的“虚拟”AsyncEnumerableAsyncQueryable同步?

1 个答案:

答案 0 :(得分:2)

您需要创建内存中DbAsyncQueryProvider来处理异步查询。有关如何执行此操作的详细说明here。滚动到有关使用异步查询进行测试的部分。下面是代码副本&amp;从该链接粘贴:

using System.Collections.Generic; 
using System.Data.Entity.Infrastructure; 
using System.Linq; 
using System.Linq.Expressions; 
using System.Threading; 
using System.Threading.Tasks; 

namespace TestingDemo 
{ 
    internal class TestDbAsyncQueryProvider<TEntity> : IDbAsyncQueryProvider 
    { 
        private readonly IQueryProvider _inner; 

        internal TestDbAsyncQueryProvider(IQueryProvider inner) 
        { 
            _inner = inner; 
        } 

        public IQueryable CreateQuery(Expression expression) 
        { 
            return new TestDbAsyncEnumerable<TEntity>(expression); 
        } 

        public IQueryable<TElement> CreateQuery<TElement>(Expression expression) 
        { 
            return new TestDbAsyncEnumerable<TElement>(expression); 
        } 

        public object Execute(Expression expression) 
        { 
            return _inner.Execute(expression); 
        } 

        public TResult Execute<TResult>(Expression expression) 
        { 
            return _inner.Execute<TResult>(expression); 
        } 

        public Task<object> ExecuteAsync(Expression expression, CancellationToken cancellationToken) 
        { 
            return Task.FromResult(Execute(expression)); 
        } 

        public Task<TResult> ExecuteAsync<TResult>(Expression expression, CancellationToken cancellationToken) 
        { 
            return Task.FromResult(Execute<TResult>(expression)); 
        } 
    } 

    internal class TestDbAsyncEnumerable<T> : EnumerableQuery<T>, IDbAsyncEnumerable<T>, IQueryable<T> 
    { 
        public TestDbAsyncEnumerable(IEnumerable<T> enumerable) 
            : base(enumerable) 
        { } 

        public TestDbAsyncEnumerable(Expression expression) 
            : base(expression) 
        { } 

        public IDbAsyncEnumerator<T> GetAsyncEnumerator() 
        { 
            return new TestDbAsyncEnumerator<T>(this.AsEnumerable().GetEnumerator()); 
        } 

        IDbAsyncEnumerator IDbAsyncEnumerable.GetAsyncEnumerator() 
        { 
            return GetAsyncEnumerator(); 
        } 

        IQueryProvider IQueryable.Provider 
        { 
            get { return new TestDbAsyncQueryProvider<T>(this); } 
        } 
    } 

    internal class TestDbAsyncEnumerator<T> : IDbAsyncEnumerator<T> 
    { 
        private readonly IEnumerator<T> _inner; 

        public TestDbAsyncEnumerator(IEnumerator<T> inner) 
        { 
            _inner = inner; 
        } 

        public void Dispose() 
        { 
            _inner.Dispose(); 
        } 

        public Task<bool> MoveNextAsync(CancellationToken cancellationToken) 
        { 
            return Task.FromResult(_inner.MoveNext()); 
        } 

        public T Current 
        { 
            get { return _inner.Current; } 
        } 

        object IDbAsyncEnumerator.Current 
        { 
            get { return Current; } 
        } 
    } 
}