编写一个在 EF Core 中不区分大小写的搜索查询?

Sam*_* Öz 5 c# sql-server case-insensitive entity-framework-core .net-core

我想问一个关于 SQL Server 和 EF Core 的问题。数据库中的排序规则是Latin1_CI_AS,我想编写一个包含土耳其语字符的搜索查询。

在数据库中,'personnel'表中有一个名为“SEL?M”的记录。当我在 EF Core 中编写这样的查询时:

    public async Task<IList<PersonnelGetDto>> Get(PersonnelGetPayload payload)
        {
           if (payload.Name != null)
                query = query.Where(x => x.Name.Contains(payload.Name)); 
        }
Run Code Online (Sandbox Code Playgroud)

如果我的搜索条件是“selim”,则列表为空。

我没有机会将数据库中的排序规则更改为土耳其语,因为我们的应用程序是多语言的。我认为其他语言会有问题。还是我错了?

我还写了字符串扩展名。但是,当将 LINQ 查询转换为 SQL 时,所有记录都会进入服务层,因为 LIKE 运算符未分配 WHERE 子句。在sql端运行这个条件非常重要。如果我把所有的数据集都拿到服务层去查询,会花费我很多。

当我在数据库中键入查询时,我可以解决这个问题:

SELECT * FROM Personnel WHERE Name LIKE 'selim' COLLATE Turkish_CI_AS
Run Code Online (Sandbox Code Playgroud)

我想如果我可以在 EF Core 上操作整理,我会解决这个问题。

Tie*_* T. 5

您正在寻找EF.Functions.Like,它需要添加using Microsoft.EntityFrameworkCore;(如果您还没有添加的话)。然后,您的查询将类似于:

query.Where(x => EF.Functions.Like(x.Name, $"%{payload.Name}%"))
Run Code Online (Sandbox Code Playgroud)

这会直接转换为LIKE生成的 SQL 语句中的运算符。它并不适用于每个 DBMS,但只要您添加了Microsoft.EntityFrameworkCore.SqlServer,您就可以使用(假设您的问题已正确标记)。

  • 让我为此添加另一个方面,让我们还为该列添加排序规则: `query.Where(x =&gt; EF.Functions.Like(EF.Functions.Collat​​e(x.Name,"Turkish_CI_AS"), $"%{payload .名称}%"))` (2认同)

Eld*_*dar 3

我已经测试了类似的功能,但结果并不如操作所述正确。所以只剩下一个选择了。即创建拦截器并实现自定义逻辑。我创建了一个如下示例:

\n\n
   public class Suffixes\n    {\n        public const string Collate = "--Collate";\n    }\n\n    public class CollationDbCommandInterceptor : DbCommandInterceptor\n    {\n        private const string CollateSyntax = " collate turkish_ci_as";\n\n        public override InterceptionResult<DbDataReader> ReaderExecuting(DbCommand command, CommandEventData eventData, InterceptionResult<DbDataReader> result)\n        {\n            var args = command.Parameters.OfType<DbParameter>()\n                           .Where(t => t.DbType == DbType.String && t.Value.ToString().EndsWith(Suffixes.Collate)).ToList();\n            if (args.Count <= 0)\n                return base.ReaderExecuting(command, eventData, result);\n\n            foreach (var parameter in args)\n            {\n                parameter.Value = parameter.Value.ToString().Replace(Suffixes.Collate, "");\n                var equality = $"= {parameter.ParameterName}";\n\n                var ixs = AllIndexesOf(command.CommandText, equality);\n\n#pragma warning disable CA2100 // Review SQL queries for security vulnerabilities\n                foreach (var eq in ixs)\n                {\n                    command.CommandText = command.CommandText.Insert(eq+equality.Length,CollateSyntax);\n\n                }\n#pragma warning restore CA2100 // Review SQL queries for security vulnerabilities\n\n            }\n\n\n\n            return base.ReaderExecuting(command, eventData, result);\n        }\n\n        private static IEnumerable<int> AllIndexesOf(string str, string value)\n        {\n            if (string.IsNullOrEmpty(value))\n                throw new ArgumentException("the string to find may not be empty", nameof(value));\n            var indexes = new List<int>();\n            for (var index = 0; ; index += value.Length)\n            {\n                index = str.IndexOf(value, index);\n                if (index == -1)\n                    return indexes;\n                indexes.Insert(0,index);\n            }\n        }\n    }\n
Run Code Online (Sandbox Code Playgroud)\n\n

配置 :

\n\n
protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)\n        {\n            if (!optionsBuilder.IsConfigured)\n            {\n               ....  \n                optionsBuilder.AddInterceptors(new CollationDbCommandInterceptor());\n                ....\n            }\n        }\n
Run Code Online (Sandbox Code Playgroud)\n\n

用法 :

\n\n
var kadayif = $"kaday\xc4\xb1f{Suffixes.Collate}";\nvar william = $"W\xc4\xb0lliam{Suffixes.Collate}";            \nvar auths = ctx.Authors.Where(t =>   t.FirstName == william ||t.LastName == kadayif).ToList(); \n// returns William Shakespeare and Abuzer Kaday\xc4\xb1f\n
Run Code Online (Sandbox Code Playgroud)\n\n

逻辑是创建一个拦截器,在查询中传递的 sql 参数中寻找特定后缀。将查询特定排序规则注入到最终的 sql 命令文本中。我尝试涵盖一些高级场景,例如参数重用。它可能需要更多改进。

\n\n

请注意,此示例适用于 Entity Framework Core 3.0,这是拦截器引入的版本。早期 ef core 版本中的拦截是有一点技巧的。您可以参考链接以获取更多信息。

\n