转换为值类型“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:我不明白这个问题。如果Amount
是int
,那么我们已经确定它不能为空,不需要合并。如果您收到您所说的错误,那么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