如何使用 PredicateBuilder、EF Core 5 和 Postgresql 10+ 执行不区分大小写和重音的 LIKE子字符串查询?

问题描述

sql Server 中,使用 EF Core 5 和 PredicateBuilder 创建不区分大小写、不区分重音、LIKE查询相对简单。

例如:

  • 用户正在尝试使用标准的北美键盘数据库中查找客户(即,输入口音有点麻烦)。
  • 搜索 helene 应匹配 Mme. Hélène Laurendeau。重要的是我们可以匹配子字符串而不仅仅是前缀或后缀。

假设我们有一个具有属性 Customer 的实体 Name,以下代码段将按预期工作:

var predicate = PredicateBuilder
                 .New<Customer>(c => EF.Functions.Collate(c.Name,"latin1_general_CI_AI")
                                                 .Contains("helen"));

var customers = context.Customers.AsExpandable().Where(predicate);

我们如何在 Postgresql(10 或更高版本)中执行相同的查询

我们刚刚从 sql Server 进行了快速(基本上是 1:1)迁移,并且正在尝试更新我们的代码以确保可以进行常规迁移。这个问题没有考虑可能的查询速度问题(请参阅那里的链接了解更多信息。)

解决方法

假设您新创建的 Postgres 数据库是 UTF8(我相信这是默认设置)

  1. 确保安装了 unaccent。如果没有,CREATE EXTENSION unaccent;
  2. 按如下方式更新您的 predicate
var predicate = PredicateBuilder
                  .New<Customer>(c => EF.Functions.ILike(EF.Functions.Unaccent(c.Name),"%helen%"));

  1. 利润! :)

注意: 可以整理关于 SO 和其他来源的各种问题的答案以得出这个结论,但我一直无法找到一个有意义的地方发表评论可以轻松定位的解决方案。另外,我不认为引入全文搜索是这个问题的答案,但如果我弄错了,很乐意更新它。

This answer 是迄今为止我见过的最好、最完整的一个,强烈鼓励人们在有时间的时候深入研究它。如果您正在尝试从 SQL Server 迁移不过,以 Postgres 作为原型,这个答案应该会为您节省很多痛苦和时间 :)

有些答案建议在列的 lowercase / unaccent-ed 版本上创建索引,但这不能直接工作,因为 unaccent 不是IMMUTABLE。您可以根据需要将它们包装起来,然后将它们编入索引(链接中的示例。)

此外,尝试通过 EF.Functions 直接传递排序规则(在服务器上创建它之后)似乎也不起作用,但也许我在那里缺少 Postgres 的一些东西。

可能tweak individual column collations

一些相关问题包括:

其他来源: