2011-03-28 77 views
1

有人能解释为什么这个异常在下面的LINQ查询存在的了:例外:空值不能分配与类型System.Int32一个成员是一个非空的值类型

 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字段在数据库中为空的情况下,该语句返回InvalidOperationException。

换句话说,为什么上面的查询失败并且 'int y = Convert.ToInt16(null);'
工作?

+0

当数据库中的字段为空时,您希望在ParentID中使用什么值? – Kipotlov 2011-03-28 15:12:05

+0

int x = Convert.ToInt16(matches.Single()。ParentId);当这个ParentId在db中为空时,这不会抛出任何异常吗?......奇怪! – 2011-03-28 15:21:04

+0

如果数据库字段为空,我希望ParentId为零。 – Will 2011-03-28 19:15:33

回答

1

如果c.PartentId可以null,然后Convert.ToInt16(null)会抛出异常。

既然你指出Classification.ParentId是一个整数,是不是有一个原因,你使用 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); 
} 

上述的“选择”的作品,但是把同样的LINQ表达式针对LINQ2SQL或的EntityFramework收集会导致Linq处理器的不同实现来处理表达式,并且它可能会尝试对表达式进行不同的操作,或者将其中的一部分转换为SQL语句,或者可能只是存在其他实现不会执行的错误。

我知道这并不能真正解决您的问题,但它可能有助于解释它?

+0

Nullable x = null; int y = Convert.ToInt16(x);导致y = 0。为什么当它是LINQ表达式的一部分时会导致异常? – Will 2011-03-28 19:25:17

2

假设你想有0作为ParentId当它在数据库中NULL:

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部分。如果c.ParentIdnullc.ParentId,则使用0。有关更多信息,请参见?? Operator

0

c.ParentId的类型是int?

您对Convert.ToInt16呼叫随后在两个方面打破;它失败(如这里),如果ParentId大于short.MaxValue或小于short.MinValue,则失败。

为什么在那里打电话?去掉它。另外,将Single<Classification>()替换为SingleOrDefault(),以便它在适当时可以返回null。

+0

可为空 x = null; int y = Convert.ToInt16(x);导致y = 0。为什么当它是LINQ表达式的一部分时会导致异常? – Will 2011-03-28 19:26:42