如果为空查询,则返回最大值

Nao*_*aor 151 .net c# linq lambda entity-framework

我有这个问题:

int maxShoeSize = Workers
    .Where(x => x.CompanyId == 8)
    .Max(x => x.ShoeSize);
Run Code Online (Sandbox Code Playgroud)

maxShoeSize如果公司8根本没有工人,那将会是什么?

更新:
如何更改查询以获得0而不是异常?

小智 266

int maxShoeSize = Workers.Where(x => x.CompanyId == 8)
                         .Select(x => x.ShoeSize)
                         .DefaultIfEmpty(0)
                         .Max();
Run Code Online (Sandbox Code Playgroud)

零输入DefaultIfEmpty不是必需的.

  • 如果类型不可为空,则**不适用于 EF Core 3.1 及更高版本**。原因是所有条目都有一个左连接,对于不可为空的类型将失败。使用 `Workers.Where(...).Max(x => (int?)x) ?? 0;`。这会直接在 sql 中生成高效的最大查询。 (5认同)
  • 关于问题的第一部分,这里没有完全回答:根据[官方文档](https://docs.microsoft.com/en-us/dotnet/api/system.linq.enumerable.max?view =netframework-4.7.2#System_Linq_Enumerable_Max__1_System_Collections_Generic_IEnumerable___0__),如果_empty_序列的泛型类型是引用类型,则得到null。否则,根据[这个问题](/sf/ask/869027211/),调用`Max()`空序列会导致错误。 (2认同)

Cpt*_*bby 55

我知道这是一个老问题,并且接受的答案有效,但是这个问题回答了我的问题,即这样一个空集是否会导致异常或default(int)结果.

然而,接受的答案,虽然它确实有效,但不是理想的解决方案恕我直言,这里没有给出.因此,我在我自己的答案中提供它,以帮助任何正在寻找它的人.

OP的原始代码是:

int maxShoeSize = Workers.Where(x => x.CompanyId == 8).Max(x => x.ShoeSize);
Run Code Online (Sandbox Code Playgroud)

这就是我写它以防止异常并提供默认结果的方法:

int maxShoeSize = Workers.Where(x => x.CompanyId == 8).Max(x => x.ShoeSize as int?) ?? 0;
Run Code Online (Sandbox Code Playgroud)

这会导致Max函数的返回类型int?,它允许null结果,然后??null结果替换0.


编辑
只是为了澄清评论中的内容,Entity Framework目前不支持该as关键字,因此在使用EF时编写它的方法是:

int maxShoeSize = Workers.Where(x => x.CompanyId == 8).Max<[TypeOfWorkers], int?>(x => x.ShoeSize) ?? 0;
Run Code Online (Sandbox Code Playgroud)

由于[TypeOfWorkers]可能是一个很长的类名并且编写起来很乏味,所以我添加了一个扩展方法来帮助.

public static int MaxOrDefault<T>(this IQueryable<T> source, Expression<Func<T, int?>> selector, int nullValue = 0)
{
    return source.Max(selector) ?? nullValue;
}
Run Code Online (Sandbox Code Playgroud)

这只手柄int,但同样可以做的long,double或者你需要的任何其他类型的值.使用这个扩展方法非常简单,你只需传入你的选择器函数,并可选择包含一个用于null的值,默认为0.所以上面的内容可以像这样重写:

int maxShoeSize = Workers.Where(x => x.CompanyId == 8).MaxOrDefault(x => x.ShoeSize);
Run Code Online (Sandbox Code Playgroud)

希望这可以帮助人们更多.

  • 好方案!更受欢迎的`DefaultIfEmpty`答案仅在"Max"没有进行评估时才有效. (3认同)
  • 扩展方法的通用版本:`public static TResult MaxOrDefault&lt;TElement, TResult&gt;(this IQueryable&lt;TElement&gt; items, Expression&lt;Func&lt;TElement, TResult&gt;&gt; selector, TResult defaultValue = default) where TResult : struct =&gt; items. Select(selector).Max(item =&gt; (TResult?)item) ?? 默认值;` (2认同)

Fré*_*idi 31

在这种情况下,Max()不会返回任何内容.

它将引发InvalidOperationException,因为源不包含任何元素.

  • 如果列表中的对象是不可空类型,它只会引发“InvalidOperationException”:https://docs.microsoft.com/en-us/dotnet/api/system.linq.enumerable.max?view=netcore- 3.1 (3认同)

Che*_*hen 17

int maxShoeSize = Workers.Where(x => x.CompanyId == 8)
                     .Select(x => x.ShoeSize)
                     .DefaultIfEmpty()
                     .Max();
Run Code Online (Sandbox Code Playgroud)


abk*_*sta 8

如果这是Linq to SQL,我不喜欢使用,Any()因为它会导致对SQL Server的多次查询。

如果ShoeSize不是可为空的字段,则仅使用.Max(..) ?? 0将不起作用,但将执行以下操作:

int maxShoeSize = Workers.Where(x = >x.CompanyId == 8).Max(x => (int?)x.ShoeSize) ?? 0;
Run Code Online (Sandbox Code Playgroud)

它绝对不会更改发出的SQL,但是如果序列为空,则确实会返回0,因为它将更改Max()为返回int?而不是int


Sla*_*uma 5

int maxShoeSize=Workers.Where(x=>x.CompanyId==8)
    .Max(x=>(int?)x.ShoeSize).GetValueOrDefault();
Run Code Online (Sandbox Code Playgroud)

(假设ShoeSize类型为int

如果WorkersDbSetObjectSet来自实体框架,您的初始查询将抛出InvalidOperationException,但不会抱怨空序列,而是抱怨物化值 NULL 无法转换为int.