【问题标题】:.Any() with Nullables - Returns False When I Expect True.Any() with Nullables - 当我期望 True 时返回 False
【发布时间】:2011-08-12 14:38:16
【问题描述】:

我有一个可以为空的 int 的视图模型...

public ObjectViewModel (){
    public int? Total
}

...我的数据库中有几行总数为 null

尽管如此,这总是返回 false

bool exists = repo.AllRows() // renamed this for clarity; returns IQueryable
                  .Any(r => r.Total == vm.Total); // I know r.Total and vm.Total
                                                  // are both null

但以下返回true(如预期):

bool exists = repo.All().Any(r => r.Total == null);

知道我在这里做错了什么吗?

【问题讨论】:

  • 如果 vm 为空,你会得到一个 NullReferenceException。
  • 你从哪里得到 vm,它有什么价值?从结果中,我预计它的值在您的结果集中不存在。
  • Any之前调用All的目的是什么?
  • 关于 vm,即使你没有声明你在循环中这样做,如果你这样做要小心:blogs.msdn.com/b/ericlippert/archive/2009/11/12/…
  • All 中的谓词是什么?据我所知,没有一个就不能调用它。

标签: c# linq extension-methods nullable


【解决方案1】:

假设您的意思是“vm.Total 为空”并且 All() 是一个错字...

我认为你的问题是它被翻译成 SQL 的方式:

  • 第一个查询被翻译为带有r.Total = @param1 的 WHERE 子句
  • 第二个查询被翻译为使用IS NULL 的WHERE 子句

MSDN has a good description on NULL:

NULL 值表示该值是 未知。 NULL 值不同 从空值或零值。没有两个 空值相等。比较 在两个空值之间,或在一个 NULL 和任何其他值,返回 未知,因为每个 NULL 的值 未知。

这意味着您不能在 SQL 中使用比较运算符 - 因此您也不能在 Linq to sql 中使用。

解决这个问题的一些方法是:

【讨论】:

  • +1,这肯定是 C# 和 SQL 不匹配的一个例子。我相信您可以在 C# 中使用空合并运算符 (??) 让 LINQ 使用 ISNULL(foo, 0) 代替。至于All() 调用,他不仅不需要它而且不会编译。我怀疑这是一个错误。
  • 添加了博客文章的链接 - brentlamborn.com/post/…
  • .All() 混淆源于我的存储库中有一个 All() 方法,该方法返回 from m in context select m 的结果。我不是指 .All() 扩展方法。它编译得很好。 :-)
  • @ScottSEA 这不是个坏主意吗?
  • @Josh - 是的,正如我们所说的那样进行重构。 :-)
【解决方案2】:

正如 Bala R 所说,如果 vm 为 null,那么您将无法访问 Total 属性,它必须抛出 NullReferenceException。

您的查询应该是:

bool exists = repo.Any(r => r.Total == null);

如果Total 属性中至少有null 的记录,exists 将为真。

【讨论】:

    【解决方案3】:

    如果集合中的任何项目满足 lambda 指定的条件,Any 方法将返回 true。因此,repo 中的所有项目都没有等于 vm.Total 的总计,但是有些项目为空,因此第二个返回 true。

    为了验证,在里面扔了一点调试代码,

    Console.WriteLine("vm.Total=" + vm.Total.ToString());
    foreach (var r in repo)
        Console.WriteLine("r.Total=" r.Total == null ? "null" : r.Total.ToString());
    

    再看看项目,你应该不会看到r.Total,它等于vm.Total,你会看到至少一个null

    【讨论】:

      【解决方案4】:

      您的代码应该给出异常,但无论哪种方式您都可以尝试:

      Any(r => r.Total == vm==null ? null : vm.Total)
      

      【讨论】:

      • 我明白你在说什么,但你不需要一些括号吗? Any(r => r.Total == (vm==null) ? null: vm.Total)
      • 我实际上并没有运行代码,但我相信你没有。查找 C# 喜欢调用的三元运算符或条件运算符。 msdn.microsoft.com/en-us/library/ty67wk28(v=VS.100).aspx
      【解决方案5】:

      乔希的回答对我来说似乎是最准确的。只需使用空合并运算符:

      bool exists = repo.AllRows().Any(r => r.Total ?? 0 == vm.Total ?? 0);
      

      ...您将不再有“WHERE NULL = NULL”,而是“WHERE 0 = 0”,这没关系。

      【讨论】:

        猜你喜欢
        • 2020-10-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2021-07-02
        • 1970-01-01
        相关资源
        最近更新 更多