【问题标题】:Ef Core String Not Contains Excludes NullEf 核心字符串不包含排除 Null
【发布时间】:2021-01-22 04:36:29
【问题描述】:

为什么当我在 Entity Framework Core 中查询字符串 Not Equals 时它会返回 NULL 值(通过附加“或 ISNULL(字段)”),但是当我查询例如“不包含”或“不 StartWith”时" 不会

我知道我可以通过手动添加到查询中以包含 NULL 来实现相同的结果,我的问题是为什么 2 在涉及 NULL 时表现不同?有什么明显的原因吗?

代码示例:

C# - dbContext.Employee.Where(x => x.jobNotes != "abc").Select(x => x.firstName).ToList();

生成的 Sql - exec sp_executesql N'SELECT [x].[firstName] FROM [Employee] AS [x] WHERE (([x].[jobNotes] <> N''abc'') OR [x].[jobNotes] IS NULL)'

C# - dbContext.Employee.Where(x => !x.jobNotes.Contains("abc")).Select(x => x.firstName).ToList();

生成的 Sql - exec sp_executesql N'SELECT [x].[firstName] FROM [Employee] AS [x] WHERE (CHARINDEX(N''abc'', [x].[jobNotes]) <= 0)'

【问题讨论】:

  • 您要问的是“为什么 EF Core 团队决定做出这个具体的实施决定”,不幸的是,除非在场的人是核心团队成员,否则任何答案都是猜测。可能值得在 EF Core 存储库上打开一个问题以了解清楚。
  • 嗯,这很有意义。 NULL 不是“Hello World”,因此如果我查询“所有内容但“Hello World””,请包含 NULLS。但是 NULL 永远不会包含任何内容,也不会以字符串开头。所以从我的结果中排除它。
  • edit 您的问题包括您在 C# 代码中的 LINQ(?) 语句和生成的 SQL 语句。然后解释您想要(或不想要)任何ISNULL() 语句的位置以及原因。

标签: c# entity-framework-core


【解决方案1】:

原因并不“明显”,但可以通过某种方式解释:

拥有 C# 表达式:

x.jobNotes.Contains("abc")

只有当x.JobNotes 的值不是NULL 时才“有效”,否则你会得到NullReferenceException。为确保您不这样做,仅检查 NOT NULL 值。生成的SQL语句

(CHARINDEX(N''abc'', [x].[jobNotes]) <= 0)

这样做是因为对于jobNotes 表中的任何NULL 值,CHARINDEX 的结果将是NULL,如documentation of CHARINDEX 中所定义:

如果 expressionToFindexpressionToSearch 表达式的值为 NULL,则 CHARINDEX 返回 NULL。

在这种情况下比较 NULL 的值 (NULL &lt;= 0) 得到 UNKNOWN,如 documentations of comparison operators 中所定义:

当 SET ANSI_NULLS 为 ON 时,具有一个或两个 NULL 表达式的运算符返回 UNKNOWN。当 SET ANSI_NULLS 为 OFF 时,应用相同的规则,但等于 (=) 和不等于 () 运算符除外。当 SET ANSI_NULLS 为 OFF 时,这些运算符将 NULL 视为已知值,等同于任何其他 NULL,并且仅返回 TRUE 或 FALSE(从不 UNKNOWN)。

我不确定WHERE UNKNOWN 会做什么,因为您不能直接运行此表达式,但作为示例,表达式WHERE NULL &lt;= 0 会导致WHERE FALSE,这意味着将jobNotes 列设置为@ 的行987654341@不返回。

当您从 C# 或实体框架的角度查看查询时,不返回这些 NULL 值是有道理的。当您有类似的查询时

dbContext.Employee
    .Where(x => !x.jobNotes.Contains("abc"))
    .Select(x => x.firstName)
    .ToList()

如果你得到jobNotes 列是NULL 的实体,问题就出现了:

“等等,为什么jobNotes NULL?它应该抛出一个NullReferenceException 因为Contains() 方法调用。”

因此,可能是它不返回 jobNotes 列的值为 NULL 的行的原因(并且与 x.jobNotes != "abc" 的工作方式“不同”)。

【讨论】:

  • 与 linq 到实体一样有意义,如果它为 null 但不等于当然有效,您实际上会得到一个不包含的 NullReferenceException,但它仍然很有趣,因为在 linq to sql 的情况下“包含”是真的只是传递给 sql 和 sql 将能够处理它并返回空值
  • 但问题是,如果它应该返回具有NULL 值的行,那么x.jobNotes.Contains() 将导致 NullReferenceException。看起来并不一致。
  • 我相信在“linq to sql”的情况下,语句 x.jobNotes.Contains() 永远不会在 c# 中进行评估,而是 c# 会将其转换为 sql 并让 sql 进行评估(也许我错了那)所以它不应该导致 NullReferenceException
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-01-17
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多