【问题标题】:Linq query with nullable sum总和可为空的 Linq 查询
【发布时间】:2010-10-16 08:03:26
【问题描述】:
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 而不是一个可为空的 int,所以给 sum 一个 int?由于输入只给出相同的错误,可能导致 sum 仅适用于整数。

有什么好的解决方法吗?

【问题讨论】:

  • AndreasN,我无法以任何方式重现您的问题...... v.Points 的类型是什么?是 int, int?, List ....
  • 它的 linq2Sql,应该这么说。
  • 仍然 - v.Points 的类型是什么?整数整数? IEnumerable
  • 我觉得DefaultIfEmpty不能用来解决这些问题太可惜了。无论出于何种原因,当它在查询和 Sum 方法之间楔入时,它似乎不起作用。

标签: c# linq linq-to-sql sum nullable


【解决方案1】:

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

【讨论】:

    【解决方案2】:
    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。和??运算符不适用于不可为空的类型。
    • 我只是在这里拍摄 - 我假设空集合的总和应该为 0。所以问题可能是 v.Points 可以为空?
    • 所以 v.Points 是某种序列?
    • 这个答案有效,但不能解释 - 为什么 - 你的答案无效。请参阅weblogs.asp.net/zeeshanhirani/archive/2008/07/15/… 或在下面查看我的答案...
    • 会不会是因为SQL返回DBNull for SUM()超过0行?
    【解决方案3】:

    假设“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(...) 之前没有尝试过
    • 这是因为该信息对 .NET 端很重要,因为它将检索到的数据注入到对象中。
    【解决方案4】:

    尝试检查一下:

    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】:

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

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

      【讨论】:

        【解决方案6】:

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

        【讨论】:

          【解决方案7】:

          只是为了添加另一种方法:)

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

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

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

          【讨论】:

            【解决方案8】:

            假设 Points 是一个 Int32 的列表,那么类似:

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

            【讨论】:

              【解决方案9】:

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

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

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

              【讨论】:

                【解决方案10】:

                我认为情况相同。 我解决了。这是我的解决方案:

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

                希望对你有所帮助。

                【讨论】:

                  【解决方案11】:

                  我想我会抛出另一个解决方案。我有一个类似的问题,这就是我最终解决它的方式:

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

                  【讨论】:

                    【解决方案12】:
                            (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 的答案不应该对您有用吗?我认为你想获得所有具有相应票数的项目,如果数据库中的票数为空(DBNull),则将 Points 设置为 0。
                    【解决方案13】:

                    我遇到了类似的问题,并想出了一个解决方案,即从数据库中取出我试图从数据库中取出的任何东西,对它们进行计数,然后只有当我返回任何东西时才进行总和。由于某种原因无法让演员正常工作,因此如果其他人有类似问题,请发布此内容。

                    例如

                    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
                    

                    【讨论】:

                      【解决方案14】:

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

                      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
                      }
                      

                      可以说这更符合实际情况,但它与this answer 中的演员阵容具有相同的效果。

                      【讨论】:

                        猜你喜欢
                        • 1970-01-01
                        • 1970-01-01
                        • 1970-01-01
                        • 1970-01-01
                        • 1970-01-01
                        • 2012-06-04
                        • 2012-12-30
                        • 1970-01-01
                        • 1970-01-01
                        相关资源
                        最近更新 更多