许多嵌套的聚合异常

Many nested AggregateExceptions

使用 Entity Framework 7,我在一些 linq 上犯了一个简单的错误(使用了 Skip 并忘记包含我的 OrderBy 子句)。

由此引发的异常包括多个嵌套聚合异常。

生成(并捕获)异常的代码是:

int[] newIds;
try
{
    newIds = await db.Products
        .Where(p => p.PortalId == portalId)
        .Skip(ids.ProductIds.Count) //Skip the rows already read
        .Take(takeTotal) //get the next block
        .Select(p => p.ProductId)
        .ToArrayAsync();
}
catch (AggregateException ex)
{
    Console.WriteLine(ex.Message);
    newIds = new int[] { };
}

上面的代码在从 Asp.Net 5 WebApi 控制器调用的 repo class 中。所有级别的调用都使用 async-await。

然而,我从中得到的聚合异常是(从上面显示的 catch 块转储到立即 window):

System.AggregateException: One or more errors occurred. ---> System.AggregateException: One or more errors occurred. ---> System.AggregateException: One or more errors occurred. ---> System.AggregateException: One or more errors occurred. ---> System.AggregateException: One or more errors occurred. ---> System.AggregateException: One or more errors occurred. ---> System.InvalidOperationException: A query containing the Skip operator must include at least one OrderBy operation. at Microsoft.Data.Entity.Relational.Query.Sql.DefaultSqlQueryGenerator.GenerateLimitOffset(SelectExpression selectExpression) at Microsoft.Data.Entity.Relational.Query.Sql.DefaultSqlQueryGenerator.VisitSelectExpression(SelectExpression selectExpression) at Microsoft.Data.Entity.Relational.Query.Expressions.SelectExpression.Accept(ExpressionTreeVisitor visitor) at Microsoft.Data.Entity.Relational.Query.Sql.DefaultSqlQueryGenerator.GenerateSql(SelectExpression selectExpression, IDictionary`2 parameterValues) etc etc

这里实际的异常已经被一大堆聚合异常层(6 个嵌套层)包裹起来。我明白为什么我会得到一个聚合异常,但想知道为什么会有这么多异常?更重要的是,因为在异常冒泡回到控制器入口点之前我正在查看异常。

这是否是多层异步等待的结果(我认为我没有多达 6 层)还是 EF7 实现中的问题?

目前使用的是 EF 7 版本 7.0.0-beta4。

正如 the MSDN page on Task<T> 所解释的那样,Task 抛出的所有异常在被抛出到等待代码之前都包含在 AggregateException 中。如果您使用多个 async/await 级别并且没有在尽可能低的级别捕获此异常,那么每次它冒泡到另一个级别时,它都会再次包装,导致 AggregateExceptionAggregateException, 每次等待没抓到一个.

也可能是每个操作都算作自己的任务; IE。每次添加另一个操作时,结果都会从前一个操作中出来并返回到下一个操作中,每个操作都在等待前一个操作。看看:

newIds = await db.Products               // 1
    .Where(p => p.PortalId == portalId)  // 2
    .Skip(ids.ProductIds.Count)          // 3
    .Take(takeTotal)                     // 4
    .Select(p => p.ProductId)            // 5
    .ToArrayAsync();                     // 6

六层事物,每一层都在等待上一层的结果。六 AggregateException 层。现在,您的异常是由六个中的第三个引起的,但从错误的性质来看,它很可能来自 EF 在执行任何查询之前读取您的整个查询的部分,并且在这样做时发现您'我有一个 .Skip() 没有匹配的 .OrderBy()

正如 Stephen Cleary 在评论中提醒我的那样,虽然你 await return Task<T> 的东西也会为你做一定程度的展开,所以 await 的行为不像 Task<T>.Result,这意味着 await 应该 抛出实际异常而不将其包装在 AggregateException 中。这一切意味着我们最多只有一半的答案(这有点尴尬,因为它已经被接受了)。老实说,我建议你取消接受这个答案,这样其他人就不会跳过你的问题,看看是否有其他人知道一些可以填补空白的东西。

与链中调用的方法数量无关。您只需调用 ToArrayAsync。

我认为问题出在Rx.NET。我发送了一个 Pull Request 来修复它:https://github.com/aspnet/EntityFramework/issues/2192

https://github.com/Reactive-Extensions/Rx.NET/pull/131/files