Максимальное возвращаемое значение, если пустой запрос - PullRequest
137 голосов
/ 06 августа 2011

У меня есть этот запрос:

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

Что будет в maxShoeSize, если в компании 8 вообще нет рабочих?

ОБНОВЛЕНИЕ:
Как изменить запрос, чтобы получить 0, а не исключение?

Ответы [ 11 ]

242 голосов
/ 06 августа 2011
int maxShoeSize = Workers.Where(x => x.CompanyId == 8)
                         .Select(x => x.ShoeSize)
                         .DefaultIfEmpty(0)
                         .Max();

Ноль в DefaultIfEmpty не обязателен.

50 голосов
/ 27 февраля 2016

Я знаю, что это старый вопрос, и принятый ответ работает, но этот вопрос ответил на мой вопрос о том, приведет ли такой пустой набор к исключению или результату default(int).

Однако принятый ответХотя это работает, не идеальное решение ИМХО, которое здесь не приводится.Таким образом, я предоставляю его в своем собственном ответе в интересах любого, кто его ищет.

Оригинальный код ОП был:

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.


РЕДАКТИРОВАТЬ
Просто чтобы уточнить кое-что из комментариев, Entity Framework в настоящее время не поддерживает ключевое слово 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 или для любого другого типа значения, который вам нужен.Использовать этот метод расширения очень просто: вы просто передаете свою функцию селектора и, необязательно, включаете значение, которое будет использоваться для нуля, по умолчанию равное 0. Таким образом, вышеприведенное можно переписать так:

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

Надеемсяэто помогает людям еще больше.

27 голосов
/ 06 августа 2011

Max () не будет ничего возвращать в этом случае.

Это повысит InvalidOperationException , так как источник не содержит элементов.

17 голосов
/ 06 августа 2011
int maxShoeSize = Workers.Where(x => x.CompanyId == 8)
                     .Select(x => x.ShoeSize)
                     .DefaultIfEmpty()
                     .Max();
4 голосов
/ 14 июля 2017

Если это Linq to 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.

3 голосов
/ 06 августа 2011
int maxShoeSize=Workers.Where(x=>x.CompanyId==8)
    .Max(x=>(int?)x.ShoeSize).GetValueOrDefault();

(при условии, что ShoeSize имеет тип int)

Если Workers - это DbSet или ObjectSet из Entity Framework, ваш начальный запрос выдаст InvalidOperationException, но не будет жаловаться на пустую последовательность, но будет жаловаться, что материализованное значение NULL не может быть преобразовано в int.

2 голосов
/ 10 декабря 2015

Примечание: запрос с DefaultIfEmpty() может быть значительно медленнее .В моем случае это был простой запрос с .DefaultIfEmpty(DateTime.Now.Date).

. Мне было лень его профилировать, но, очевидно, EF попытался получить все строки и затем принять значение Max().

Вывод: иногда обработка InvalidOperationException может быть лучшим выбором.

2 голосов
/ 06 августа 2011

Макс сгенерирует 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;
}
0 голосов
/ 03 мая 2017

Вы можете проверить, есть ли работники, прежде чем выполнять Макс ().

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);
}
0 голосов
/ 08 декабря 2016

Вы можете попробовать это:

int maxShoeSize = Workers.Where(x=>x.CompanyId == 8).Max(x => x.ShoeSize) ?? 0;
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...