转换为值类型“Int32”失败,因为具体化值为 null

Posted

技术标签:

【中文标题】转换为值类型“Int32”失败,因为具体化值为 null【英文标题】:The cast to value type 'Int32' failed because the materialized value is null 【发布时间】:2011-10-15 09:53:14 【问题描述】:

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

“转换为值类型 '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();

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

【问题讨论】:

【参考方案1】:

要允许可以为空的 Amount 字段,只需使用空值合并运算符将空值转换为 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();

【讨论】:

当我使用你的提示时,编译器会说:运算符'??'不能应用于“int”和“int”类型的操作数。我忘记了什么吗? @zosim:这就是首先将演员表添加到int? 的原因。 我添加了 int?,但同样的例外。当您拥有开发环境时,我将感谢您。检查这个语法有什么问题。 @zosim:我不明白这个问题。如果Amountint,那么我们已经确定它不能为空,不需要合并。如果您收到您所说的错误,那么Amount 不可为空,它只是一个int,在这种情况下,您可能需要更改设计器中的 linq2sql dbml 列以允许为空。 @recursive:金额是整数,没关系。金额已经有价值。我认为,发生上述错误是因为 CreditHistory 表为空。我在 User 表中有 1 条记录,在 CreditHistory 表中有 0 条记录,并且发生错误。当我使用 DefaultIfEmpty(0).Sum() 时,它工作正常,但使用 ?? 0 它抛出错误。我的另一个问题是在这种情况下最佳做法是什么?默认如果空(0)?谢谢【参考方案2】:

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

这样的一种情况是空值处理,在不同的地方可能会有意想不到的空值。 ...DefaultIfEmpty(0).Sum(0) 可以在这种(非常简单的)情况下提供帮助,其中可能没有元素并且 sql 的 SUM 返回 null 而 c# 期望 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 的情况。

基于这个答案,我写了一个blog post,其中包含 LINQ to SQL 和 LINQ to Entities 的详细信息。

【讨论】:

感谢安德斯,使用 DefaultIfEmpty(0).Sum() 的解决方案对我来说很好。我也尝试过使用 (int?) ... ?? 的第二种解决方案0 ...,但它会引发与以前相同的异常.. 终于有时间测试并调整了它,所以现在第二个版本也可以了。 Sum() 和其他聚合函数在应用于空数据集时将返回 null。与它们的定义相反,实际上它们返回底层类型的可为空版本。 @recursive:您的示例是 LINQ-to-Objects,而不是 LINQ-to-SQL(或 LINQ-to-Entities)。它们的底层数据提供者使它们的行为有所不同。 这是个好主意。我更新了我的返回对象以具有可为空的属性,这很有吸引力。【参考方案3】:

您正在使用 aggregate 函数,它没有让项目执行操作,您必须验证 linq 查询是否给出如下结果:

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

【讨论】:

这会使 sdv 执行两次。这不是您想要的 IQueryables【参考方案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
                            

【讨论】:

谢谢!!!天哪,这很棘手,所以如果你 Concat 结果它必须是 final【参考方案5】:

我看到这个问题已经回答了。但是如果你想把它分成两个语句,可以考虑如下。

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;

【讨论】:

【参考方案6】:

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

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

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

var 经销商 = Context.Dealers.Where(x => x.dealerCode == DealerCode).FirstOrDefault();

视图刷新前:

public int SubscriberId  get; set; 

视图刷新后:

public Nullable<int> SubscriberId  get; set; 

在 EDMX 中删除和添加视图有效。

希望它可以帮助某人。

【讨论】:

这也是我的问题和我的答案【参考方案7】:

在运行时使用此代码在 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;

【讨论】:

不会执行两次吗? 这不是一个好的答案。它将从数据库中检索两次。 @nawfal 这是真的,但它比运行时错误要好得多。您绝对可以使用 linq-to-sql 但使用 lambda 会更难。您当然可以捕获异常,但我认为该解决方案比执行两次更糟糕。 @LeandroSoares 见上述评论 @LeandroSoares 不错!我更新了我的答案并使用了您提供的代码并说明了为什么要使用它。【参考方案8】:

我也面临同样的问题,并通过使用“?”将列设为可空来解决。运算符。

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

有时会返回 null。

【讨论】:

以上是关于转换为值类型“Int32”失败,因为具体化值为 null的主要内容,如果未能解决你的问题,请参考以下文章

从具体化的“System.Int32”类型到“System.Int64”类型的指定转换无效

从具体化的“System.Int32”类型到“System.Double”类型的指定转换无效

ArrowTypeError: Did not pass numpy.dtype object', '转换失败的列 X 类型为 int32

如何将 int32 类型转换为 int,因为它不是 JSON 可序列化的

C#数组的笔记

Mongoose:CastError:在路径“items”处为值“ value:'x'”转换为嵌入失败