有人可以解释为什么在以下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是datacontext,Classification是一个包含int属性ParentId的类。 ParentId列是来自Sql Server数据库的可空int。如果ParentId字段在数据库中为null,则该语句返回InvalidOperationException。
换句话说,为什么上面的查询失败了
'int y = Convert.ToInt16(null);'
工作?
答案 0 :(得分:2)
假设您希望在数据库中为NULL时将0设为ParentId
:
return (from c in dc.Classifications
where c.Id == classificationId
select new Classification()
{
Description = c.Description,
ParentId = Convert.ToInt16(c.ParentId ?? 0),
}).Single<Classification>();
我的回答还假设Classifications.ParentId
的类型为Nullable<int>
/ int?
,如果数据库中的列为NULL,则其值为null
。
我唯一改变的是转换中的?? 0
部分。如果0
为c.ParentId
,则null
使用c.ParentId
,否则为{{1}}。有关详细信息,请参阅?? Operator。
答案 1 :(得分:1)
如果c.PartentId
可以是null
,则Convert.ToInt16(null)
会抛出异常。
由于您指出Classification.ParentId
是一个int,因此您使用的原因是正确的
Convert.ToInt16
让它变短了吗?你不想要ToInt32吗?就此而言,为什么转换呢?简单地:
ParentId = c.ParentId ?? 0
...而且只是为了挑选,从技术上讲,你不需要在Linq表达式的末尾指定你的类型:
.Single<Classification>()
你可以省略它,因为它是由编译器确定的,只是这样做:
.Single()
<强>更新强>
哦,我明白了,对不起,我错误地读了你原来的问题。问题是为什么:
int y = Convert.ToInt16(null);
工作,而Linq2Sql表达式中的相同内容会引发异常。
我没有一个很好的答案,除了指出虽然表达式在代码中看起来相同,但它实际上是由2个不同的Linq实现处理的。 (与界面大致相同,可以有不同的后台实现)。
以下情况:
int y = Convert.ToInt16(null);
您正在直接调用Convert.ToInt16。这似乎将null转换为default<T>
,其中T是所需的类型(因此在这种情况下返回0)。
但是,当在Linq2Sql表达式中使用时,表达式及其投影将传递给Linq2Entities或Linq2Sql进行处理。那个地方可能只有一个错误。用作基本的Linq2Objects(或者你想要的任何东西)它实际上似乎工作正常:
[TestMethod] // test passes
public void TestLinqToObjects()
{
var stuff = new List<int?>() { null };
var y = (from x in stuff
select Convert.ToInt32(x))
.First();
Assert.AreEqual(0, y);
}
上面的“select”有效,但是对Linq2Sql或EntityFramework集合使用相同的Linq表达式会导致Linq处理器的不同实现来处理表达式,并且它可能会做一些不同的尝试来表达表达式,或者将其中一部分转换为SQL语句,或者只是存在其他实现不存在的错误。
我知道这并没有真正解决你的问题,但它可能有助于解释它?
答案 2 :(得分:0)
c.ParentId的类型为int?
您对Convert.ToInt16的调用会以两种方式被破坏;它在null(如此处)失败,如果ParentId大于short.MaxValue或小于short.MinValue,则失败。
那为什么打电话?去掉它。另外,将Single<Classification>()
替换为SingleOrDefault()
,以便在适当时返回null。