.net LINQ Where忽略重音和大小写

pxyaymoc  于 2023-02-20  发布在  .NET
关注(0)|答案(7)|浏览(161)

使用LINQ通过Where方法忽略重音和大小写来过滤元素的最简单方法是什么?
到目前为止,我已经能够通过在属性上调用方法来忽略Casing,我认为这不是一个好主意,因为它对每个元素调用相同的方法(对吗?)
这是我目前得到的结果:

var result = from p in People
             where p.Name.ToUpper().Contains(filter.ToUpper())
             select p;

请告诉我这是否是一个好的做法,以及忽略重音的最简单的方法。

cdmah0mi

cdmah0mi1#

变更校对:

ALTER TABLE dbo.MyTable 
ALTER COLUMN CharCol varchar(10)**COLLATE Latin1_General_CI_AS** NOT NULL;
r7knjye2

r7knjye22#

下面是一些允许忽略重音进行比较的代码:
Ignoring accented letters in string comparison
我将有体面的不复制代码,所以作者可以得到他的答案代表。现在,回答你的问题:
你会得到这段代码并像这样使用它:

var result = from p in People
             where p.Name.ToUpper().Contains(RemoveDiacritics(filter.ToUpper()))
             select p;

你甚至把那个代码变成了一个扩展方法。我有:)

wlzqhblo

wlzqhblo3#

下面是Dunc更改整个数据库排序规则的解决方案,这里是一个完整的教程,涉及索引、键等:
https://www.codeproject.com/Articles/302405/The-Easy-way-of-changing-Collation-of-all-Database
(Just一定要先阅读所有的评论。)

l5tcr1uw

l5tcr1uw4#

如果使用链接到实体,则可以:

1.创建一个SQL函数,通过对输入字符串应用排序规则 SQL_Latin1_General_CP1253_CI_AI 来删除发音符号,例如:

CREATE FUNCTION [dbo].[RemoveDiacritics] (
@input varchar(max)
)   RETURNS varchar(max)

AS BEGIN
DECLARE @result VARCHAR(max);

select @result = @input collate SQL_Latin1_General_CP1253_CI_AI

return @result
END

2.通过将其与属性DbFunction进行Map,将其添加到DB上下文(在本例中为ApplicationDbContext)中,例如:

public class ApplicationDbContext : IdentityDbContext<CustomIdentityUser>
    {
        [DbFunction("RemoveDiacritics", "dbo")]
        public static string RemoveDiacritics(string input)
        {
            throw new NotImplementedException("This method can only be used with LINQ.");
        }

        public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options)
            : base(options)
        {
        }
}

3.在LINQ查询中使用,例如:

var query = await db.Users.Where(a => ApplicationDbContext.RemoveDiacritics(a.Name).Contains(ApplicationDbContext.RemoveDiacritics(filter))).tolListAsync();

filter 您要搜索的字符串,在本例中是DB的表Users的列名。

eeq64g8w

eeq64g8w5#

从EntityFrameworkCore5.0开始,您现在可以动态地为LinqtoSQL更改查询的排序规则。
因此,对于您的示例,如果我想忽略大小写和重音,我将执行以下操作:
(Note我们不能使用contains,但可以使用SQL的“like”运算符)

var result = from p in People
             where EF.Functions.Like(EF.Functions.Collate(p.Name, "Latin1_General_CI_AI"), $"%{filter}%")
             select p;

Latin1_General_CI_AI不区分大小写(CI)和重音(AI)
此处提供了有关EF归类和EF区分大小写的详细信息:
https://learn.microsoft.com/en-us/ef/core/miscellaneous/collations-and-case-sensitivity#explicit-collation-in-a-query

deyfvvtc

deyfvvtc6#

要忽略大小写和重音符号(变音符号),可以先定义一个扩展方法,如下所示:

public static string RemoveDiacritics(this String s)
    {
        String normalizedString = s.Normalize(NormalizationForm.FormD);
        StringBuilder stringBuilder = new StringBuilder();

        for (int i = 0; i < normalizedString.Length; i++)
        {
            Char c = normalizedString[i];
            if (CharUnicodeInfo.GetUnicodeCategory(c) != UnicodeCategory.NonSpacingMark)
                stringBuilder.Append(c);
        }

        return stringBuilder.ToString();
    }

(修改自Ignoring accented letters in string comparison
现在可以运行查询了:

string queryText = filter.ToUpper().RemoveDiacritics();

var result = from p in People
         where p.Name.ToUpper().RemoveDiacritics() == queryText
         select p;

如果你只是在C#中迭代一个集合,这是很好的,但是如果你使用LINQ to SQL,最好在你的LINQ查询中避免非标准的方法(包括扩展方法)。这是因为你的代码不能被转换成有效的SQL,因此不能在SQL Server上运行,而SQL Server具有所有可爱的性能优化。
由于在LINQ to SQL中似乎没有忽略重音的标准方法,在这种情况下,我建议将要搜索的字段类型更改为不区分大小写和重音(CI_AI)。
以你为例:

ALTER TABLE People ALTER COLUMN Name [varchar](100) COLLATE SQL_Latin1_General_CP1_CI_AI

您的查询现在应该忽略重音和大小写。
请注意,在运行上述查询 * 之前 *,您需要临时删除字段上的任何唯一约束,例如

ALTER TABLE People DROP CONSTRAINT UQ_People_Name

现在,您的LINQ查询将简单地为:

var result = from p in People
         where p.Name == filter
         select p;

参见相关问题here

qoefvg9y

qoefvg9y7#

对于重音符号,如果你不能更新你的数据库模式,也不能在RAM中获取整个列表,你可以枚举所有的重音符号(这里是法语):

var result = from p in People
             where p.Name.ToLower()
                .Replace("à", "a")
                .Replace("â", "a")
                .Replace("ä", "a")
                .Replace("ç", "c")
                .Replace("é", "e")
                .Replace("è", "e")
                .Replace("ê", "e")
                .Replace("ë", "e")
                .Replace("î", "i")
                .Replace("ï", "i")
                .Replace("ô", "o")
                .Replace("ù", "u")
                .Replace("û", "u")
                .Replace("ü", "u").Contains(RemoveDiacritics(filter.ToLower()))
             select p;

相关问题