【问题标题】:Exception: The null value cannot be assigned to a member with type System.Int32 which is a non-nullable value type例外:不能将 null 值分配给 System.Int32 类型的成员,该类型是不可为 null 的值类型
【发布时间】:2014-01-17 14:14:46
【问题描述】:

有人可以解释为什么在以下 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 字段为空的情况下,该语句将返回 InvalidOperationException。

也就是说,上面的查询为什么会失败? 'int y = Convert.ToInt16(null);'
工作吗?

【问题讨论】:

  • 当数据库中的字段为空时,您希望 ParentID 中的值是多少?
  • int x = Convert.ToInt16(matches.Single().ParentId);当数据库中的 ParentId 为 null 时,这不会引发任何异常吗?...奇怪!!!
  • 如果数据库字段为空,我希望 ParentId 为零。
  • 我的解决方案对您没有帮助吗?还请发布该InvalidOperationException 的确切错误消息和堆栈跟踪。
  • @Daniel Hilgarth:是的,我已经更改了代码以使用 c.ParentId ? 0. 但是,我也想知道为什么转换在 Linq2Sql 中不起作用。抱歉不清楚。

标签: c# linq linq-to-sql


【解决方案1】:

假设您希望在数据库中为 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&lt;int&gt;/int?,如果数据库中的列为NULL,则其值为null

我唯一改变的是转换中的?? 0 部分。如果c.ParentIdnull,它使用0,否则使用c.ParentId。请参阅?? Operator 了解更多信息。

【讨论】:

    【解决方案2】:

    如果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&lt;T&gt; 其中 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 语句,或者可能只是存在其他实现没有的错误。

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

    【讨论】:

    • Nullable x = null; int y = Convert.ToInt16(x);结果 y=0。当它是 LINQ 表达式的一部分时,为什么会导致异常??
    【解决方案3】:

    c.ParentId 的类型为int?

    您对 Convert.ToInt16 的调用会以两种方式中断;它在 null 上失败(如此处),如果 ParentId 大于 short.MaxValue 或小于 short.MinValue 则失败。

    为什么会有那个电话?去掉它。另外,将Single&lt;Classification&gt;() 替换为SingleOrDefault(),以便它可以在适当的时候返回null。

    【讨论】:

    • Nullable x = null; int y = Convert.ToInt16(x);结果 y=0。当它是 LINQ 表达式的一部分时,为什么会导致异常??
    猜你喜欢
    • 2013-04-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-11-28
    相关资源
    最近更新 更多