值类型转换为“Double”失败,因为实例化的值为空。

28

代码:

double cafeSales = db.InvoiceLines
    .Where(x =>
        x.UserId == user.UserId &&
        x.DateCharged >= dateStart &&
        x.DateCharged <= dateEnd)
    .Sum(x => x.Quantity * x.Price);

错误:

由于实例化的值为 null,将值类型“Double”强制转换失败。查询必须使用可空类型。

我已经看到的内容:

由于实例化的值为 null,将值类型“Int32”强制转换失败

由于实例化的值为 null,将值类型“Decimal”强制转换失败

我尝试过的方法:

double cafeSales = db.InvoiceLines
    .Where(x =>
        x.UserId == user.UserId &&
        x.DateCharged >= dateStart &&
        x.DateCharged <= dateEnd)
    .DefaultIfEmpty()
    .Sum(x => x.Quantity * x.Price);

而且:

double? cafeSales = db.InvoiceLines
    .Where(x =>
        x.UserId == user.UserId &&
        x.DateCharged >= dateStart &&
        x.DateCharged <= dateEnd)
    .Sum(x => x.Quantity * x.Price);

这两个都不起作用。我知道问题的原因是该表中没有与我传入的UserId相对应的行。在这种情况下,我希望Sum()只返回0给我。有什么想法吗?


2
你应该从以下任何解决方案中选择最合适和高效的,并将其标记为答案。 - Jitendra Pancholi
2
你应该接受下面的答案,这样别人才能依赖它。 - Jitendra Pancholi
1
可能是重复的问题:将值类型 'Int32' 强制转换失败,因为实例化的值为空 - Michael Freidgeim
8个回答

72

最佳解决方案

double cafeSales = db.InvoiceLines
                     .Where(x =>
                                x.UserId == user.UserId &&
                                x.DateCharged >= dateStart &&
                                x.DateCharged <= dateEnd)
                     .Sum(x => (double?)(x.Quantity * x.Price)) ?? 0;

1
太好了!这就是正确的方式。 - Mahmood Dehghan
1
工作得非常出色!!谢谢@jitendra - Avishekh Bharati

8
您可以检查集合是否具有任何正确的结果。
double? cafeSales = null;
var invoices = db.InvoiceLines
    .Where(x =>
        x.UserId == user.UserId &&
        x.DateCharged >= dateStart &&
        x.DateCharged <= dateEnd
    )
    .Where(x => x.Quantity != null && x.Price != null);
if (invoices.Any()) {
    cafeSales = invoices.Sum(x => x.Quantity * x.Price);
}

我刚刚也想到了类似的东西,但我希望有一种更简洁的方法可以实现它...仅用一个语句。 - Matt
2
这种方法的问题在于会向数据库发送两个查询,第一个是为了查看是否有任何记录,第二个是为了执行实际的sum()。 - Peter Huber
这里并不是两个查询,而只有一个。Where方法实际上并没有进行查询,而是准备了一个查询,而对Any的调用才是真正的数据库查询。无论如何,我更喜欢@Jitendra Pancholi的解决方案,它使用了??运算符将@Maarten的两个语句合并成了一个。 - David Silva-Barrera

4

我知道这可能有点老了,但以防万一它能帮到任何人。

@Matt 我猜 DefaultIFEmpty() 方法应该适用于您,在您对其应用Sum时传递默认值。此方法有一些重载,您可能需要检查,并且如果重载不支持您的要求,则建议进行类型转换。

 (query).DefaultIfEmpty(0) 

它帮助了我。这是一个很好的方式去做。 - Meryovi
它可以帮助并仅向数据库发送一个查询,但是非常丑陋!如果没有DefaultIfEmpty,它只是一个简单的SELECT语句,而使用DefaultIfEmpty生成的查询将使用4个SELECT语句。与其在数据库中进行检查是否有任何请求,不如在C#客户端中测试查询是否已返回任何记录。 - Peter Huber

3
这应该能起到作用(如果QuantityPrice不可为空,则可能需要删除其中一个条件):
var cafeSales = db.InvoiceLines
    .Where(x =>
        x.UserId == user.UserId &&
        x.DateCharged >= dateStart &&
        x.DateCharged <= dateEnd &&
        x.Quantity != null &&
        x.Price != null);

double cafeSalesTotal = 0;

if (cafeSales.Any())
{
    cafeSalesTotal = cafeSales.Sum(x => x.Quantity * x.Price);
}

1
join sim in ctx.EF.Collaterals on new { id = ini.cam.id, Type = 0 } equals new 
{ id = sim.CampaignId == null ? new Guid() : sim.CampaignId, sim.Type } 
into tempcoll
from sim in tempcoll.DefaultIfEmpty()

这个解决方案可行。实际上,您需要使用三元运算符来检查值并在第二列和第二个表中插入Guid(如果为null),然后它就会起作用。将解决"将材料化的值转换为值类型'Double'失败"的问题。谢谢。

0

在.NET 4.0中,Nullable类型有一个"GetValueOrDefault()"方法。因此,如果将查询转换为Nullable类型,则可以在完成时得到正确的类型。该方法还将生成正确的单个SQL SELECT SUM查询,并且比其他通过linq返回整个记录集以后再进行求和的解决方案更快。

decimal result = ((decimal?)query.Where(w => w.Customer =="ABC").Sum(s =>  (decimal?)s.Amount)).GetValueOrDefault();

0
以上的解决方案对我没有用。我的问题类似。我确定没有返回任何行,但是Sum的行为有些奇怪。因此,我决定在调用lambda表达式之前添加一个检查,检查lambda返回的行数计数属性。如果大于零,则调用sum表达式。这对我有用。

TimeSheetRepository.GetAll().Where(t => t.UserID == theUserId). Where(t => t.Date >= startDate).Where(t => t.Date <= endDate).Sum(t => t.Hours); - Bryida
我必须检查是否存在这样的计数:TimeSheetRepository.GetAll().Where(t => t.UserID == theUserId).Where(t => t.Date >= startDate).Where(t => t.Date <= endDate).Count() > 0。当结果集中没有行时,调用总小时数的.Sum(它始终是一个十进制数)会导致上述错误。 - Bryida

0
 var cafeSales = db.InvoiceLines
.Where(x =>
    x.UserId == user.UserId &&
    x.DateCharged >= dateStart &&
    x.DateCharged <= dateEnd)
.Sum(x => x.Quantity * x.Price);

double i;
if(cafeSales==null) ? i=0 : i=(double)cafeSales.First();

1
Sum(...) 不会返回可枚举的结果,因此在 Sum(...) 的结果上调用 First() 会导致编译时错误。 - Maarten
它有任何意义吗?如果(cafeSales==null),那么i=0,否则i=(double)cafeSales.First(); - Michael Brennt

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