实体框架在记录上调用MAX为null

ble*_*evo 48 entity-framework

在IQueryable上调用Max()并且没有记录时,我得到以下异常.

转换为值类型"Int32"失败,因为实现值为null.结果类型的泛型参数或查询必须使用可空类型.

var version = ctx.Entries
    .Where(e => e.Competition.CompetitionId == storeCompetition.CompetitionId)
    .Max(e => e.Version);
Run Code Online (Sandbox Code Playgroud)

现在我明白为什么会发生这种情况我的问题是如果表格可以为空,那么最好的方法是如何做到这一点.下面的代码可以解决这个问题,但是它的丑陋是否没有MaxOrDefault()概念?

int? version = ctx.Entries
    .Where(e => e.Competition.CompetitionId == storeCompetition.CompetitionId)
    .Select(e => (int?)e.Version)
    .Max();
Run Code Online (Sandbox Code Playgroud)

div*_*ega 86

是的,转换为Nullable of T是处理LINQ to Entities查询中的问题的推荐方法.拥有一个具有正确签名的MaxOrDefault()方法听起来像一个有趣的想法,但是你只需要为每个提出这个问题的方法提供一个额外的版本,这个版本不能很好地扩展.

这是CLR中的工作方式与它们在数据库服务器上的实际工作方式之间的许多不匹配之一.Max()方法的签名已经这样定义,因为结果类型应该与CLR上的输入类型完全相同.但是在数据库服务器上,结果可以为null.出于这个原因,您需要将输入(尽管取决于您编写查询的方式,可能足以将输出强制转换)转换为Nullable of T.

这是一个看起来比上面简单的解决方案:

var version = ctx.Entries 
    .Where(e => e.Competition.CompetitionId == storeCompetition.CompetitionId) 
    .Max(e =>(int?)e.Version);
Run Code Online (Sandbox Code Playgroud)

希望这可以帮助.


小智 22

尝试此操作为最大值创建默认值.

int version = ctx.Entries 
    .Where(e => e.Competition.CompetitionId == storeCompetition.CompetitionId) 
    .Max(e =>(int?)e.Version) ?? 0;
Run Code Online (Sandbox Code Playgroud)

  • 接受的答案返回一个可以为空的int.你的答案是一个简单的方法来返回一个不可为空的int,这对我更有帮助. (6认同)

Cod*_*ely 8

您可以编写一个这样的简单扩展方法,如果不存在任何记录,则返回类型T的默认值,然后将Max应用于该值或查询是否存在记录.

public static T MaxOrEmpty<T>(this IQueryable<T> query)
{
    return query.DefaultIfEmpty().Max();
}
Run Code Online (Sandbox Code Playgroud)

你可以像这样使用它

maxId = context.Competition.Select(x=>x.CompetitionId).MaxOrEmpty();
Run Code Online (Sandbox Code Playgroud)