Query Linq con sum nullable

from i in Db.Items select new VotedItem { ItemId = i.ItemId, Points = (from v in Db.Votes where b.ItemId == v.ItemId select v.Points).Sum() } 

Ho ottenuto questa query, tuttavia fallisce se non vengono trovati voti con eccezione:

 The null value cannot be assigned to a member with type System.Int32 which is a non-nullable value type. 

Presumo che sia perché sum restituisce un int e non un nullable int, dando sum a int? come input solo dare lo stesso errore, probabilmente causa la sum funziona solo su ints.

Qualche buona soluzione per questo?

 from i in Db.Items select new VotedItem { ItemId = i.ItemId, Points = (from v in Db.Votes where b.ItemId == v.ItemId select v.Points ?? 0).Sum() } 

EDIT – ok, che mi dici di questo … (Riprese dal momento che non conosco il tuo modello …):

 from i in Db.Items select new VotedItem { ItemId = i.ItemId, Points = (from v in Db.Votes where b.ItemId == v.ItemId) .Sum(v => v.Points) } 

Vuoi utilizzare la forma nullable di Sum, quindi prova a trasmettere il tuo valore a un valore nullo:

 from i in Db.Items select new VotedItem { ItemId = i.ItemId, Points = (from v in Db.Votes where b.ItemId == v.ItemId select v.Points).Sum(r => (decimal?) r.Points) } 

Il problema è discusso qui in modo più dettagliato:

http://weblogs.asp.net/zeeshanhirani/archive/2008/07/15/applying-aggregates-to-empty-collections-causes-exception-in-linq-to-sql.aspx

Supponendo che “v.Points” sia un decimale, basta usare quanto segue:

 from i in Db.Items select new VotedItem { ItemId = i.ItemId, Points = (from v in Db.Votes where b.ItemId == v.ItemId select (decimal?) v.Points).Sum() ?? 0 } 

Se non ti piace eseguire il casting con i decimali nullabe, puoi provare a utilizzare Linq To Objects con il metodo ToList (),

LinqToObjects La sum della raccolta vuota è 0, dove LinqToSql Sum della raccolta vuota è nullo.

Prova a controllare questo:

 var count = db.Cart.Where(c => c.UserName == "Name").Sum(c => (int?)c.Count) ?? 0; 

Quindi, la radice del problema è che la query SQL come questa:

 SELECT SUM([Votes].[Value]) FROM [dbo].[Votes] AS [Votes] WHERE 1 = [Votes].[UserId] 

restituisce NULL

Una soluzione semplice ma efficace sarebbe quella di sumre i voti solo dove Points.Count> 0, in modo da non avere mai valori nulli:

 from i in Db.Items select new VotedItem { ItemId = i.ItemId, Points = (from v in Db.Votes where b.ItemId == v.ItemId && v.Points.Count > 0 select v.Points).Sum() } 

Solo per aggiungere un altro metodo nel mix 🙂

 Where(q=> q.ItemId == b.ItemId && b.Points.HasValue).Sum(q=>q.Points.Value) 

Ho avuto uno scenario simile ma non stavo confrontando un campo aggiuntivo quando sumndo …

 Where(q => q.FinalValue.HasValue).Sum(q=>q.FinalValue.Value); 

Ho avuto lo stesso problema. Risolto con unione di lista vuota:

 List emptyPoints = new List() { 0 }; from i in Db.Items select new VotedItem { ItemId = i.ItemId, Points = (from v in Db.Votes where b.ItemId == v.ItemId select v.Points).Union(emptyPoints).Sum() } 

In caso di “Punti” è intero questo dovrebbe funzionare.

Penso che questo sia lo stesso caso. L’ho risolto. Questa è la mia soluzione:

 var x = (from a in this.db.Pohybs let sum = (from p in a.Pohybs where p.PohybTyp.Vydej == true select p.PocetJednotek).Sum() where a.IDDil == IDDil && a.PohybTyp.Vydej == false && ( ((int?)sum??0) < a.PocetJednotek) select a); 

Spero che questo aiuto.

Potrebbe essere mettere questa query in try / catch..if “exception”, quindi non sono stati trovati voti

Supponendo che Points è un elenco di Int32, che ne dici di qualcosa di simile:

 var sum = Points.DefaultIfEmpty().Sum(c => (Int32)c ?? 0) 
  (from i in Db.Items where (from v in Db.Votes where i.ItemId == v.ItemId select v.Points).Count() > 0 select new VotedItem { ItemId = i.ItemId, Points = (from v in Db.Items where i.ItemId == v.ItemId select v.Points).Sum() }).Union(from i in Db.Items where (from v in Db.Votes where i.ItemId == v.ItemId select v.Points).Count() == 0 select new VotedItem { ItemId = i.ItemId, Points = 0 }).OrderBy(i => i.Points); 

Funziona, ma non è molto carina o leggibile.

Ho avuto un problema simile e ho trovato la soluzione per ottenere qualsiasi cosa stavo cercando di uscire dal database, fare un conteggio su quelli e poi solo se avessi restituito qualcosa fare una sum. Non sono riuscito a far funzionare il cast per qualche motivo, quindi postalo se qualcun altro ha avuto problemi simili.

per esempio

 Votes = (from v in Db.Votes where b.ItemId = v.ItemId select v) 

E poi controlla se hai dei risultati in modo da non restituire nulla.

 If (Votes.Count > 0) Then Points = Votes.Sum(Function(v) v.Points) End If 

Simile alle risposte precedenti, ma puoi anche trasmettere il risultato dell’intera sum al tipo nullable.

 from i in Db.Items select new VotedItem { ItemId = i.ItemId, Points = (decimal?)((from v in Db.Votes where b.ItemId == v.ItemId select v.Points).Sum()) ?? 0 } 

Probabilmente questo si adatta meglio a ciò che sta realmente accadendo, ma ha lo stesso effetto del cast in questa risposta .

Ho pensato di buttare un’altra soluzione là fuori. Ho avuto un problema simile ed è così che ho finito per risolverlo:

 Where(a => a.ItemId == b.ItemId && !b.IsPointsNull()).Sum(b => b.Points)