EF Core Average без последовательности - PullRequest
0 голосов
/ 29 января 2019

У меня проблема, когда из списка нужно выполнить группировку по свойствам и взять среднее или сумму определенных свойств. Я получаю сообщение об ошибке. Последовательность не содержит элементов.Чем я ставлю DefaultIfEmpty, чем получаю другую ошибку NullReferenceException: ссылка на объект не установлена ​​для экземпляра объекта.

Код такой:

var items = _repository.GetAllItems();
var groupedItems = items.GroupBy(x=> new {Year = x.DateCreate.Year, Month = x.DateCreate.Month})
.Select(s=> new ItemForListViewModel(){
   Year = s.Key.Year,
   Month = s.Key.Month,
   AvgQnt = s.Where(x=>x.Price > 10).Average(x=>x.Qnt)
}).ToList();

Кодсверху выдает ошибку. Последовательность не содержит элементов, которые я изменяю

 var groupedItems = items.GroupBy(x=> new {Year = x.DateCreate.Year, Month = x.DateCreate.Month})
    .Select(s=> new ItemForListViewModel(){
       Year = s.Key.Year,
       Month = s.Key.Month,
       AvgQntPrice10 = s.Where(x=>x.Price > 10).DefaultIfEmpty().Average(x=>x.Qnt),
AvgQntPrice100 = s.Where(x=>x.Price > 100).DefaultIfEmpty().Average(x=>x.Qnt
    }).ToList();

Чем я получаю новую ошибку: NullReferenceException: Ссылка на объект не установлена ​​на экземпляр объекта.

В базе данных, если я запускаю запрос, я получаю 0 для AvgQntPrice10 и пример 15 для AvgQntPrice100, что правильно.

С уважением, Даниэль

1 Ответ

0 голосов
/ 29 января 2019

Проблема, конечно, в том, что после DefaultIfEmpty параметр x из Average вызовов может быть null (значение по умолчанию CLR для ссылочных типов).

Вернуться к исходной проблеме - Последовательность не содержит элементов исключение при вызове Min, Max или Average в пустой коллекции.Его можно правильно решить двумя способами.

Во-первых, вместо DefaultIfEmpty().Average(selector), используйте не очень лаконичную, но рабочую комбинацию Select(selector).DefaultIfEmpty().Average(), например,

AvgQntPrice10 = s.Where(x => x.Price > 10).Select(x => x.Qnt).DefaultIfEmpty().Average(),
AvgQntPrice100 = s.Where(x => x.Price > 100).Select(x => x.Qnt).DefaultIfEmpty().Average()

Second (ия предпочитаю использовать тот факт, что перегрузочные методы Min, Max и Average, допускающие значение NULL, не генерируют Последовательность не содержит элементов исключение для пустой коллекции, но вместо этого возвращает null,Поэтому все, что вам нужно, - привести тип выражения селектора к соответствующему типу, допускающему значение NULL, и при необходимости использовать ?? в результате результата метода агрегирования, чтобы назначить специальное значение для этого случая (например, 0).

Например, если тип Qnt равен int (если нет, используйте правильный тип), вышеприведенное можно записать как

AvgQntPrice10 = s.Where(x => x.Price > 10).Average(x => (int?)x.Qnt) ?? 0,
AvgQntPrice100 = s.Where(x => x.Price > 100).Average(x => (int?)x.Qnt) ?? 0
...