【问题标题】:Linq where column == (null reference) not the same as column == nullLinq where column == (null reference) 与 column == null 不同
【发布时间】:2010-01-19 22:11:05
【问题描述】:

我在使用 linq-to-sql 时遇到了一个相当奇怪的问题。在下面的例子中,

var survey = (from s in dbContext.crmc_Surveys
                                   where (s.crmc_Retail_Trade_Id == tradeId) && (s.State_.Equals(state))
                                   select s).First();

如果tradeId 为null,它的行为就好像我专门指定了这样的null,

var survey = (from s in dbContext.crmc_Surveys
                                   where (s.crmc_Retail_Trade_Id == null) && (s.State_.Equals(state))
                                   select s).First();

这是我想要的行为。事实上,除非两个值都不为空,否则它不会返回任何内容。我不知道如何在缺少几个不同的 linq 查询的情况下完成这个任务。有什么想法吗?

【问题讨论】:

    标签: c# .net linq linq-to-sql


    【解决方案1】:

    更改where (s.crmc_Retail_Trade_Id == tradeId)

    where (s.crmc_Retail_Trade_Id == tradeId || 
          (tradeId == null && s.crmc_Retail_Trade_Id == null))
    

    编辑 - 基于 Brant Lamborn 的 this post,看起来以下内容可以满足您的需求:

    where (object.Equals(s.crmc_Retail_Trade_Id, tradeId))
    

    Null Semantics (LINQ to SQL) MSDN 页面链接到一些有趣的信息:

    LINQ to SQL 不会强制 C# null 或 Visual Basic 没什么比较 SQL 上的语义。比较运算符 在句法上被翻译成他们的 SQL 等价物。语义反映 服务器定义的 SQL 语义或 连接设置。两个空值 默认情况下被认为是不平等的 SQL Server 设置(尽管您可以 更改设置以更改 语义)。无论如何,LINQ to SQL 不考虑服务器设置 查询翻译。

    与文字 null 的比较 (无)被翻译成 适当的 SQL 版本(为 null 或为 不为空)。

    null(无)的值在 排序规则由 SQL Server 定义; LINQ to SQL 不会改变 排序规则。

    【讨论】:

    • 是的,我想这是显而易见的答案。但好奇的人想知道为什么常量 null 与指向 null 的变量不同。
    • 我怀疑 Joel Coehoorn 是正确的,您的问题中的第二种情况被转换为直接指定 null 的 sql 查询。
    • 这似乎是微软 linq 解析器中的一个非常大的缺陷,甚至是错误,无法正确处理空对象引用,但我会相信你的话。
    • “适当地”是非常主观的 - 我从 MSDN 添加了一些文本来解释 LINQ 的作用。
    • 我刚刚尝试了 object.Equals 解决方法,它适用于可为空的整数,但不适用于字符串。 (使用 LINQ to EF,而不是 LINQ to SQL)
    【解决方案2】:

    解决这个问题的另一种选择,因为我也遇到了这个问题。

    where (tradeId == null ? s.crmc_Retail_Trade_Id == null : s.crmc_Retail_Trade_Id == tradeId)
    

    【讨论】:

      【解决方案3】:

      不确定这一点,但我怀疑当 linq-to-sql 将其转换为 sql 查询字符串时,您会得到一个稍微不同的表达式,直接指定 null,这样在某些时候您最终会将 NULL 与自身进行比较,并且NULL=NULL 被定义为假。

      【讨论】:

      • 除非 ANSI_NULLS 设置为 OFF。但这会导致宇宙内爆。
      【解决方案4】:

      我不熟悉 Linq,但总的来说:

      NULL 表示缺失、未知或未定义的值。严格来说,一个变量不能等于NULL;提供这种结构的低级语言通常这样做是为了方便,因为没有简单的替代方案——在更高级别上,通常最好依赖 ISNULLdefined 或您的语言提供的任何功能。

      一个未定义的变量不等于另一个未定义的变量(同样适用于 NULL == NULL)。 Joe Celko 有一个很好的例子,他编写了一个查询来查找所有头发颜色与他们驾驶的车辆颜色相匹配的人。这个查询应该匹配一个到处走的秃子吗?

      【讨论】:

      • 我认为一个男人不存在的头发颜色被认为与他不存在的汽车油漆相匹配是很有道理的。
      • 在低级或高级语言中,null 是十六进制值 0x0,null == null 为真。现在我知道这在 SQL 中是不正确的,但 C# 不是 SQL,我们希望这能坚持下去。 Linq-to-Sql 应该是 C# 用户的抽象。如果你问我 MS 搞砸了,我错了吗?
      • 确实如此。我更想向那些想知道为什么常量 null 与指向 1 的变量不同的询问者解释。在大多数情况下,null 等价于 0x0,如果您需要指向内存段开头的指针,这是一个严重的问题(幸好这不再是问题)。我说等价是因为我认为与等价有细微的差别。这就像说 1.999999999... 不等于 2,它们恰好是相同的值只是数学上的不便。
      • 我更愿意认为它们是不同的。在 Perl 中,定义为 0。在 PHP 0 中!== null。在 SQL 0 中!= NULL。在 XSLT 中,设置为 0 的属性与未定义的属性不匹配。应该记住,即使您的语言允许,它仍然是对不确定性的测试,而不是平等性的测试。
      • 我猜它如何从 C# 转换为 SQL 取决于它是由 C# 人还是 SQL 人实现的。但是,如果它应该是 C# 程序员的抽象,但它并没有达到 C# 程序员的预期,那么 MS 确实搞砸了。 (请注意,即使它确实按预期工作,我仍然怀疑某处发生了一些令人讨厌的事情。)
      【解决方案5】:

      最好为此目的制作 sp,因为如果您正在使用 linq,linq 将执行迭代,同时为您提供帮助。

      var c = lstQ_Buffer.Where(q => (((semesterId == 0 || semesterId == null ? q.fkSemesterId == null : q.fkSemesterId == semesterId) && (subjectSpecialtyId == 0 || subjectSpecialtyId == null ? q.fkSubSpecialtyId == null : q.fkSubSpecialtyId == subSpecialtyId) && (subTopicId == 0 || subTopicId == null ? q.fkSubTopicId == null : q.fkSubTopicId == subTopicId)) && (q.fkProgramId == programId && q.fkYearId == yearId && q.fkCourse_ModuleId == courseModuleId && q.fkSubject_SpecialtyId == subjectSpecialtyId && q.fkTopicId == topicId && q.fkDifficultyLevelId == diffucultyLevelId))).ToList();
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2013-09-25
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多