总和可为空的 Linq 查询
Posted
技术标签:
【中文标题】总和可为空的 Linq 查询【英文标题】:Linq query with nullable sum 【发布时间】: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 方法之间楔入时,它似乎不起作用。 【参考方案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 中的演员阵容具有相同的效果。
【讨论】:
以上是关于总和可为空的 Linq 查询的主要内容,如果未能解决你的问题,请参考以下文章