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


174

我有这个查询:

int maxShoeSize = Workers
    .Where(x => x.CompanyId == 8)
    .Max(x => x.ShoeSize);

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

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


Naor:您听说过LINQPad吗?
米奇·

3
我不明白您为什么会问:“里面会有什么maxShoeSize?” 如果您已经尝试过。
jwg

@jwg:我想我想看看您是否知道答案:)最终,我有了一种更好的方式来完成所要的事情,这就是我的意思。
Naor

@Naor,这不是一个猜谜游戏。我也将否决原始问题。如果您知道答案,请给我们,否则您看起来很懒。刚才我正要做同样的问题,并且我准备了包括异常消息在内的所有信息。
胡安·卡洛斯·奥罗佩萨

Answers:


297
int maxShoeSize = Workers.Where(x => x.CompanyId == 8)
                         .Select(x => x.ShoeSize)
                         .DefaultIfEmpty(0)
                         .Max();

零输入DefaultIfEmpty不是必需的。


作品:)但是在我的代码上,DefaultIfEmpty中的零是必要的。
卡洛斯·特诺里奥·佩雷斯

1
关于问题的第一部分,此处没有完全回答:根据官方文档,如果序列的泛型是引用类型,则为null。否则,根据此问题,调用Max()空序列将导致错误。
RaimundKrämer19年

59

我知道这是一个古老的问题,可以接受的答案有效,但是这个问题回答了我有关这样一个空集是导致异常还是default(int)结果的问题。

但是,虽然可以接受,但是可以接受的答案不是IMHO的理想解决方案,此处未给出。因此,我以自己的答案提供它,以帮助正在寻找它的任何人。

OP的原始代码为:

int maxShoeSize = Workers.Where(x => x.CompanyId == 8).Max(x => x.ShoeSize);

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

int maxShoeSize = Workers.Where(x => x.CompanyId == 8).Max(x => x.ShoeSize as int?) ?? 0;

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


编辑
只是为了澄清注释中的内容,实体框架当前不支持该as关键字,因此在使用EF时编写该关键字的方式为:

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

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

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

这只手柄int,但同样可以为完成longdouble或任何其他价值,你需要的类型。使用此扩展方法非常简单,只需传入选择器函数,并可以选择包含要用于null的值(默认为0)。因此,可以将上述内容重写为:

int maxShoeSize = Workers.Where(x => x.CompanyId == 8).MaxOrDefault(x => x.ShoeSize);

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


3
很好的解决方案!DefaultIfEmpty仅当Max不进行评估时,比较流行的答案才有效。
McGuireV10年

@ McGuireV10是的,Select当我将要使用类似Max结果的聚合函数时,我通常不喜欢用作中间人。我还认为(我尚未测试过)生成的SQL将通过执行此操作使用额外的子选择查询,而我的SQL只会通过返回null来处理空集。感谢您的支持和反馈!;)
CptRobby

@ McGuireV10同样,如果ShoeSize实际位于相关Uniform实体中,则不使用Workers.Where(x => x.CompanyId == 8).Select(x => x.Uniform).Max(x => x.ShoeSize),而是将整个求值保留在Max函数中:Workers.Where(x => x.CompanyId == 8).Max(x => x.Uniform.ShoeSize)。我更喜欢在查询中使用尽可能少的方法,以使EF在决定如何有效构造查询时拥有最大的自由度。;-)
CptRobby

1
我无法在EntityFramework中使用它。谁能阐明任何想法?(使用DefaultIfEmpty技术有效)。
Moe Sisko

1
扩展方法的通用版本:public static TResult MaxOrDefault<TElement, TResult>(this IQueryable<TElement> items, Expression<Func<TElement, TResult>> selector, TResult defaultValue = default) where TResult : struct => items.Select(selector).Max(item => (TResult?)item) ?? defaultValue;
relative_random


17
int maxShoeSize = Workers.Where(x => x.CompanyId == 8)
                     .Select(x => x.ShoeSize)
                     .DefaultIfEmpty()
                     .Max();

10

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

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

int maxShoeSize = Workers.Where(x = >x.CompanyId == 8).Max(x => (int?)x.ShoeSize) ?? 0;

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


4
int maxShoeSize=Workers.Where(x=>x.CompanyId==8)
    .Max(x=>(int?)x.ShoeSize).GetValueOrDefault();

(假设ShoeSize类型为int

如果WorkersDbSetObjectSet来自Entity Framework,则您的初始查询将引发InvalidOperationException,但不是抱怨空序列,而是抱怨实例化值NULL无法转换为int


2

Max将抛出System.InvalidOperationException“序列不包含任何元素”

class Program
{
    static void Main(string[] args)
    {
        List<MyClass> list = new List<MyClass>();

        list.Add(new MyClass() { Value = 2 });

        IEnumerable<MyClass> iterator = list.Where(x => x.Value == 3); // empty iterator.

        int max = iterator.Max(x => x.Value); // throws System.InvalidOperationException
    }
}

class MyClass
{
    public int Value;
}

2

注意:的查询DefaultIfEmpty()可能会明显变慢。就我而言,这是一个简单的查询.DefaultIfEmpty(DateTime.Now.Date)

我懒得剖析它,但是显然EF试图获取所有行然后Max()取值。

结论:有时处理InvalidOperationException可能是更好的选择。


0

您可以在其中使用三元数.Max()来处理谓词并设置其值。

// assumes Workers != null && Workers.Count() > 0
int maxShoeSize = Workers.Max(x => (x.CompanyId == 8) ? x.ShoeSize : 0);

如果可能,您需要将Workers集合处理为null / empty,但这取决于您的实现。


0

您可以尝试以下方法:

int maxShoeSize = Workers.Where(x=>x.CompanyId == 8).Max(x => x.ShoeSize) ?? 0;

我认为这将失败,因为Max期望一个int并且它得到一个null;因此在null推算运算符生效之前已经发生了错误。
d219

0

您可以在执行Max()之前检查是否有任何工作程序。

private int FindMaxShoeSize(IList<MyClass> workers) {
   var workersInCompany = workers.Where(x => x.CompanyId == 8);
   if(!workersInCompany.Any()) { return 0; }
   return workersInCompany.Max(x => x.ShoeSize);
}
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.