web-dev-qa-db-ja.com

null許容合計を含むLinqクエリ

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

私はこのクエリを取得しましたが、例外なく投票が見つからない場合は失敗します:

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

Sumはnullを許可するintではなくintを返し、sumにintを与えるためだと思いますか?入力は同じエラーを与えるだけなので、おそらくintではsumのみが機能します。

これの良い回避策はありますか?

69
AndreasN
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() 
}

編集-これについてはどうですか...(あなたのモデルがわからないのでもう一度撮影してください...):

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

ヌルの許容可能な形式のSumを使用するため、値をヌル可能にキャストしてみてください。

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

ここで問題について詳しく説明します。

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

74
Scott Stafford

「v.Points」が小数であると仮定すると、次を使用します。

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
}
19
Jeroen Bernsen

Nullabe decimalにキャストしたくない場合は、ToList()メソッドでLinq To Objectsを使用することもできます。

LinqToObjects空のコレクションの合計は0です。LinqToSql空のコレクションの合計はnullです。

11
Emir

これをチェックしてみてください:

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

したがって、問題の根本は次のようなSQLクエリです。

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

nULLを返します

10
Pavel Shkleinik

シンプルだが効果的な回避策は、Points.Count> 0の場合にのみ投票を合計することです。そのため、null値はありません。

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()
}
5
Razzie

別のメソッドをミックスに追加するだけです:)

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

同様のシナリオがありましたが、合計するときに追加のフィールドを比較していませんでした...

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

ポイントがInt32のリストであると仮定すると、次のようになります:

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

これは同じケースだと思います。解決しました。これは私の解決策です:

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

これが役立つことを願っています。

2
Pepa

同じ問題がありました。空のリスト結合で解決しました:

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

「ポイント」が整数の場合、これは機能するはずです。

2
Alex

このクエリをtry/catch..if "exception"に入れると、投票が見つからなかった可能性があります

1
0x49D1

前の回答と似ていますが、合計の結果をNULL可能型にキャストすることもできます。

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
}

おそらく、これは実際に行われていることによりよく適合しますが、 この答え のキャストと同じ効果があります。

0
OlduwanSteve
        (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);

これは機能しますが、あまりきれいでも読みやすいものでもありません。

0
AndreasN

私はそこに別の解決策を投げると思いました。私は同様の問題を抱えていましたが、これが最終的にそれを解決する方法です:

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

私は同様の問題を抱えており、データベースから取得しようとしていたものをすべて取得し、それらをカウントし、何かが返された場合にのみ合計するという解決策を考え出しました。何らかの理由でキャストを機能させることができなかったため、他の誰かが同様の問題を抱えている場合はこれを投稿してください。

例えば.

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

そして、nullが返されないように、結果があるかどうかを確認します。

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