У меня есть этот запрос:
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.