EF核心:执行MaxAsync

时间:2019-01-08 19:01:53

标签: c# asp.net entity-framework asp.net-core

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

示例:

数据表:Id, ForeignId, OrderIndex

所以我在做:

var highestOrderIndex = await _context
                .ExampleDbSet
                .Where(x =>
                    x.ForeignId == foreignId)
                .MaxAsync(x =>
                    x.OrderIndex);

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

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

谢谢

5 个答案:

答案 0 :(得分:6)

实际上,利用诸如MinMax之类的聚合方法抛出的事实,这是一种相当优雅的方法(与其他答案中建议的相比,性能更高,因为它仅执行单个数据库查询) Sequence contains no element仅在与不可为空的重载一起使用时例外,但可为空的重载只是返回null

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

.MaxAsync(x => (int?)x.OrderIndex);

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

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

答案 1 :(得分:3)

您可以查找是否存在任何记录,如果存在,则查找最大值。像这样:

var query = _context.ExampleDbSet
                .Where(x => x.ForeignId == foreignId);

var itemsExist = await query.AnyAsync();
int maxOrderIndex = 0;

if(itemsExist)
{
    maxOrderIndex = await query.MaxAsync(x => x.OrderIndex);
}

在这里,您不必从数据库中检索所有项目,只需检查是否存在一条记录要快得多,并且还可以使该方法保持异步。

答案 2 :(得分:2)

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

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

答案 3 :(得分:1)

如果默认值为您要获得的默认值(如果没有结果),则其性能比MaxAsync好一点。

var highestOrderIndex = await _context.ExampleDbSet
    .Where(x => x.ForeignId == foreignId)
    .OrderByDescending(x => x.OrderIndex)
    .Select(x => x.OrderIndex)
    .FirstOrDefaultAsync();

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

答案 4 :(得分:0)

您可以在 MaxAsync 之前使用 DefaultIfEmpty 和 Select。

        var highestOrderIndex = await _context
            .ExampleDbSet
            .Where(x =>
                x.ForeignId == foreignId)
            .Select(x => x.OrderIndex)
            .DefaultIfEmpty() // default is 0 if OrderIndex is int or long
             // .DefaultIfEmpty(-1) // default is -1
            .MaxAsync();