C# 具有可为空总和的 Linq 查询

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/696431/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-04 13:51:23  来源:igfitidea点击:

Linq query with nullable sum

c#linqlinq-to-sqlsumnullable

提问by 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).Sum()
}

I got this query, however it fails if no votes are found with exception:

我收到了这个查询,但是如果没有找到投票,它就会失败,但有例外:

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

I assume its because sum returns an int and not a nullable int, giving sum a int? as input only give the same error, probably cause sum only workes on ints.

我假设它是因为 sum 返回一个 int 而不是一个可空的 int,给 sum 一个 int?由于输入只给出相同的错误,可能导致 sum 仅适用于整数。

Any good workaround for this?

有什么好的解决方法吗?

采纳答案by Rashack

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 what about this... (Shooting again since I don't know your model...):

编辑 - 好吧,这个怎么样......(再次拍摄,因为我不知道你的模型......):

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

回答by Razzie

A simple but effective workaround would be to only sum the votes where Points.Count > 0, so you never have null values:

一个简单但有效的解决方法是只对 Points.Count > 0 的投票求和,这样你就永远不会有空值:

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

回答by AndreasN

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

This works, but isn't very pretty or readable.

这有效,但不是很漂亮或可读。

回答by Scott Stafford

You want to use the nullable form of Sum, so try casting your value to a nullable:

您想使用 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)
}

Your issue is discussed here in more detail:

此处更详细地讨论了您的问题:

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

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

回答by Emir

If you don't like casting to nullabe decimal you could also try using Linq To Objects with ToList() method,

如果您不喜欢转换为 nullabe 十进制,您也可以尝试使用带有 ToList() 方法的 Linq To Objects,

LinqToObjects Sum of empty collection is 0, where LinqToSql Sum of empty collection is null.

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

回答by Jeroen Bernsen

Assuming "v.Points" is a decimal just use the following:

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

回答by Alex

I had the same problem. Solved it with empty list union:

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

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

In case of "Points" is integer this should work.

如果“点”是整数,这应该可以工作。

回答by tcmorris

I had a similar issue and came up with the solution of getting whatever I was trying to get out of the database, do a count on those and then only if I had anything returned do a sum. Wasn't able to get the cast working for some reason so posting this if anyone else had similar issues.

我有一个类似的问题,并想出了一个解决方案,即从数据库中获取任何我想要的东西,对这些进行计数,然后只有当我返回任何东西时才计算总和。由于某种原因无法让演员工作,所以如果其他人有类似问题,请发布此信息。

e.g.

例如

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

And then check to see if you've got any results so that you don't get null returned.

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

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

回答by Pavel Shkleinik

Try to check this out:

尝试检查一下:

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

So, the root of the problem is that SQL query like this:

所以,问题的根源在于这样的 SQL 查询:

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

returns NULL

返回 NULL

回答by OlduwanSteve

Similar to previous answers, but you can also cast the result of the entire sum to the nullable type.

与之前的答案类似,但您也可以将整个总和的结果转换为可空类型。

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
}

Arguably this better fits what is really going on but it has the same effect as the cast in this answer.

可以说这更符合实际情况,但它与此答案中的演员表具有相同的效果。