EF核心:执行MaxAsync时,序列不包含任何元素

huc*_*ius 5 c# asp.net entity-framework asp.net-core

我在ASP核心API项目中使用ef核心。我必须找到最高顺序的索引。

例:

数据表: Id, ForeignId, OrderIndex

所以我在做:

var highestOrderIndex = await _context
                .ExampleDbSet
                .Where(x =>
                    x.ForeignId == foreignId)
                .MaxAsync(x =>
                    x.OrderIndex);
Run Code Online (Sandbox Code Playgroud)

问题是示例数据库集包含0个元素时。这将引发异常:Sequence contains no element

有没有一种优雅的方法可以做到这一点?因为我不想从数据库中获取所有元素。而且应该是异步的。

谢谢

Iva*_*oev 16

实际上,通过利用像这样的聚合方法Min,仅当与不可为空的重载一起使用时才Max抛出Sequence contains no element异常,而实际上可以为空的重载,是一种相当优雅的方法(与其他答案中建议的相比,性能更高,因为它只执行一个数据库查询)返回null

因此,您所需要做的就是将不可为空的属性类型提升为相应的可为空类型。例如,如果OrderIndex类型为int,则对查询的唯一更改可能是

.MaxAsync(x => (int?)x.OrderIndex);
Run Code Online (Sandbox Code Playgroud)

请注意,这还会将接收变量的类型更改highestOrderIndexint?。您可以检查null并做出相应的反应,或者可以简单地将聚合函数调用与??运算符结合起来并提供一些默认值,例如

var highestOrderIndex = (await _context.ExampleDbSet
    .Where(x => x.ForeignId == foreignId)
    .MaxAsync(x => (int?)x.OrderIndex)) ?? -1; // or whatever "magic" number works for you
Run Code Online (Sandbox Code Playgroud)


Lar*_*ars 6

MaxAsync如果默认值是您想要获得的值,并且没有结果,则另一种性能比 更好的方法:

var highestOrderIndex = await _context.ExampleDbSet
    .Where(x => x.ForeignId == foreignId)
    .OrderByDescending(x => x.OrderIndex)
    .Select(x => x.OrderIndex)
    .FirstOrDefaultAsync();
Run Code Online (Sandbox Code Playgroud)

TOP比聚合函数更快,查看 SQL Server 中的执行计划。


Kev*_*vin 5

执行 anAnyAsync和 aMaxAsync将导致两个单独的数据库调用。您可以通过确保序列包含“默认”最小值来将其压缩为一个。在任何使用 Linq Max/Min 方法的地方,这都是一个有用的技巧,而不仅仅是在数据库代码中:

context.ExampleDbSet
    .Where(w => w.ForeignId == foreignId)
    .Select(s => s.OrderIndex)
    .Concat(new[] { 0 })
    .MaxAsync();
Run Code Online (Sandbox Code Playgroud)