ToArrayAsync()抛出“源IQueryable不实现IAsyncEnumerable". [英] ToArrayAsync() throws "The source IQueryable doesn't implement IAsyncEnumerable"

查看:125
本文介绍了ToArrayAsync()抛出“源IQueryable不实现IAsyncEnumerable".的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我在ASP.NET Core上有一个MVC项目,我的问题与IQueryable和异步有关.我在IQueryable<T>中编写了以下搜索方法:

I have a MVC project on ASP.NET Core, my problem is connected with IQueryable and asynchronous. I wrote the following method for search in 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
}

当我对此进行测试时,我在调用ToArrayAsync()

When I test this I get an InvalidOperationException on line where I call ToArrayAsync()

源IQueryable没有实现IAsyncEnumerable.只有实现IAsyncEnumerable的源才可用于Entity Framework异步操作.

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

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

I had changed ToArrayAsync() to ToListAsync() but nothing have changed. I have searched this problem for a while, but resolved questions are connected mostly with DbContext and entity creating. EntityFramework is not installed for this project and it's better not to do it because of application architecture. Hope someone has any ideas what to do in my situation.

推荐答案

如果您不打算更改设计,则可以选择以下几种方式:

If you are not going to change your design - you have several options:

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

1) Change AsQueryable to another method which returns IQueryable which also implements IDbAsyncEnumerable. For example you can extend EnumerableQuery (which is returned by 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).

And later, ToArrayAsync will not throw exception any more (obviously you can create your own extension method like 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,它将退回到同步枚举.在您的情况下,仅当查询实际上是内存中的列表而不是查询时才会发生,因此异步执行仍然没有意义.

And use ToArrayAsyncSafe instead of ToArrayAsync, which will fallback to synchronous enumeration in case IQueryable is not IDbAsyncEnumerable. In your case this only happens when query is really in-memory list and not query, so async execution does not make sense anyway.

这篇关于ToArrayAsync()抛出“源IQueryable不实现IAsyncEnumerable".的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆