我正在编写一个非常非常简单的查询,它只是根据其唯一Id从集合中获取文档。经过一些挫折(我是mongo和async/await编程模型的新手),我弄明白了:
IMongoCollection<TModel> collection = // ...
FindOptions<TModel> options = new FindOptions<TModel> { Limit = 1 };
IAsyncCursor<TModel> task = await collection.FindAsync(x => x.Id.Equals(id), options);
List<TModel> list = await task.ToListAsync();
TModel result = list.FirstOrDefault();
return result;
它工作,太好了!但是我一直看到一个"查找"方法的引用,我解决了这个问题:
IMongoCollection<TModel> collection = // ...
IFindFluent<TModel, TModel> findFluent = collection.Find(x => x.Id == id);
findFluent = findFluent.Limit(1);
TModel result = await findFluent.FirstOrDefaultAsync();
return result;
事实证明,这也有效,太棒了!
我相信我们有两种不同的方法来达到这些结果是有一些重要的原因的。这些方法之间的区别是什么?为什么我应该选择其中一个而不是另一个?
区别在于语法。Find
和FindAsync
都允许构建具有相同性能的异步查询,只有
FindAsync
返回游标,其中不会一次加载所有文档,并提供从DB游标中逐一检索文档的接口。在查询结果非常大的情况下非常有用。
Find
通过方法ToListAsync
为您提供更简单的语法,其中它在内部从游标检索文档,而一次返回所有文档。
想象你在一个web请求中执行这段代码,通过调用find方法,请求的线程将被冻结,直到数据库返回结果,这是一个同步调用,如果它是一个长时间的数据库操作,需要几秒钟才能完成,你将有一个线程可用来服务web请求,只是等待数据库返回结果,浪费宝贵的资源(线程池中的线程数量是有限的)。
使用FindAsync, web请求的线程在等待数据库返回结果时将是空闲的,这意味着在数据库调用期间,该线程可以自由地参加另一个web请求。当数据库返回结果时,代码继续执行。
对于长时间的操作,如从文件系统读/写,数据库操作,与其他服务通信,使用异步调用是一个好主意。因为当你在等待结果时,线程可以为另一个web请求服务。看看这篇微软文章https://msdn.microsoft.com/en-us/magazine/dn802603.aspx