Исключение при попытке отсортировать запрос linq по вложенному агрегированному значению - PullRequest
0 голосов
/ 30 сентября 2019

При попытке отсортировать результаты linq по агрегированному значению из нескольких вложенных полей возникает странная проблема. Та же проблема возникает для любого агрегатного метода (среднее, сумма, мин). Пробовал разные подходы для предотвращения исключения, но получение пустой ссылки или последовательности не содержит элементов (недопустимая операция).

Вот что я пытаюсь сделать - получить массив TopLevelItem, включающий два вложенных массива, и отсортировать его поагрегированное значение в массиве второго уровня. Некоторые списки элементов / подэлементов могут быть пустыми.

Вот пример кода, который выдает исключение нулевой ссылки (не могу выяснить, где именно это происходит, поскольку linq не дает мне много подсказок).

IQueryable<TopLevelItem> query = repository.TopLevelItems
                .Include(x => x.Items)
                .ThenInclude(x => x.Subitems);

var ordeByClause = x => x.Items.Sum(y => y.Subitems.Sum(z => z.NullableDecimalParameter ?? 0));

query = query.OrderBy(orderByClause);

var results = query.ToList();

Также пытался использовать select, но с тем же результатом:

var ordeByClause = x => x.Items.SelectMany(y => y.Subitems.Select(z => z.NullableDecimalParameter ?? 0).DefaultIfEmpty(0)).DefaultIfEmpty(0).Sum();

Есть идеи, что я пропускаю / делаю неправильно?


Редактировать

Я провел дальнейшее расследование, и, похоже, проблема в том, что массив x.Items равен нулю (не существует элементов для данного TopLevelItem). Linq генерирует следующий sql для каждой строки из результатов (что не очень эффективно):

exec sp_executesql N'SELECT SUM(COALESCE([y.SubItems].[NullableDecimalParameter], 0.0))
FROM [Items] AS [y0]
INNER JOIN [SubItems] AS [y.SubItems] ON [y0].[Id] = [y.SubItems].[ItemId]
WHERE @_outer_Id = [y0].[TopLevelItemId]',N'@_outer_Id uniqueidentifier',@_outer_Id='some_guid'

Поскольку массив Items равен null, весь запрос возвращает null, а linq завершается с ошибкой в ​​исключительной ситуации. Использование DefaultIfEmpty, похоже, изменяет только INNER JOIN для LEFT JOIN , но с тем же результатом.

Не уверен, что это ошибка в Linq или что-то в дизайне,но я не мог найти способ обойти это.

1 Ответ

2 голосов
/ 30 сентября 2019

Linq задерживает запрос оценки до тех пор, пока значение не будет повторено.

Это означает, что запрос (Include, ThenInclude, Sum, OrderBy) не будет выполнен, пока код не достигнетquery.ToList()

Если вы хотите узнать, где происходит исключение, разбейте запрос и оцените его с помощью .ToList()

...