许多嵌套的aggregateexception
本文关键字:aggregateexception 嵌套 许多 | 更新日期: 2023-09-27 17:49:02
使用Entity Framework 7时,我在linq上犯了一个简单的错误(使用Skip,忘记包含OrderBy子句)。
由this抛出的异常包括许多嵌套的聚合异常。
生成(并捕获)异常的代码是: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. js调用的repo类中。Net 5 WebApi控制器。所有级别的调用都使用async-await。
然而,我从这里得到的聚合异常是(这是从上面所示的catch块转储到直接窗口):
系统。AggregateException:发生了一个或多个错误。--->系统。AggregateException:发生了一个或多个错误。--->系统。AggregateException:发生了一个或多个错误。--->系统。AggregateException:发生了一个或多个错误。--->系统。AggregateException:发生了一个或多个错误。--->系统。AggregateException:发生了一个或多个错误。--->系统。InvalidOperationException:包含Skip操作符的查询必须包含至少一个OrderBy操作。在Microsoft.Data.Entity.Relational.Query.Sql.DefaultSqlQueryGenerator.GenerateLimitOffset (SelectExpressionselectExpression)Microsoft.Data.Entity.Relational.Query.Sql.DefaultSqlQueryGenerator.VisitSelectExpression (SelectExpressionselectExpression)Microsoft.Data.Entity.Relational.Query.Expressions.SelectExpression.Accept (ExpressionTreeVisitor访客)Microsoft.Data.Entity.Relational.Query.Sql.DefaultSqlQueryGenerator.GenerateSql (SelectExpressionselect表达式,字典' 2参数值等等
在这里,实际的异常最终被一大堆聚集异常层(6个嵌套层)包裹起来。我理解为什么我得到了一个汇总异常,但想知道为什么有这么多异常?更重要的是,在它冒泡回到控制器入口点之前,我正在查看异常。
这将是许多层的async-await的结果,(不认为我有多达6)或它可能是一个问题在EF7的实现?
当前使用的是EF 7 7.0.0-beta4版本
正如MSDN页面上Task<T>
解释的那样,Task
抛出的所有异常在被抛出到等待代码之前都被AggregateException
包装。如果你使用多个级别的async/await并且没有在尽可能低的级别捕获此异常,那么每次它出现在另一个级别时,它将再次被包装,导致AggregateException
在AggregateException
中,每次你等待而没有捕获。
也可以将每个操作算作自己的任务;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
六层东西,每一层都在等待前一层的结果。6个AggregateException
层。现在,您的异常是由六个中的第三个引起的,但是从错误的性质来看,它很可能来自EF在执行任何查询之前读取整个查询的部分,并且在这样做时发现您有一个.Skip()
而没有匹配的.OrderBy()
。
正如Stephen Cleary在评论中提醒我的那样,虽然await
返回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