У меня есть этот запрос:
int maxShoeSize=Workers.Where(x=>x.CompanyId==8).Max(x=>x.ShoeSize);
Что будет в maxShoeSize, если в компании 8 нет рабочих?
UPDATE:
Как я могу изменить запрос, чтобы получить 0, а не исключение?
У меня есть этот запрос:
int maxShoeSize=Workers.Where(x=>x.CompanyId==8).Max(x=>x.ShoeSize);
Что будет в maxShoeSize, если в компании 8 нет рабочих?
UPDATE:
Как я могу изменить запрос, чтобы получить 0, а не исключение?
int maxShoeSize = Workers.Where(x => x.CompanyId == 8)
.Select(x => x.ShoeSize)
.DefaultIfEmpty(0)
.Max();
Нуль в DefaultIfEmpty не нужен.
Я знаю, что это старый вопрос, и принятый ответ работает, но этот вопрос ответил на мой вопрос о том, приведет ли такой пустой набор к исключению или к результату 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.
Max() в этом случае ничего не вернет.
Он поднимет InvalidOperationException, поскольку источник не содержит элементов.
int maxShoeSize = Workers.Where(x => x.CompanyId == 8)
.Select(x => x.ShoeSize)
.DefaultIfEmpty()
.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;
}
int maxShoeSize=Workers.Where(x=>x.CompanyId==8)
.Max(x=>(int?)x.ShoeSize).GetValueOrDefault();
(предполагая, что ShoeSize имеет тип int)
Если Workers является DbSet или ObjectSet из Entity Framework, ваш первоначальный запрос будет вызывать InvalidOperationException, но не жалуется на пустую последовательность, но жалуется, что материализованное значение NULL не может быть преобразовано в int.
NB: запрос с DefaultIfEmpty() может быть значительно медленнее.
В моем случае это был простой запрос с .DefaultIfEmpty(DateTime.Now.Date).
Я был слишком ленив к профилю. Но, очевидно, EF попытался получить все строки, а затем взять значение Max().
Вывод: иногда обработка InvalidOperationException может быть лучшим выбором.
Для обработки предиката вы можете использовать тернар внутри .Max(),
// assumes Workers != null && Workers.Count() > 0
int maxShoeSize = Workers.Max(x => (x.CompanyId == 8) ? x.ShoeSize : 0);
Вам нужно будет обрабатывать коллекцию Workers, являющуюся нулевой/пустой, если это возможно, но это будет зависеть от вашей реализации.
Вы можете попробовать следующее:
int maxShoeSize = Workers.Where(x=>x.CompanyId == 8).Max(x => x.ShoeSize) ?? 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);
}
Если это 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.