在从数据库引擎返回实体时异步处理实体

Mik*_*sen 7 c# asynchronous entity-framework async-await entity-framework-6

在EF 6中,我想异步处理从数据库引擎返回的实体.

我知道我可以打电话ToListAsync(),ForEachAsync()也许他们会做我正在寻找的事情,但我不相信.我认为我要找的是两者的结合.

根据我的理解,ToListAsync()将在从数据库引擎读取整个查询并转换为实体时完成任务.这意味着您必须等待整个查询在开始处理之前返回.

我无法确定ForEachAsync()我正在寻找的是什么,但我假设,由于没有在其他地方找到信息,它ForEachAsync()只是在已经检索的集合上工作,并且每个项目的处理都是异步的.

理想的是,ForEachAsync()当从数据库引擎中检索数据时,(或另一种未知的方法)会调用该任务.

所以... ForEachAsync()实际上是这样做的,如果没有,有没有办法完成它?

想要这个的原因有两个:

  1. 大型查询不需要作为整个集合存储在内存中,因此可以节省内存占用并处理不受内存限制的更大结果集的能力
  2. 由于在数据检索的延迟期间处理每个项目,整个过程的持续时间可能会缩短

更新:基本上,如果在你打电话时为每个实体DbContext举起一个事件,我可以完成我想要的一切.因为我可以将实体排入单独的任务处理器,并且可以有效地处理实体并利用任何I/O延迟.我总是可以调整单独的任务处理器,所以我真的不需要EF来支持实体的异步处理,只是在每个实体加载时异步加载和触发事件/调用委托.OnEntityLoadedLoadAsync()

更新2:如果ForEachAsync()在实体被加载时被调用,那么这也将完成我所追求的目标.

i3a*_*non 3

ForEachAsync与 不同的是ToListAsync,它不会提前获取所有项目,而只是让您对其进行迭代。迭代就是async它本身。

QueryableExtensions.ForEachAsync代表们IDbAsyncEnumerable.ForEachAsync 这是

internal static async Task ForEachAsync(
    this IDbAsyncEnumerable source, Action<object> action, CancellationToken cancellationToken)
{
    DebugCheck.NotNull(source);
    DebugCheck.NotNull(action);

    cancellationToken.ThrowIfCancellationRequested();

    using (var enumerator = source.GetAsyncEnumerator())
    {
        if (await enumerator.MoveNextAsync(cancellationToken).WithCurrentCulture())
        {
            Task<bool> moveNextTask;
            do
            {
                cancellationToken.ThrowIfCancellationRequested();
                var current = enumerator.Current;
                moveNextTask = enumerator.MoveNextAsync(cancellationToken);
                action(current);
            }
            while (await moveNextTask.WithCurrentCulture());
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

您可以看到它与迭代的方式非常相似,IEnumerable但要async-await记住。而不是IEnumerable, GetEnumerator,IEnumerator我们MoveNextIDbAsyncEnumerable, GetAsyncEnumerator,IDbAsyncEnumeratorMoveNextAsync

MoveNextAsync允许在需要时实际异步检索项目。