I have problem when from List want to do grouping by properties and take average or sum of specific properties I'm getting error Sequence does not contain elements. Than I put DefaultIfEmpty, than I get different error NullReferenceException: Object reference not set to an instance of an object.
Code is like this:
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();
Code from above gives error Sequence does not contain elements, than I change
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();
Than I get new error: NullReferenceException: Object reference not set to an instance of an object.
In database if I run query I get 0 for AvgQntPrice10 and example 15 for AvgQntPrice100 what is correct.
Regards, Danijel
The problem is of course that after DefaultIfEmpty
the parameter x
of Average
calls can be null
(the CLR default value for reference types).
Back to the original problem - Sequence does not contain elements exception when calling Min
, Max
or Average
on empty collection. It can be solved correctly in two ways.
First is, instead of DefaultIfEmpty().Average(selector)
, use the not so concise, but working combination Select(selector).DefaultIfEmpty().Average()
, eg
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 (and my preferred) is to utilize the fact the nullable overloads of the Min
, Max
and Average
methods do not throw Sequence does not contain elements exception for empty collection, but return null
instead. So all you need is to cast the selector expression type to the corresponding nullable type, and optionally use the ??
on the aggregate method result to assign a special value for that case (like 0
).
For instance, if the type of the Qnt
is int
(if not, use the proper type), the above could be written as
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
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.