转换为值类型'Int32'失败,因为实例化值为null


192

我有以下代码。我收到错误消息:

“强制转换为值类型'Int32',因为实例化值为null。结果类型的通用参数或查询必须使用可为空的类型。”

当CreditHistory表没有记录时。

var creditsSum = (from u in context.User
                  join ch in context.CreditHistory on u.ID equals ch.UserID                                        
                  where u.ID == userID
                  select ch.Amount).Sum();

如何修改查询以接受空值?

Answers:


328

linq-to-sql查询不会作为代码执行,而是转换为SQL。有时,这是一种“泄漏抽象”,会产生意外的行为。

一种这样的情况是空值处理,在不同的地方可能会有意外的空值。...DefaultIfEmpty(0).Sum(0)可以在这种(非常简单)的情况下提供帮助,在这种情况下,可能没有任何元素,并且sql的SUM返回值是nullc#期望为0。

一种更通用的方法是,只要生成的SQL有返回意外的null的风险,??就将其转换为COALESCE

var creditsSum = (from u in context.User
              join ch in context.CreditHistory on u.ID equals ch.UserID                                        
              where u.ID == userID
              select (int?)ch.Amount).Sum() ?? 0;

这首先int?要告诉C#编译器null,即使Sum()返回一个,该表达式的确可以返回int。然后,我们使用普通??运算符处理该null案件。

基于此答案,我写了一篇博客文章,其中详细介绍了LINQ to SQL和LINQ to Entities。


3
感谢Anders,使用DefaultIfEmpty(0).Sum()的解决方案对我来说很好。我也用(int?)... ??尝试了第二种解决方案。0 ...,但它抛出同样的异常像以前..
zosim

最终经过测试并对其进行了调整,因此现在第二个版本也可以使用。
Anders Abel

1
Sum()和其他聚合函数在应用于空数据集时将返回null。与它们的定义相反,实际上它们返回基础类型的可空版本。
Suncat2000

2
@recursive:您的示例是LINQ-to-Objects,而不是LINQ-to-SQL(或LINQ-to-Entities)。他们的基础数据提供者使他们的行为有所不同。
Suncat2000

这是个好主意。我将返回对象更新为具有可为空的属性,并且将其作为一种魅力。
Kremena Lalova

8

要允许可为空的Amount字段,只需使用null合并运算符即可将null转换为0。

var creditsSum = (from u in context.User
              join ch in context.CreditHistory on u.ID equals ch.UserID                                        
              where u.ID == userID
              select ch.Amount ?? 0).Sum();

1
当我使用您的提示时,编译器会说:运算符'??' 不能应用于类型为'int'和'int'的操作数。我忘了什么吗?
zosim 2011年

@zosim:这就是将演员表添加到int?第一个的原因。
Anders Abel

我已经添加了int ?,但是同样的例外。当您有开发环境时,我将感激您。检查此语法中的错误。
zosim 2011年

1
@zosim:我不明白这个问题。如果Amountint,则我们已经确定它不能为null,并且不需要合并。如果遇到错误,则说明该错误Amount不可为空,而只是一个int,在这种情况下,您可能需要在设计器中更改linq2sql dbml列以允许为空。
递归

1
@recursive:金额为int,可以。金额已经有价值。我认为,发生上述错误是因为CreditHistory表为空。我在User表中有一条记录,在CreditHistory表中有0条记录,并且发生了错误。当我使用DefaultIfEmpty(0).Sum()时,它工作正常,但带有?? 0它引发错误。我的另一个问题是这种情况下的最佳做法是什么?DefaultIfEmpty(0)吗?谢谢
zosim 2011年

4

您正在使用aggregate不让项目执行操作的函数,必须验证linq查询给出了如下结果:

var maxOrderLevel =sdv.Any()? sdv.Max(s => s.nOrderLevel):0

11
这将使sdv执行两次。对于IQueryables来说,这不是您想要的
Ody

4

当我尝试从视图中进行选择时出现此错误消息。

问题在于视图最近获得了一些新的空行(在SubscriberId列中),并且尚未在EDMX中更新(首先是EF数据库)。

该列必须为Nullable类型才能工作。

var Dealer = Context.Dealers.Where(x => x.dealerCode == DealerCode).FirstOrDefault();

视图刷新之前:

public int SubscriberId { get; set; }

视图刷新后:

public Nullable<int> SubscriberId { get; set; }

在EDMX中删除并重新添加视图已成功。

希望它能帮助某人。


这也是我的问题,也是我的答案
Simon Nicholls

4

我已使用此代码,并且它可以正确响应,只有输出值可以为空。

var packesCount = await botContext.Sales.Where(s => s.CustomerId == cust.CustomerId && s.Validated)
                                .SumAsync(s => (int?)s.PackesCount);
                            if(packesCount != null)
                            {
                                // your code
                            }
                            else
                            {
                                // your code
                            }

1

我看到这个问题已经回答。但是,如果您希望将其分为两个语句,可以考虑以下内容。

var credits = from u in context.User
              join ch in context.CreditHistory 
                  on u.ID equals ch.UserID                                        
              where u.ID == userID
              select ch;

var creditSum= credits.Sum(x => (int?)x.Amount) ?? 0;

0

在运行时使用以下代码在Entity Framework 6中获得此错误:

var fileEventsSum = db.ImportInformations.Sum(x => x.FileEvents)

来自LeandroSoares的更新:

使用此命令执行一次:

var fileEventsSum = db.ImportInformations.Sum(x => (int?)x.FileEvents) ?? 0

原版的:

更改为此,然后它起作用:

var fileEventsSum = db.ImportInformations.Any() ? db.ImportInformations.Sum(x => x.FileEvents) : 0;

1
会执行两次吗?
nawfal

这不是一个好答案。它将两次从数据库检索。
Leandro Soares '18

@nawfal这是正确的,但比运行时错误要好得多。您可以绝对使用linq-to-sql,但使用lambda则更困难。您当然可以捕获异常,但是我认为解决方案比两次执行更糟糕。
Ogglas

@LeandroSoares看到以上评论
Ogglas

1
@LeandroSoares不错的一个!我更新了答案,并使用了您提供的代码并说明了为什么要使用它。
Ogglas

0

我也面临着同样的问题,并通过使用“?”将列设置为可空值来解决。操作员。

Sequnce = db.mstquestionbanks.Where(x => x.IsDeleted == false && x.OrignalFormID == OriginalFormIDint).Select(x=><b>(int?)x.Sequence</b>).Max().ToString();

有时会返回null。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.