Как сделать так, чтобы Sum () возвращала 0 вместо 'null'? - PullRequest
0 голосов
/ 09 октября 2018

Я пытаюсь использовать LINQ-to-entity для запроса моей БД, где у меня есть 3 таблицы: Room, Conference и Participant.В каждой комнате много конференций, и в каждой конференции много участников.Для каждой комнаты я пытаюсь подсчитать количество конференций и сумму всех участников для всех конференций комнаты.Вот мой запрос:

var roomsData = context.Rooms
    .GroupJoin(
        context.Conferences
            .GroupJoin(
                context.Participants,
                conf => conf.Id,
                part => part.ConferenceId,
                (conf, parts) => new { Conference = conf, ParticipantCount = parts.Count() }
            ),
        rm => rm.Id,
        data => data.Conference.RoomId,
        (rm, confData) => new {
            Room = rm,
            ConferenceCount = confData.Count(),
            ParticipantCount = confData.Sum(cd => cd.ParticipantCount)
        }
    );

Когда я пытаюсь превратить это в список, я получаю сообщение об ошибке:

Ошибка приведения к типу значения «System.Int32», посколькуматериализованное значение равно нулю.Либо универсальный параметр типа результата, либо запрос должен использовать обнуляемый тип.

Я могу исправить это, изменив строку Sum на:

ParticipantCount = confData.Count() == 0 ? 0 : confData.Sum(cd => cd.ParticipantCount)

Но проблема в том, чточто это, кажется, генерирует более сложный запрос и добавляет 100 мс к времени запроса.Есть ли лучший способ для меня сказать EF, что при суммировании ParticipantCount пустой список для confData должен просто означать ноль, а не выдавать исключение?Раздражает то, что эта ошибка происходит только с EF;если я создаю пустую в памяти List<int> и на этом вызываю Sum(), это дает мне ноль, а не вызывает исключение!

Ответы [ 4 ]

0 голосов
/ 09 октября 2018

Вместо того, чтобы пытаться заставить EF сгенерировать SQL-запрос, который возвращает 0 вместо нуля, вы изменяете это по мере обработки результатов запроса на стороне клиента следующим образом:

var results = from r in roomsData.AsEnumerable()
              select new 
              {
                r.Room,
                r.ConferenceCount,
                ParticipantCount = r.ParticipantCount ?? 0
              };

AsEnumerable() заставляет запрос SQL быть оцененным, и последующие операторы запроса являются LINQ-to-Objects на стороне клиента.

0 голосов
/ 09 октября 2018

Вы можете использовать оператор объединения нулей ??как:

confData.Sum(cd => cd.ParticipantCount ?? 0)
0 голосов
/ 09 октября 2018

Я заставил его работать, изменив строку Sum на:

ParticipantCount = (int?)confData.Sum(cd => cd.ParticipantCount)

Смущает, что, хотя IntelliSense сообщает мне, что перегрузка int для Sum() используется, вво время выполнения он фактически использует перегрузку int?, поскольку список confData может быть пустым.Если я явно скажу ему, что тип возвращаемого значения int?, он возвращает null для пустых записей списка, и позже я могу слить нуль null s в ноль.

0 голосов
/ 09 октября 2018

Использование Enumerable.DefaultIfEmpty:

 ParticipantCount = confData.DefaultIfEmpty().Sum(cd => cd.ParticipantCount)
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...