Как заставить linq Sum возвращать значение null, если все суммированные значения равны нулю

У меня есть запрос LINQ, который выглядит так...

var duration = Level3Data.AsQueryable().Sum(d => d.DurationMonths);

Если все значения d.DurationMonths равны нулю, сумма возвращает 0. Как я могу заставить сумму возвращать null, если все d.DurationMonths равны null? Или мне нужно сначала запустить отдельный запрос, чтобы устранить эту ситуацию перед выполнением суммы?


person Simon Keep    schedule 24.08.2009    source источник
comment
Каков тип DurationMonths? инт ? Nullable<int> ?   -  person Thomas Levesque    schedule 24.08.2009


Ответы (5)


Наряду с предыдущим предложением для метода расширения - вы можете использовать тернарный оператор...

var duration = Level3Data.AsQueryable().Any(d => d.DurationMonths.HasValue) 
               ? Level3Data.AsQueryable().Sum(d => d.DurationMonths) 
               : null;
person Scott Ivey    schedule 24.08.2009
comment
Хотя это действительно перечисляет результаты дважды, Мои коллекции малы, и я считаю это наиболее читаемым. Итак, приняли это. Спасибо всем. - person Simon Keep; 24.08.2009

Вы можете использовать Aggregate для предоставления пользовательского кода агрегации:

var items = Level3Data.AsQueryable();
var duration = items.Aggregate<D,int?>(null, (s, d) => (s == null) ? d.DurationMonths : s + (d.DurationMonths ?? 0));

(при условии, что элементы в Level3Data относятся к типу D)

person Thomas Levesque    schedule 24.08.2009
comment
+= на самом деле должно быть просто +. - person GSerg; 08.12.2016

var outputIndicatorSum = (from OutputIndicatorTable in objDataBaseContext.Output_Indicators
                                          where OutputIndicatorTable.Output_Id == outputId
                                          select (int?)OutputIndicatorTable.Status).Sum();
                int outputIndicatorSumReturn = Convert.ToInt32(outputIndicatorSum);
                return outputIndicatorSumReturn;

Вы можете явно ввести переменную cast non-nullable в тип, допускающий значение null. i.e, select (int?)OutputIndicatorTable.Status).Sum();

person Vijay Singh    schedule 08.05.2013
comment
Этот ответ неверен. Приведение к (int?) перед суммированием имеет смысл в контексте Linq2Sql, где Sum может возвращать null (непосредственно из SQL-запроса), даже если компилятор выводит ненулевой результат, что приводит к исключению. С Linq2Objects Sum всегда возвращает 0, даже если все элементы ввода были null или вообще не было элементов ввода. - person GSerg; 08.12.2016

Используя только Sum, это невозможно. Как вы указали в своем вопросе, вам нужно будет проверить эту ситуацию, прежде чем звонить Sum:

var q = Level3Data.AsQueryable();
var duration = q.All(d => d.DurationMonths == null)
                   ? null
                   : q.Sum(d => d.DurationMonths);
person Erik Forbes    schedule 24.08.2009
comment
Ба, опоздал меньше чем на минуту. Ржунимагу - person Erik Forbes; 24.08.2009

Если вы хотите получить результат без двух запросов, попробуйте:

var duration = Level3Data.AsQueryable().Sum(d => (double?)d.DurationMonths);

Если вы хотите ноль вместо нуля в результате этого запроса, используйте:

var duration = Level3Data.AsQueryable().Sum(d => (double?)d.DurationMonths) ?? 0;

person C Tierney    schedule 28.03.2013
comment
Мне лично этот вариант нравится больше всего. - person TravisWhidden; 26.11.2013
comment
Если DurationMonths равно int?, а все значения равны null, Linq2Sql вернет null вместо Sum, а Linq2Objects вернет 0. OP возвращает 0, поэтому они используют Linq2Objects, и в этом случае приведение к double? перед суммированием не будет работать, и результат все равно будет 0. - person GSerg; 08.12.2016