Linq查询具有可为空的总和


70
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返回一个int而不是可为null的int,从而给sum一个int?由于输入仅给出相同的错误,可能导致求和仅适用于int。

有什么好的解决方法吗?


AndreasN,我无法以任何方式重现您的问题。v.Points是什么类型?它是一个int,int吗?,列表....
bruno conde

它的linq2Sql曾说过。
AndreasN 2009年

仍然-v.Points是什么类型?int int?IEnumerable
Rashack,2009年

我认为DefaultIfEmpty无法用于解决这些问题是很糟糕的。无论出于何种原因,在查询和Sum方法之间进行合并时,它似乎都无法正常工作。
jpierson

Answers:


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

对不起,错误的复制粘贴在那里。它不会编译,因为Sum()返回一个int。和?? 运算符不适用于非空类型。
2009年

我只是在这里拍摄-我假设空集合的总和应该为0。所以问题可能是v.Points是否可以为空?
2009年

那么v.Points是某种序列吗?
Dave Van den Eynde 09年

这个答案有效,但是并不能解释-为什么-您的无效。请参阅weblogs.asp.net/zeeshanhirani/archive/2008/07/15/…或在下面查看我的答案...
Scott Stafford 2010年

难道是因为SQL回报DBNullSUM()超过0行?
2014年


19

假设“ 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
}

关于强制转换为“十进制”的有趣的事情如果不执行强制转换,则生成的T-SQL代码与生成的代码没有区别!在想到生成的T-SQL代码将使用CAST(...)之前,我没有尝试过它
vcRobe 2014年

1
这是因为该信息对于.NET端很重要,因为它将检索到的数据注入到对象中。
argyle,2015年

11

如果您不希望将值强制转换为nullabe小数,也可以尝试使用带有ToList()方法的Linq To Objects,

LinqToObjects空集合的总和为0,其中LinqToSql空集合的总和为null。


11

尝试检查一下:

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


5

一个简单但有效的解决方法是仅对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()
}

4

只是在混合中添加另一种方法:)

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

我有类似的情况,但求和时没有比较其他字段...

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

3

假设点是Int32的列表,那么类似:

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

2

我有同样的问题。用空列表联合解决了它:

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

我认为情况也是一样。我解决了 这是我的解决方案:

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

希望对您有所帮助。


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

这行得通,但不是很漂亮或不可读。


在这种情况下,Rashack的答案对您有用吗?我想你想获得相应票数的所有项目,如果在数据库中votecount为空(DBNull的),然后设置分数为0
金酸莓

0

我遇到了类似的问题,并提出了一种解决方案:将要尝试从数据库中获取的所有内容都从数据库中取出,对它们进行计数,然后仅当我退回任何东西时,才求和。由于某种原因无法使演员正常工作,因此如果其他人遇到类似问题,请发布此演员表。

例如

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

然后检查是否有任何结果,以免返回空值。

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

0

与先前的答案类似,但是您也可以将整个总和的结果转换为可为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

以为我会在那里提出另一种解决方案。我有一个类似的问题,这就是我最终解决它的方式:

Where(a => a.ItemId == b.ItemId && !b.IsPointsNull()).Sum(b => b.Points)
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.