Как заставить LINQ Sum() вернуть 0, когда исходный набор пуст
В основном, когда я выполняю следующий запрос, если ни один из них не был сопоставлен, следующий запрос выдает исключение. В этом случае я предпочел бы, чтобы сумма выравнивала 0, а не вызывало исключение.
Возможно ли это в самом запросе - я имею в виду вместо сохранения запроса и проверки query.Any()
?
double earnings = db.Leads.Where(l => l.Date.Day == date.Day
&& l.Date.Month == date.Month
&& l.Date.Year == date.Year
&& l.Property.Type == ProtectedPropertyType.Password
&& l.Property.PropertyId == PropertyId).Sum(l => l.Amount);
Ответы
Ответ 1
Попробуйте изменить свой запрос на это:
db.Leads.Where(l => l.Date.Day == date.Day
&& l.Date.Month == date.Month
&& l.Date.Year == date.Year
&& l.Property.Type == ProtectedPropertyType.Password
&& l.Property.PropertyId == PropertyId)
.Select(l => l.Amount)
.DefaultIfEmpty(0)
.Sum();
Таким образом, ваш запрос будет выбирать только поле Amount
. Если коллекция пуста, она вернет один элемент со значением 0
, а затем будет применена сумма.
Ответ 2
Я предпочитаю использовать другой хак:
double earnings = db.Leads.Where(l => l.Date.Day == date.Day
&& l.Date.Month == date.Month
&& l.Date.Year == date.Year
&& l.Property.Type == ProtectedPropertyType.Password
&& l.Property.PropertyId == PropertyId)
.Sum(l => (double?) l.Amount) ?? 0;
Ответ 3
Попробуйте это вместо этого: короче:
db.Leads.Where(..).Aggregate(0, (i, lead) => i + lead.Amount);
Ответ 4
Это победа для меня:
int Total = 0;
Total = (int)Db.Logins.Where(L => L.id == item.MyId).Sum(L => (int?)L.NumberOfLogins ?? 0);
В моей таблице LOGIN в поле NUMBEROFLOGINS некоторые значения имеют значение NULL, а другие имеют номер INT. Здесь я суммирую NUMBEROFLOGINS всех пользователей одной корпорации (каждый идентификатор).
Ответ 5
Обновление: Хотя это и рабочее решение, этот ответ неверен. Правильный - тот, который дал Саймон Белэнджер. Тем не менее, вместо удаления я оставляю это здесь в качестве дополнительной информации (см. комментарии).
Интересная деталь здесь в том, что реализация LINQ To SQL в Sum
(которую вы используете) отличается от реализации LINQ To Objects. Ответ саймона Беланджера правильный, и мне нравится это, но (не для поиска далеко) другой вариант, чтобы заставить эту работу работать, это изменить тип компиляции источника и использование LINQ To Objects. Будет выполнен другой Sum
(без каких-либо дополнительных операций):
db.Leads.Where(...)
.AsEnumerable() // switch to LINQ to Objects
.Sum(l => l.Amount);
Из MSDN:
Метод AsEnumerable (IEnumerable) не имеет никакого эффекта кроме того, чтобы изменить тип источника времени компиляции от типа, который реализует IEnumerable сам IEnumerable.
Ответ 6
db.Leads.Where(l => l.Date.Day == date.Day
&& l.Date.Month == date.Month
&& l.Date.Year == date.Year
&& l.Property.Type == ProtectedPropertyType.Password
&& l.Property.PropertyId == PropertyId)
.Select(l => l.Amount)
.ToList()
.Sum();
Ответ 7
Попробуйте:
double earnings = db.Leads.Where(l => l.ShouldBeIncluded).Sum(l =>
(double?) l.Amount) ?? 0;
Запрос "SELECT SUM ([Amount])" вернет NULL для пустого списка.
Но если вы используете LINQ, он ожидает, что "Sum (l => l.Amount)" вернет значение double, и это не позволит вам использовать оператор "??" для установки 0 для пустой коллекции.
Чтобы избежать этой ситуации, вам нужно заставить LINQ ожидать "double?". Вы можете сделать это, применив "(double?) L.Amount".
Это не влияет на запрос к SQL, но заставляет LINQ работать с пустыми коллекциями.