【问题标题】:How can I turn an enumerable into an AsyncEnumerable?如何将可枚举转换为 AsyncEnumerable?
【发布时间】:2017-03-27 02:09:07
【问题描述】:

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

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

IQueryable 我提供的函数直接来自 EF 时,这非常有用。我还想重用这段代码在 LINQ-to-objects“查询”上执行一些逻辑:

var evens = Enumerable.Range(0, 10).Where(i => i % 2 == 0);
var result = DoQuery(evens.AsQueryable());

这失败了(这并不奇怪):

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

看起来重构是有序的,但我很好奇:有没有办法将一个普通的枚举变成一个“虚拟”AsyncEnumerableAsyncQueryable 同步处理 CountAsync

【问题讨论】:

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


    【解决方案1】:

    您需要创建一个内存中的DbAsyncQueryProvider 来处理异步查询。关于如何做到这一点here 有详细说明。滚动到关于使用异步查询进行测试的部分。以下是从该链接复制和粘贴的代码:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-05-07
      • 2016-03-20
      • 2010-09-06
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多