Значение cast для значения "Int32" не выполнено, поскольку материализованное значение равно null

У меня есть следующий код. Я получаю сообщение об ошибке:

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

когда таблица CreditHistory не имеет записей.

var creditsSum = (from u in context.User
                  join ch in context.CreditHistory on u.ID equals ch.UserID                                        
                  where u.ID == userID
                  select ch.Amount).Sum();

Как я могу изменить запрос для принятия нулевых значений?

Ответ 1

Запрос linq-to-sql не выполняется как код, а скорее переведен в SQL. Иногда это "непроницаемая абстракция", которая приводит к неожиданному поведению.

Одним из таких случаев является обработка с нулевым значением, где могут быть неожиданные значения в разных местах. ...DefaultIfEmpty(0).Sum(0) может помочь в этом (довольно простом) случае, где не может быть элементов, а sql SUM возвращает null, тогда как С# ожидать 0.

Более общий подход заключается в использовании ??, который будет переведен на COALESCE всякий раз, когда существует риск того, что сгенерированный SQL возвращает неожиданный null:

var creditsSum = (from u in context.User
              join ch in context.CreditHistory on u.ID equals ch.UserID                                        
              where u.ID == userID
              select (int?)ch.Amount).Sum() ?? 0;

Это первый запрос на int?, чтобы сообщить компилятору С#, что это выражение действительно может вернуть null, хотя Sum() возвращает int. Затем мы используем обычный оператор ?? для обработки случая null.

Основываясь на этом ответе, я написал сообщение в блоге с подробностями для LINQ to SQL и LINQ to Entities.

Ответ 2

Чтобы разрешить нулевое поле Amount, просто используйте нулевой оператор коалесцирования для преобразования нулей в 0.

var creditsSum = (from u in context.User
              join ch in context.CreditHistory on u.ID equals ch.UserID                                        
              where u.ID == userID
              select ch.Amount ?? 0).Sum();

Ответ 3

Вы используете функцию aggregate, которая не получает элементы для выполнения действий, вы должны подтвердить, что запрос linq дает следующий результат:

var maxOrderLevel =sdv.Any()? sdv.Max(s => s.nOrderLevel):0

Ответ 4

Это сообщение об ошибке, когда я пытался выбрать из представления.

Проблема заключалась в том, что в последнее время недавно появились несколько новых нулевых строк (в столбце SubscriberId), и он не был обновлен в EDMX (сначала база EF).

Столбец должен был быть Nullable, чтобы он работал.

var dealer = Context.Dealers.Where(x = > x.dealerCode == dealerCode).FirstOrDefault();

Перед обновлением вида:

public int SubscriberId { get; set; }

После просмотра обновления:

public Nullable<int> SubscriberId { get; set; }

Сработало удаление и добавление представления в EDMX.

Надеюсь, это поможет кому-то.

Ответ 5

Я использовал этот код, и он отвечает правильно, только выходное значение обнуляется.

var packesCount = await botContext.Sales.Where(s => s.CustomerId == cust.CustomerId && s.Validated)
                                .SumAsync(s => (int?)s.PackesCount);
                            if(packesCount != null)
                            {
                                // your code
                            }
                            else
                            {
                                // your code
                            }

Ответ 6

Я вижу, что на этот вопрос уже дан ответ. Но если вы хотите, чтобы он был разделен на два утверждения, можно рассмотреть следующее.

var credits = from u in context.User
              join ch in context.CreditHistory 
                  on u.ID equals ch.UserID                                        
              where u.ID == userID
              select ch;

var creditSum= credits.Sum(x => (int?)x.Amount) ?? 0;

Ответ 7

Получил эту ошибку в Entity Framework 6 с этим кодом во время выполнения:

var fileEventsSum = db.ImportInformations.Sum(x => x.FileEvents)

Обновление от LeandroSoares:

Используйте это для одиночного выполнения:

var fileEventsSum = db.ImportInformations.Sum(x => (int?)x.FileEvents) ?? 0

Оригинал:

Поменял на это и тогда все заработало:

var fileEventsSum = db.ImportInformations.Any() ? db.ImportInformations.Sum(x => x.FileEvents) : 0;