[英]Getting mongodb documents but ToListAsync on Iqueriable throws exception The source IQueryable doesn't implement IAsyncEnumerable
I am using MongoDB.Driver 2.10.4我正在使用 MongoDB.Driver 2.10.4
I want to get all documents that have an id in a list of ids that I get from my controller我想从我的 controller 获得的 id 列表中获取所有具有 id 的文档
I am doing something like this我正在做这样的事情
var pending_processes = mongo_context.collectionName
.AsQueryable()
.Where(x => request.ids.Contains(x.Id))
.Select(x => new ViewModel()
{
process_id = x.Id,
date = not important just accessing the x object
state = new States()
{
timeline = x.states.timeline,
part = x.states.part,
}
}).ToList();
The code above works fine but if I make my function async and do an await and replace ToList by ToListAsync I get the following error上面的代码工作正常,但如果我让我的 function 异步并执行等待并用 ToListAsync 替换 ToList,我会收到以下错误
The source IQueryable doesn't implement IAsyncEnumerable<Application.Process.Query.GetPendingProcesses.ViewModel>. Only sources that implement IAsyncEnumerable can be used for Entity Framework asynchronous operations.
Clearly there is something I am not getting here my concern is I don't want my code to run synchronously this would be really bad.很明显,我没有到达这里我担心的是我不希望我的代码同步运行,这真的很糟糕。 usually when dealing with postgresql context I always use the ToListAsync but here in order to use linq with mongo i had to use AsQueryable() and AsQueryable as I understand it does not get the data it's a normal query that I need to execute afterwards but when I use with it ToList everything works but when I use ToListAsync I get the error.
通常在处理 postgresql 上下文时,我总是使用 ToListAsync 但在这里为了将 linq 与 mongo 一起使用,我必须使用 AsQueryable() 和 AsQueryable,因为据我所知它没有得到数据,这是一个正常的查询,我需要在之后执行但是当我使用它 ToList 一切正常,但是当我使用 ToListAsync 时出现错误。
I just want to know what is behind all of this and is the code above synchronous or asynchronous?我只想知道这一切的背后是什么,上面的代码是同步的还是异步的?
Sure you can keep it asynchronous, but first you have switch out AsQueryable
to some other method which returns back and IQueryable
.当然你可以让它保持异步,但首先你已经将
AsQueryable
切换到返回和IQueryable
的其他方法。
In a nutshell ToListAsync()
works on a IQueryable<T>
only , when you turned it in to a IEnumerable via AsEnumerable() you lost the ability to call it.简而言之
ToListAsync()
仅适用于IQueryable<T>
,当您通过AsEnumerable()将其转换为IEnumerable时,您将失去调用它的能力。 Its explained well here它在这里解释得很好
You have a couple of choices, either implement IDbAsyncEnumerable see here or change the result list you have into an async list
with Task.FromResult()
您有几个选择,要么实现 IDbAsyncEnumerable 参见此处,要么使用
Task.FromResult()
将您拥有的结果列表更改为async list
Option 1:选项1:
// try this in your controller
public async Task<List<PeopleStatesType>> GetAsyncStatesList()
{
//for e.g.
List<PeopleType> peopleList = new List<PeopleType>()
{
new PeopleType(){ Name = "Frank", Gender = "M" },
new PeopleType(){ Name = "Rose", Gender = "F" } //..
};
var result = from e in peopleList
where e.Gender == "M"
select e;
return await Task.FromResult(result.ToList());
}
Option 2: Use this class选项 2:使用此class
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;
}
}
// FindAll: with a condition like .Find(x => x.user == "Jone Doe")
// see [here][3]
var task = collection.Find(p => true).ToListAsync();
Update Option 3 : Simple Async Get更新选项 3 :简单异步获取
public async Task<IEnumerable<MyMongoEntity>> Where(Expression<Func<MyMongoEntity, bool>> expression = null)
{
return await context.GetCollection<MyMongoEntity>(typeof(MyMongoEntity).Name, expression).Result.ToListAsync();
}
Based on your comment, for a simple get documents collection, this helper should work.根据您的评论,对于一个简单的获取文档集合,这个助手应该可以工作。
From your error, it seems like the mongo_context.collectionName
is returning something from Entity Framework?从您的错误来看,似乎
mongo_context.collectionName
从实体框架返回了一些东西?
Only sources that implement IAsyncEnumerable can be used for Entity Framework asynchronous operations.
只有实现 IAsyncEnumerable 的源才能用于实体框架异步操作。
Make sure you are calling the AsQueryable
extension method directly on the Mongo collection .确保直接在 Mongo 集合上调用
AsQueryable
扩展方法。 (Your code just shows mongo_context.collectionName.AsQueryable()
so I'm not sure you're doing that) (您的代码仅显示
mongo_context.collectionName.AsQueryable()
所以我不确定您是否这样做)
Hooking into the LINQ provider requires getting access to an
IQueryable
instance.挂钩到 LINQ 提供程序需要访问
IQueryable
实例。 The driver provides anAsQueryable
extension method onIMongoCollection
.驱动程序在
IMongoCollection
上提供了AsQueryable
扩展方法。var collection = db.GetCollection<Person>("people"); var queryable = collection.AsQueryable();
Reference: https://mongodb.github.io/mongo-csharp-driver/2.10/reference/driver/crud/linq/#queryable
参考: https://mongodb.github.io/mongo-csharp-driver/2.10/reference/driver/crud/linq/#queryable
The AsQueryable
extension above actually returns an IQueryable
instance that implements IMongoQueryable
and has all the same async
extensions that other ORMs (Entity Framework, NHibernate, etc.) have - including ToListAsync
.上面的
AsQueryable
扩展实际上返回了一个IQueryable
实例,该实例实现IMongoQueryable
并具有其他 ORM(实体框架、NHibernate 等)具有的所有相同的async
扩展 - 包括ToListAsync
。
I just changed the way I query my context usind Find and and ForEachAsync and now all works well I just did not use AsQueryable because the mongodb driver as I understand it use these other functions but provides a way to use linq so I used the default methods without linq我只是更改了使用 Find 和 ForEachAsync 查询上下文的方式,现在一切正常我只是没有使用 AsQueryable,因为据我了解,mongodb 驱动程序使用这些其他功能,但提供了一种使用 linq 的方法,因此我使用了默认方法无 linq
var result = new GetPendingProcessesViewModel();
var filter = Builders<Domain.MongoDocuments.Process>.Filter
.Where(x => own_processes.Contains(x.Id));
await _elba_mongo_context.process.Find(filter)
.ForEachAsync(x=>result.pending_processes_own.Add(
new GetPendingProcessesViewModelItem()
{
process_id = x.Id,
state = new States()
{
timeline = x.states.timeline,
part = x.states.part,
supplier = x.states.supplier
}}));
this is the link where you can get the documentation and references for your mongodb driver version https://mongodb.github.io/mongo-csharp-driver/这是您可以获得 mongodb 驱动程序版本https://mongodb.github.io/mongo-csharp-driver的文档和参考的链接
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.