简体   繁体   English

Ef 核心字符串不包含排除空

[英]Ef Core String Not Contains Excludes Null

Why is it that when i query in Entity Framework Core for string Not Equals it will give return NULL values (by appending "Or ISNULL(field)"), but when i query for example "not Contains" or "not StartWith" It will not为什么当我在 Entity Framework Core 中查询字符串 Not Equals 时,它会返回 NULL 值(通过附加“Or ISNULL(field)”),但是当我查询例如“not Contains”或“not StartWith”时它会不是

I know that i can achieve the same result by adding manually to the query to include NULL, my question is why are the 2 behaving differently when it comes to NULL?我知道我可以通过手动添加到查询中以包含 NULL 来获得相同的结果,我的问题是为什么 2 在涉及 NULL 时表现不同? is there any obvious reason for that?有什么明显的原因吗?

Code Example:代码示例:

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

Generated Sql - exec sp_executesql N'SELECT [x].[firstName] FROM [Employee] AS [x] WHERE (([x].[jobNotes] <> N''abc'') OR [x].[jobNotes] IS NULL)'生成的 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(); C# - dbContext.Employee.Where(x => !x.jobNotes.Contains("abc")).Select(x => x.firstName).ToList();

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

The reason is not "obviously", but it can be explained somehow:原因不是“显然”,但可以以某种方式解释:

Having the C# expression:有 C# 表达式:

x.jobNotes.Contains("abc")

only "works", when the value of x.JobNotes is not NULL , otherwise you would get a NullReferenceException .只有“有效”,当x.JobNotes的值不是NULL ,否则你会得到一个NullReferenceException To ensure that you don't, only NOT NULL values are checked.为确保您不这样做,只检查NOT NULL值。 The generated SQL statement生成的 SQL 语句

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

does that because for any NULL values in the jobNotes table, the result of CHARINDEX will be NULL , as defined in the documentation of CHARINDEX :这样做是因为对于jobNotes表中的任何NULL值, CHARINDEX的结果将是NULL ,如CHARINDEX文档中所定义:

If either the expressionToFind or expressionToSearch expression has a NULL value, CHARINDEX returns NULL.如果expressionToFindexpressionToSearch表达式具有 NULL 值,则 CHARINDEX 返回 NULL。

Comparing NULL values in this case ( NULL <= 0 ) results in UNKNOWN , as defined in the documentations of comparison operators :在这种情况下比较NULL值 ( NULL <= 0 ) 会导致UNKNOWN ,如比较运算符文档中所定义:

When SET ANSI_NULLS is ON, an operator that has one or two NULL expressions returns UNKNOWN.当 SET ANSI_NULLS 为 ON 时,具有一两个 NULL 表达式的运算符将返回 UNKNOWN。 When SET ANSI_NULLS is OFF, the same rules apply, except for the equals (=) and not equals (<>) operators.当 SET ANSI_NULLS 为 OFF 时,应用相同的规则,但等于 (=) 和不等于 (<>) 运算符除外。 When SET ANSI_NULLS is OFF, these operators treat NULL as a known value, equivalent to any other NULL, and only return TRUE or FALSE (never UNKNOWN).当 SET ANSI_NULLS 为 OFF 时,这些运算符将 NULL 视为已知值,等同于任何其他 NULL,并且只返回 TRUE 或 FALSE(从不为 UNKNOWN)。

I'm not sure what WHERE UNKNOWN would do as you cannot run this expression directly, but as an example the expression WHERE NULL <= 0 results in WHERE FALSE , which means the row with the jobNotes column set to NULL is not returned.我不确定WHERE UNKNOWN会做什么,因为您不能直接运行此表达式,但作为示例,表达式WHERE NULL <= 0导致WHERE FALSE ,这意味着不会返回jobNotes列设置为NULL的行。

When you look at the query from the C# or Entity Framework standpoint, it does make sense that these NULL values are not returned.当您从 C# 或实体框架的角度查看查询时,不返回这些NULL值确实是有意义的。 When you have a query like当您有类似的查询时

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

and you get entities where the jobNotes column is NULL , the question arise:并且您得到jobNotes NULL实体,问题出现了:

"Wait, why is jobNotes NULL? It should have thrown a NullReferenceException because of the Contains() method call." “等等,为什么jobNotes NULL?它应该因为Contains()方法调用而抛出NullReferenceException 。”

So, that might be the reason why it does not return rows where the jobNotes column has the value NULL (and works "differently" with x.jobNotes != "abc" ).因此,这可能是它不返回jobNotes列值为NULL行的原因(并且与x.jobNotes != "abc"以“不同的方式”工作)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM