实体框架核心 - 包含区分大小写还是不区分大小写?

Posted

技术标签:

【中文标题】实体框架核心 - 包含区分大小写还是不区分大小写?【英文标题】:Entity Framework core - Contains is case sensitive or case insensitive? 【发布时间】:2017-09-02 19:45:35 【问题描述】:

Entity Framework 核心中的“包含”应该等同于 SQL %like% 运算符。因此“包含”应该不区分大小写,但它是区分大小写的! (至少在 postgres 中????)

以下仅在使用正确的关键字大小写时输出结果。

context.Counties.Where(x => x.Name.Contains(keyword)).ToList();

我做错了什么?

【问题讨论】:

LIKE 在 postgresql 中区分大小写。 请注意,有一个名为“citext”的扩展名,它允许您使用不区分大小写的“citext”类型的列进行比较。否则,您应该显式使用lower 来执行不区分大小写的比较。 postgresql 中还有ILIKE,它是LIKE 的不区分大小写版本。 @Evk 难怪! 【参考方案1】:

以前是旧版本的 EF 内核的情况。现在string.Contains 区分大小写,例如 sqlite 它映射到 sqlite 函数 `instr()' (我不知道对于 postgresql)。

如果您想以不区分大小写的方式比较字符串,您可以使用 DbFunctions 来完成这项工作。

context.Counties.Where(x => EF.Functions.Like(x.Name, $"%keyword%")).ToList();

@Gert 更新:

问题中的部分假设不正确。 string.Contains 不会转换为 LIKE expression,即使它曾经在 ef 核心版本

在SQLServer string.contains 转换为CHARINDEX(),在oracle 和sqlite 转换为instr() 默认情况下区分大小写,除非另外定义了db 或列排序规则(同样,我不知道对于 postgresql )。 在所有情况下,EF.Functions.Like() 都会转换为默认情况下不区分大小写的 SQL LIKE 表达式,除非另外定义了 db 或列排序规则。

所以是的,这一切都归结为排序规则,但是 - 如果我错了,请纠正我 - 在某种程度上,代码可能会影响区分大小写/不区分大小写的搜索,具体取决于您使用上述哪种方法。

现在,我可能不是完全最新的,但我认为 EF 核心迁移不会自然地处理数据库排序规则,除非您已经手动创建了表,否则您最终会使用默认排序规则(区分大小写sqlite,我真的不知道其他人)。

回到最初的问题,如果在未来的版本中没有 3 个选项,您至少有 2 个选项来执行此不区分大小写的搜索:

    使用此trick 在创建时使用 DbContext.OnModelCreating() 指定列排序规则 将您的string.Contains 替换为EF.Functions.Like() 或等待discussion 中仍有前景的功能:EF.Functions.Collate() 函数

【讨论】:

不正确。它仅取决于数据库排序规则。 EF在这里没有任何影响,更不用说EF版本了。 排序规则对此有影响,我不是说别的。但是,如果您不想使用排序规则,您可以选择我在这里指出的选项。但是,让我编辑我的回复,希望我不会错。 好的,继续,但是除了申请ToLower之外,真的没有办法从客户那里得到指导,但那是“作弊”。 EF.Functions.ILike... 发现这一点真是太棒了。谢谢。 安全性怎么样;这似乎很可能不安全:EF.Functions.Like(x.Name, $"%keyword%")【参考方案2】:

我的回答将涉及 NpgSQL。

    PostgreSQL 中的EF.Functions.Like() 区分大小写,但您可以使用位于Npgsql.EntityFrameworkCore.PostgreSQL assembly 的EF.Functions.ILike() 扩展method。

    如果您在构建查询的地方没有参考实体框架程序集,您可以使用ToLower()Contains() 组合方法,因为Npgsql 是able 转换ToLower() 方法来纠正SQL

例子:

context.Counties.Where(x => x.Name.ToLower().Contains(keyword.ToLower())).ToList();

关于第二种方法请记住:您可能会遇到性能问题并且可能会遇到与编码相关的问题。

【讨论】:

性能地狱正是把我带到这里的原因,我使用的是第二种方法,我无法理解为什么我的查询需要 5 分钟才能执行,请小心使用第二种方法,性能上的变化是吓人的。 我在这里参加聚会有点晚了,但我想知道性能影响,因为第二种方法似乎对我很有效。我检查了查询,发现它使用 strpos(lower(...)) 进行字符串比较,在这篇文章 (dba.stackexchange.com/questions/89901/…) 中提到它是更快的选择。我在这里错过了什么吗? @HakanFıstık ToLower in postgres 将使用扫描列,这就是它性能非常差的原因。【参考方案3】:

IQueryable.Where在数据库中执行,所以很可能不区分大小写。

IEnumerable.Where 使用 C# String.Contains,所以区分大小写。

阅读此答案:Returning IEnumerable vs. IQueryable

【讨论】:

IQueriable 的行为将取决于数据库。例如,在 SQL Server 中,它不区分大小写,但对于 postgres,它是区分大小写的【参考方案4】:

试试吧:

您可以Lower case字段和搜索值

  context.Counties.Where(x => x.Name.ToLower().Contains(keyword.ToLower())).ToList();

或者你可以Upper Case提交并搜索值

context.Counties.Where(x => x.Name.ToUpper().Contains(keyword.ToUpper())).ToList();

【讨论】:

这可能会导致非常大的性能问题,尤其是对于 PostgreSQL,请参阅上面的@Stas 答案以避免您可能面临的性能灾难 还有不变文化的问题,你不能通过不变文化【参考方案5】:

在查询中使用显式排序规则

例如

var customers = context.Customers
.Where(c => EF.Functions.Collate(c.Name, "SQL_Latin1_General_CP1_CS_AS") == "John")
.ToList();

更多详情见msdn链接

https://docs.microsoft.com/en-us/ef/core/miscellaneous/collations-and-case-sensitivity

【讨论】:

【参考方案6】:

使用 Entity Framework Core 3.1 和 mysql / MariaDB 提供程序,您可以通过以下方式手动设置大小写(不)敏感度 StringComparison.InvariantCultureIgnoreCase

items = items.Where(i => 
    i.Name.Contains(value, StringComparison.InvariantCultureIgnoreCase));

默认行为似乎区分大小写,但是您可以使用 StringComparison.InvariantCulture 显式设置它。

有关更多信息,请查看我博客上的this post。

我不知道它是否也适用于以前的版本(将相应地检查并更新此答案)。

【讨论】:

这款的表现如何?它是否被转化为使用 MySQL 的高效查询?还是必须逐个加载条目才能在服务器上进行比较? 翻译成这样:WHERE (LOCATE(CONVERT(LCASE(@__value_0) USING utf8mb4) COLLATE utf8mb4_bin, LCASE(b.Name)) > 0)

以上是关于实体框架核心 - 包含区分大小写还是不区分大小写?的主要内容,如果未能解决你的问题,请参考以下文章

是否有一个不区分大小写的jQuery:包含选择器?

播放框架路由不区分大小写

MySQL 查询不区分大小写的问题以及编码格式问题

使用 Spring CrudRepository 进行不区分大小写的查询

在播放框架 1.2.5 中对路由不区分大小写

区分大小写和数据库项目