问题描述
我在 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()
中调用它:
I call this in method 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 的源才能用于实体框架异步操作.
我已将 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"的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!