Sum() Возвращает null в запросе Entity Framework
У меня есть большой запрос Entity Framework, содержащий эти строки.
var programs = from p in Repository.Query<Program>()
where p.OfficeId == CurrentOffice.Id
let totalCharges = p.ProgramBillings.Where(b => b.Amount > 0 && b.DeletedDate == null).Select(b => b.Amount).Sum()
let totalCredits = p.ProgramBillings.Where(b => b.Amount < 0 && b.DeletedDate == null).Select(b => -b.Amount).Sum()
let billingBalance = (totalCharges - totalCredits)
Когда я материализую данные, я получаю следующую ошибку:
Приведение значения к типу значения "Десятичный" завершилось неудачно, поскольку материализованное значение равно нулю. Либо общий параметр типа результата, либо запрос должен использовать тип с нулевым значением.
Если я изменил свой запрос следующим образом (добавленный в двух типах), ошибка исчезнет.
var programs = from p in Repository.Query<Program>()
where p.OfficeId == CurrentOffice.Id
let totalCharges = (decimal?)p.ProgramBillings.Where(b => b.Amount > 0 && b.DeletedDate == null).Select(b => b.Amount).Sum()
let totalCredits = (decimal?)p.ProgramBillings.Where(b => b.Amount < 0 && b.DeletedDate == null).Select(b => -b.Amount).Sum()
let billingBalance = (totalCharges - totalCredits)
Я не понимаю этого. ProgramBilling.Amount
является непустым значением десятичного числа. Если я нахожусь над вызовом Sum()
, Intellisense говорит, что возвращает тип Decimal. И все же дополнительные тесты подтвердили, что в моей второй версии totalCharges
и totalCredits
оба установлены равными нулю для тех строк, где ProgramBillings
не имеет данных.
Вопросы:
-
Я понял, что Sum()
возвращает 0 для пустой коллекции. При каких обстоятельствах это не так?
-
И если иногда это не так, то почему, когда я наводил курсор на Sum()
, Intellisense показывает, что он возвращает тип Decimal, а не Decimal? Похоже, у Intellisense было такое же понимание, что и у меня.
EDIT:
Казалось бы, легко сделать что-то вроде Sum() ?? 0m
. Но это незаконно, давая мне ошибку:
Оператор '??' не может применяться к операндам типа "десятичный" и "десятичный"
Ответы
Ответ 1
Я понял, что Sum() возвратил 0 для пустой коллекции. При каких обстоятельствах это не так?
Если вы не используете LINQ для объектов, как это имеет место здесь. Здесь у вас есть поставщик запросов, который переводит этот запрос в SQL. Операция SQL имеет другую семантику для оператора SUM.
И если иногда это не так, то почему, когда я наводил курсор на Sum(), Intellisense показывает, что он возвращает тип Decimal, а не Decimal? Похоже, у Intellisense было такое же понимание, что и у меня.
Оператор С# LINQ SUM не возвращает значение NULL; он должен иметь ненулевое значение, но оператор SQL SUM имеет другую семантику, он возвращает null
при суммировании пустого набора, а не 0
. Тот факт, что значение null
предоставляется в контексте, где С# требует непустого значения, является всей причиной, по которой все ломается. Если оператор С# LINQ SUM здесь возвращал значение с нулевым значением, то null
можно было бы просто вернуть без каких-либо проблем.
Это различия между оператором С# и оператором SQL, который используется для представления того, что вызывает эту ошибку.
Ответ 2
У меня есть одна и та же проблема в одном из моих запросов EF, когда коллекция пуста, одно быстрое исправление для этого заключается в том, чтобы отбрасывать до нулевой десятичной:
var total = db.PaiementSet.Sum(o => (Decimal?)o.amount) ?? 0M;
надеюсь, что это поможет.
Ответ 3
До .Sum добавьте DefaultIfEmpty (0.0M)