2009-03-30 19 views
64
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() 
} 

ich diese Abfrage bekam, jedoch scheitert es, wenn keine Stimmen mit Ausnahme gefunden:Linq Abfrage mit nullable Summe

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

Ich gehe davon sein, weil Summe gibt einen int und nicht auf NULL festlegbare int, Summe geben ein int? als Eingabe geben Sie nur den gleichen Fehler, wahrscheinlich verursachen Summe nur funktioniert auf Ints.

Jeder gute Workaround dafür?

+0

AndreasN, kann ich nicht reproduzieren Ihr Problem in irgendeiner Weise ... Was ist die Art von v.Points? Ist es ein int, int ?, Liste .... –

+0

Sein linq2Sql, hätte das gesagt. – AndreasN

+0

Still - was ist der Typ von v.Points? int int? IEnumerable – Rashack

Antwort

21
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 gefunden - ok was ist das ... (Schießen wieder da ich don‘ t Ihr Modell wissen ...):

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) 
} 
+0

Warum kompiliert es nicht? –

+0

Entschuldigung falsche Kopie Paste dort. Es wird nicht kompiliert, da Sum() einen int zurückgibt. Und das ?? Der Operator arbeitet nicht mit nicht nullfähigen Typen. – AndreasN

+0

Ich filme nur hier - ich nehme an, dass die Summe der leeren Sammlung 0 sein sollte. Also könnte das Problem sein, dass v.Points NULL-fähig ist? – Rashack

1

werden können, um diese Abfrage in try/catch..if „Ausnahme“ zu setzen, dann gab es keine Stimmen

+0

Das wird nicht helfen, das alle Elemente verwirft, wenn man keine Stimmen hat. Es wird erwartet, dass einige Artikel nie Stimmen erhalten werden. – AndreasN

+2

Und außerdem ist es nur eine sehr schlechte Lösung, Ausnahmen dafür zu werfen. – Razzie

+1

hab es :) danke euch beiden für die Kommentare – 0x49D1

5

Eine einfache, aber effektive Problemumgehung nur die Stimmen zusammenfassen würde, wo Points.Count> 0, so dass Sie nie null Werte haben:

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() 
} 
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); 

Dies funktioniert, ist aber nicht sehr schön oder lesbar.

+0

In diesem Fall sollte Rashacks Antwort nicht für Sie funktionieren?Ich nehme an, Sie wollen alle Artikel mit der entsprechenden Anzahl von Stimmen erhalten, und wenn der voicecount in der Datenbank null (DBNull) ist, setzen Sie Punkte auf 0. – Razzie

72

Sie wollen die Nullable-Form Summe verwenden, so versuchen Sie Wert auf einen Nullable-Casting:

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) 
} 

Ihr Problem wird hier näher erläutert:

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

+4

+1 Danke, das hat mich verrückt gemacht! –

11

Wenn Sie mag es nicht, auf Dezimal nullull zu werfen, Sie könnten auch versuchen, Linq To Objects mit ToList() -Methode,

LinqToObjects Summe der leeren Sammlung ist 0, wobei LinqToSql Summe der leeren Sammlung null ist.

+0

Danke für die Info. – GoalMaker

19

"v.Points" Unter der Annahme ist eine Dezimalzahl verwenden nur die folgenden:

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 
} 
+0

Das Interessante an der ** Umwandlung in "Dezimal?" ** ist, dass der generierte T-SQL-Code keinen Unterschied zu dem Code hat, der generiert wird, wenn Sie die Besetzung nicht machen! Ich habe es nicht versucht, bevor ich dachte, dass der generierte T-SQL-Code CAST (...) verwenden würde. – vcRobe

+1

Das liegt daran, dass diese Information für die .NET-Seite wichtig ist, da sie die abgerufenen Daten in die Objekte injiziert. – jeromeyers

2

ich hatte das gleiche Problem. Löste es mit leeren liste gewerkschaft:

List<int> emptyPoints = new List<int>() { 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() 
} 

Im Falle von "Punkte" ist ganzzahl sollte dies funktionieren.

0

Ich hatte ein ähnliches Problem und kam mit der Lösung zu bekommen, was auch immer ich versuchte, aus der Datenbank zu bekommen, zählen Sie auf diese und dann nur, wenn ich etwas zurückgegeben hatte, eine Summe zu tun. War nicht in der Lage, die Besetzung aus irgendeinem Grund arbeiten zu lassen, also dies zu veröffentlichen, wenn jemand anderes ähnliche Probleme hatte.

z.B.

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

Und dann überprüfen Sie, ob Sie irgendwelche Ergebnisse haben, so dass Sie nicht null zurückgegeben bekommen.

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

versuchen, dies zu überprüfen:

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

So ist die Wurzel des Problems ist, dass SQL-Abfrage wie folgt aus:

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

gibt NULL zurück

0

Ähnlich wie vorherige Antworten, aber Sie können das Ergebnis der gesamten Summe auch auf den Nullable-Typ anwenden.

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 
} 

Diskutierbar das besser passt, was wirklich los ist, aber es hat die gleiche Wirkung wie die Besetzung in this answer.

2

Ich denke, das ist der gleiche Fall. Ich habe es gelöst. Das ist meine Lösung:

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); 

ich hoffe diese Hilfe.

4

einfach ein weiteres Verfahren in die Mischung hinzufügen :)

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

hatte ich ein ähnliches Szenario, aber ich war nicht ein zusätzliches Feld zu vergleichen, wenn Summieren ...

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

dachte, ich würde Wirf eine andere Lösung da draußen. Ich hatte ein ähnliches Problem, und das ist, wie ich es zu lösen endete:

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

Unter der Annahme Punkte wird eine Liste der Int32, wie wäre es so etwas wie:

var sum = Points.DefaultIfEmpty().Sum(c => (Int32)c ?? 0)