使用LINQ to Entities查询子对象属性的总和出现问题

7

给定以下查询:

from s in services
select new
{
    s.Id,
    s.DateTime,
    Class = s.Class.Name,
    s.Location,
    s.Price,
    HeadCount = s.Reservations.Sum(r => r.PartySize), // problem here. r.PartySize is int
    s.MaxSeats
}

如果服务没有任何预订,将会抛出以下异常:

System.InvalidOperationException: 转换为值类型 'Int32' 失败,因为实例化的值为空。结果类型的泛型参数或查询必须使用可空类型。

我明白了,但是我该怎么处理呢?我的意图是如果没有预订,那么HeadCount将被赋值为0。
4个回答

11

这里有一个更简单的解决方案:

from s in services
select new
{
    s.Id,
    s.DateTime,
    Class = s.Class.Name,
    s.Location,
    s.Price,
    HeadCount = (int?)s.Reservations.Sum(r => r.PartySize), 
    s.MaxSeats
}

注意强制转换。这样做可能会比@Ahmad的建议产生更简单的SQL。

基本上,你只是帮助类型推断。


2
@Ahmad,对于L2E来说,那不是正确的,尽管对于L2O来说是正确的。它们有不同的规则。不,我不是想转换值。尝试我建议的代码;它确实有效。 - Craig Stuntz
1
+1 我忽略了这个LINQ提供程序中发生的翻译。 - Ahmad Mageed
虽然谈论“Reservations”到底是什么有些含糊不清,因为它是翻译过来的,而且并不对应得很好,但请注意从.NET的角度来看,它不是null,而是一个空的可枚举对象。因此,尽管检查null是有效的(因为L2E的怪癖),但实际上并没有太多意义... - Eamon Nerbonne
谢谢!- 尽管假设Headcount不可为空,那行代码应该是 HeadCount = (int?)s.Reservations.Sum(r => r.PartySize) ?? 0, - JumpingJezza
@JumpingJezza,“HeadCount”是匿名类型的成员,因此其类型与分配给它的表达式相同。由于(int?)转换,它是可空的。 - Craig Stuntz
显示剩余2条评论

7

你应该进行检查:

HeadCount = s.Reservations != null ? s.Reservations.Sum(r => r.PartySize) : 0,

我之前发布了这个问题,只是因为我认为LINQ to Entities不能将其转换为SQL或类似的东西。我仍在适应L2E,它似乎比LINQ to SQL更加挑剔,关于你实际上可以在LINQ语句中做什么。无论如何,这个方法可行,我们永远不应该做出假设。谢谢。 - Ronnie Overby
@Ronnie,很高兴它起作用了。它们肯定是不同的,我想L2E在未来只会变得更加灵活。 - Ahmad Mageed
1
@Ronnie,@Craig:我理解问题的方式是Reservations本身可能为空。然而,我发现这篇博客文章展示了一个EF 1.0的问题,即对空集求和。解决方案涉及到可空类型的转换和使用null合并运算符。只是想提一下,以防我忽略了什么。不过我认为自EF1.0以来已经修复了这个问题。 - Ahmad Mageed
你需要从如何将其转换为SQL的角度来考虑,而不是从C#的规则出发。L2E遵循与L2O不同的规则。在L2E中不存在空引用异常,因为null值会自动合并。 - Craig Stuntz
@Craig 谢谢,这很有道理,因为它是翻译过来的。我确实在考虑L2O/C#方面的问题。 - Ahmad Mageed

2
这应该可以解决你的问题: 尝试将int转换为int?
from s in services
select new
{
    s.Id,
    s.DateTime,
    Class = s.Class.Name,
    s.Location,
    s.Price,
    HeadCount = s.Reservations.Sum(r => (int?) r.PartySize),
    s.MaxSeats
};
HeadCount = HeadCount ?? 0;

1
一个简单的三元运算符应该很好地解决这个问题...
像这样:
HeadCount = (s.Reservations != null && s.Reservations.Any()) ? s.Reservations.Sum(r => r.PartySize) : 0;

这将处理空值和空情况


我认为那段代码甚至无法编译(缺少())。它肯定不会产生高效的SQL(当你想要使用Any()时,永远不要使用.Count() == 0),但即使与L2E的内置空合并相比,这也是低效且难以阅读的。 - Craig Stuntz
你说得对,它无法编译,因为Count缺少'()'。我是临时写的 -_-。任何人都会更有效率。感谢您的纠正! - Justin Williams

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接