异常:无法将null值分配给类型为System.Int32的成员,该类型是非可空值类型

时间:2011-03-28 15:07:14

标签: c# linq linq-to-sql

有人可以解释为什么在以下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);'
工作?

3 个答案:

答案 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部分。如果0c.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。