加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

c# – ToArrayAsync()抛出“源IQueryable未实现IAsyncEnumerable

发布时间:2020-12-15 23:50:16 所属栏目:百科 来源:网络整理
导读:我在ASP.NET Core上有一个MVC项目,我的问题与IQueryable和异步相关.我在IQueryable T中编写了以下搜索方法: private IQueryableInternalOrderInfo WhereSearchTokens(IQueryableInternalOrderInfo query,SearchToken[] searchTokens){ if (searchTokens.Len
我在ASP.NET Core上有一个MVC项目,我的问题与IQueryable和异步相关.我在IQueryable< T>中编写了以下搜索方法:

private IQueryable<InternalOrderInfo> WhereSearchTokens(IQueryable<InternalOrderInfo> query,SearchToken[] searchTokens)
{
    if (searchTokens.Length == 0)
    {
        return query;
    }
    var results = new List<InternalOrderInfo>();
    foreach (var searchToken in searchTokens)
    {
        //search logic,intermediate results are being added to `results` using `AddRange()`
    }

    return results.Count != 0 ? results.Distinct().AsQueryable() : query;
}

我在方法ExecuteAsync()中调用它:

public async Task<GetAllInternalOrderInfoResponse> ExecuteAsync(GetAllInternalOrderInfoRequest request)
{
    //rest of the code
    if (searchTokens != null && searchTokens.Any())
    {
        allInternalOrderInfo = WhereSearchTokens(allInternalOrderInfo,searchTokens);
    }
    var orders = await allInternalOrderInfo.Skip(offset).Take(limit).ToArrayAsync();
    //rest of the code
}

当我测试这个时,我在线上得到一个InvalidOperationException,我调用ToArrayAsync()

The source IQueryable doesn’t implement IAsyncEnumerable. Only sources that implement IAsyncEnumerable can be used for Entity Framework asynchronous operations.

我已经将ToArrayAsync()更改为ToListAsync()但没有任何更改.我已经搜索了这个问题一段时间了,但已解决的问题主要与DbContext和实体创建有关.没有为此项目安装EntityFramework,最好不要因为应用程序架构而这样做.希望有人有任何想法在我的情况下做什么.

解决方法

如果您不打算改变您的设计 – 您有以下几种选择:

1)将AsQueryable更改为另一个返回IQueryable的方法,该方法也实现了IDbAsyncEnumerable.例如,您可以扩展EnumerableQuery(由AsQueryable返回):

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

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

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

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

    private class InMemoryDbAsyncEnumerator<T> : IDbAsyncEnumerator<T> {
        private readonly IEnumerator<T> _enumerator;

        public InMemoryDbAsyncEnumerator(IEnumerator<T> enumerator) {
            _enumerator = enumerator;
        }

        public void Dispose() {
        }

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

        public T Current => _enumerator.Current;

        object IDbAsyncEnumerator.Current => Current;
    }
}

然后你改变

results.Distinct().AsQueryable()

new AsyncEnumerableQuery<InternalOrderInfo>(results.Distinct())

之后,ToArrayAsync将不再抛出异常(显然你可以像AsQueryable一样创建自己的扩展方法).

2)更改ToArrayAsync部分:

public static class EfExtensions {
    public static Task<TSource[]> ToArrayAsyncSafe<TSource>(this IQueryable<TSource> source) {
        if (source == null)
            throw new ArgumentNullException(nameof(source));
        if (!(source is IDbAsyncEnumerable<TSource>))
            return Task.FromResult(source.ToArray());
        return source.ToArrayAsync();
    }
}

并使用ToArrayAsyncSafe而不是ToArrayAsync,如果IQueryable不是IDbAsyncEnumerable,它将回退到同步枚举.在你的情况下,这只发生在查询真的是内存列表而不是查询时,所以异步执行无论如何都没有意义.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读