我有一个疑问:

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

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

更新: 我如何改变查询,以获得0,而不是一个异常?


当前回答

注意:使用DefaultIfEmpty()的查询可能会显著变慢。 在我的情况下,这是一个简单的查询。defaultifempty (DateTime.Now.Date)。

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

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

其他回答

您可以在执行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);
}

我知道这是一个老问题,公认的答案是有效的,但这个问题回答了我关于这样一个空集是否会导致异常或默认(int)结果的问题。

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

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结果替换为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型,但同样的操作也可以用于long、double或任何其他您需要的值类型。使用这个扩展方法非常简单,只需传入选择器函数,并可选地包含一个用于null的值,该值默认为0。所以上面可以写成这样:

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

希望这能帮助到更多的人。

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

如果ShoeSize不是一个可空字段,那么使用.Max(..) ??0不能工作,但下面的可以:

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

它绝对不会改变发出的SQL,但如果序列为空,它会返回0,因为它改变了Max()以返回int?而不是int型。

你可以在.Max()中使用三元来处理谓词并设置它的值;

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

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

注意:使用DefaultIfEmpty()的查询可能会显著变慢。 在我的情况下,这是一个简单的查询。defaultifempty (DateTime.Now.Date)。

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

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