忽略重音和大小写的 LINQ
Posted
技术标签:
【中文标题】忽略重音和大小写的 LINQ【英文标题】:LINQ Where Ignore Accentuation and Case 【发布时间】:2011-11-17 03:09:50 【问题描述】:通过Where
方法忽略重读和大小写,使用 LINQ 过滤元素的最简单方法是什么?
到目前为止,我已经能够通过调用属性上的方法来忽略大小写,我认为这不是一个好主意,因为它为每个元素调用相同的方法(对吗?)。
这就是我目前得到的:
var result = from p in People
where p.Name.ToUpper().Contains(filter.ToUpper())
select p;
请告诉我这是否是一种好习惯,以及忽略重音的最简单方法。
【问题讨论】:
【参考方案1】:要忽略大小写和重音符号(变音符号),您可以首先定义一个扩展方法,如下所示:
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 上运行,并进行了所有可爱的性能优化。
由于在 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。
【讨论】:
太棒了。介意我写博客吗? 很好的答案。在告诉真正的解决方案可能是另一种方法之前,您实际上已经回答了这个问题。太多人只做后者。 当心,更改列的排序规则时应该小心。它可能导致排序规则不匹配,并可能改变其他查询的语义。【参考方案2】:更改整理:
ALTER TABLE dbo.MyTable
ALTER COLUMN CharCol varchar(10)**COLLATE Latin1_General_CI_AS** NOT NULL;
【讨论】:
【参考方案3】:对于重音符号,如果您无法更新数据库架构或获取 RAM 中的整个列表,则可以枚举所有重音符号(此处为法语):
var result = from p in People
where p.Name.ToUpper()
.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.ToUpper()))
select p;
【讨论】:
【参考方案4】:下面是一些允许比较忽略重音的代码:
Ignoring accented letters in string comparison
我将有礼貌地不复制代码,以便作者可以得到代表他的答案。现在,回答你的问题:
你会得到那段代码并像这样使用它:
var result = from p in People
where p.Name.ToUpper().Contains(RemoveDiacritics(filter.ToUpper()))
select p;
您甚至可以将该代码转换为扩展方法。我有:)
【讨论】:
如何从 SQL 端的值中删除重音符号?照原样,它不会只将大写 SQL 值与非重音(大写)C# 值进行比较吗? @Kirk - 你是对的,但我不确定是否可以在 SQL 端做到这一点。我正要发布同样的解决方案。 @Adrian 您向我展示的方法确实消除了重音,但我不能在 SQL 端调用它,因为 LINQ 没有找到对 DB 的翻译,正如 Kirk 和 Justin 所指出的那样。你们会说有一种方法可以让它在不接触数据库的情况下工作吗? @Felipe,我很确定这对于直接的 Linq-To-Sql 是不可能的。但是,您可以编写一个集成了collating suggestions described elsewhere 的存储过程(或TVF)。然后你可以add a method call to this SP in your datacontext。 @Kirk 我明白了,然后我必须直接在我的 SQL Server 数据库上为此创建一个“方法”。看起来很简单。【参考方案5】:按照 Dunc 更改整个数据库的排序规则的解决方案,这里有一个处理索引、键等的完整教程:
https://www.codeproject.com/Articles/302405/The-Easy-way-of-changing-Collation-of-all-Database
(请务必先阅读所有 cmets。)
【讨论】:
由于这不是一个新答案,而是对已经接受的答案的更新,您认为它需要作为答案发布吗? IMO,评论会更合适。 我的声望低于50,我不能评论其他用户的帖子!否则我会很高兴:)【参考方案6】:如果您使用 Linq-to-Entities,您可以:
1.通过将排序规则 SQL_Latin1_General_CP1253_CI_AI 应用于输入字符串,创建一个 SQL 函数以删除变音符号,例如:
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 进行映射,将其添加到 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();
正在过滤您要搜索的字符串,在这种情况下,在数据库的用户表的列名中。
【讨论】:
【参考方案7】:从 Entity Framework Core 5.0 开始,您现在可以动态更改 Linq to SQL 的查询排序规则。
因此,对于您的示例,如果我想忽略 大小写和重音符号,我会执行以下操作:
(请注意,我们不能使用包含,但我们可以使用 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://docs.microsoft.com/en-us/ef/core/miscellaneous/collations-and-case-sensitivity#explicit-collation-in-a-query
【讨论】:
以上是关于忽略重音和大小写的 LINQ的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 PredicateBuilder、EF Core 5 和 Postgresql 10+ 执行不区分大小写和重音的 LIKE(子字符串)查询?
unicode排序规则,汉字怎么区分大小写,区分重音,区分假名,区分宽度
SQL Server CE 4 Entity Framework 4.3.1 Code First 不区分重音和不区分大小写的搜索