异常:不能将 null 值分配给 System.Int32 类型的成员,该类型是不可为 null 的值类型
有人可以解释为什么在以下 LINQ 查询中发生此异常:
return (from c in dc.Classifications
where c.Id == classificationId
select new Classification()
{
Description = c.Description,
ParentId = Convert.ToInt16(c.ParentId),
}).Single<Classification>();
dc 是数据上下文,Classification 是包含 int 属性 ParentId 的类。 ParentId 列是来自 Sql Server 数据库的可为 null 的 int。如果数据库中的 ParentId 字段为 null,则该语句将返回 InvalidOperationException。
换句话说,为什么上面的查询会失败并且 'int y = Convert.ToInt16(null);'
工作?
Can someone explain why this exception is occuring the in the following LINQ query:
return (from c in dc.Classifications
where c.Id == classificationId
select new Classification()
{
Description = c.Description,
ParentId = Convert.ToInt16(c.ParentId),
}).Single<Classification>();
dc is the datacontext, Classification is a class containing the int property ParentId. The ParentId column is a nullable int from a Sql Server database. In the case of the ParentId field being null in the database, the statement returns an InvalidOperationException.
In other words, why does the above query fail and
'int y = Convert.ToInt16(null);'
work?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
假设当数据库中为 NULL 时,您希望将 0 作为
ParentId
:我的答案还假设
Classifications.ParentId
的类型为Nullable;
/int?
如果该列在数据库中为 NULL,则其值为null
。我唯一改变的是
?? 0
部分在转换中。如果c.ParentId
为null
,则使用0
,否则使用c.ParentId
。请参阅 ??运营商了解更多信息。Assuming that you want to have 0 as
ParentId
when it is NULL in the database:My answer also assumes, that
Classifications.ParentId
is of typeNullable<int>
/int?
and its value isnull
if the column is NULL in the database.The only thing I changed, was the
?? 0
part in the convert. It uses0
in casec.ParentId
isnull
andc.ParentId
otherwise. See ?? Operator for more info.如果
c.PartentId
可以为null
,则Convert.ToInt16(null)
将引发异常。既然您指出
Classification.ParentId
是一个 int,那么您使用它是否有原因Convert.ToInt16
使其变短?您不想用 ToInt32 代替吗?就此而言,为什么要转换呢?简单地说:...而且只是为了挑剔,从技术上讲,您不需要在该 Linq 表达式的末尾指定您的类型:
您可以省略它,因为它是由编译器确定的,只需执行以下操作:
更新:
哦,我明白了,很抱歉我误读了您原来的问题。问题实际上是为什么:
有效,而 Linq2Sql 表达式中的相同内容会引发异常。
我对此没有一个很好的答案,只是指出虽然表达式在代码中看起来相同,但它们实际上是由 2 个不同的 Linq 实现处理的。 (就像接口可以有不同的支持实现一样)。
在以下情况下:
您正在直接调用 Convert.ToInt16。这似乎将 null 转换为
default
,其中 T 是所需的类型(因此在本例中返回 0)。但是,当在 Linq2Sql 表达式中使用时,表达式及其投影将传递给 Linq2Entities 或 Linq2Sql 进行处理。那些东西可能在某个地方有一个错误。用作基本的 Linq2Objects(或任何您想称呼它的内容)时,它实际上似乎工作正常:
上面的“选择”有效,但是针对 Linq2Sql 或 EntityFramework 集合放置相同的 Linq 表达式将导致 Linq 处理器的不同实现处理表达式,并且它可能会做一些不同的事情来尝试优化表达式,或者将其中一些转换为 SQL 语句,或者可能只是存在其他实现没有的错误。
我知道这并不能真正解决你的问题,但它可能有助于解释它?
If
c.PartentId
can benull
, thenConvert.ToInt16(null)
would throw an exception.Since you indicate that
Classification.ParentId
is an int, is there a reason you are usingConvert.ToInt16
to make it a short instead? Wouldn't you want ToInt32 instead? For that matter, why convert at all? simply:...and just to nit-pick, technically you don't need to specify your type at the end of that Linq expression:
you can omit that, since it is determined by the compiler, and just do:
Update:
Oh I see, I'm sorry I mis-read your original question. The question is really why does:
work, while the same thing in a Linq2Sql expression throws an exception.
I don't have a great answer to that, other than to point out that while the expressions look the same in code,t hey are actually handled by 2 differnet Linq implementations. (Much the same as an interface can have different backing implementations).
In the case of:
You are making a direct call to Convert.ToInt16. This seems to convert a null into
default<T>
where T is the desired type (so it return 0 in this case).However when used in a Linq2Sql expression, the expression and its projection are handed off to Linq2Entities or Linq2Sql to process. There could just be a bug in that stuff somewhere. Used as a basic Linq2Objects (or whatever you want to call it) it actually seems to work OK:
The above "select" works, however putting the same Linq expression against a Linq2Sql or EntityFramework collection would cause a different implementation of the Linq processor to handle the expression,a nd it might do something different to try to optemise the expression, or to turn some of it into a SQL statement, or could just have bugs that the other implementations don't.
I know that doesn't really solve your issue, but it might help to explain it?
c.ParentId 的类型为
int?
您对 Convert.ToInt16 的调用会以两种方式被破坏;如果为 null(如此处),则失败;如果 ParentId 大于 Short.MaxValue 或小于 Short.MinValue,则失败。
为什么会有这个电话?将其删除。另外,将
Single()
替换为SingleOrDefault()
,以便它可以在适当的时候返回 null。c.ParentId is of type
int?
Your call to Convert.ToInt16 is then broken in two ways; it fails on null (as here) and it fails if ParentId is greater than short.MaxValue or smaller than short.MinValue.
Why is that call there? Remove it. Also, replace
Single<Classification>()
withSingleOrDefault()
so that it can return null when appropriate.