LINQ без акцента и регистра

Как проще всего фильтровать элементы с помощью LINQ с помощью метода Where, игнорируя акцентные знаки и регистр?

До сих пор мне удавалось игнорировать регистр, вызывая методы для свойств, что я не думаю, что это хорошая идея, потому что он вызывает один и тот же метод для каждого элемента (верно?).

Итак, вот что у меня получилось:

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

Скажите, пожалуйста, это хорошая практика и самый простой способ игнорировать акцентуацию.


person Smur    schedule 14.09.2011    source источник


Ответы (5)


Чтобы игнорировать регистр и диакритические знаки (диакритические знаки), вы можете сначала определить такой метод расширения:

    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();
    }

(Изменено из Игнорирование букв с диакритическими знаками при сравнении строк)

Теперь вы можете запустить свой запрос:

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;

См. Соответствующий вопрос здесь.

person Dunc    schedule 16.11.2011
comment
Потрясающий. Не возражаете, если я напишу об этом в блоге? - person Smur; 16.11.2011
comment
Отличный ответ. Вы на самом деле ответили на вопрос, прежде чем сказать, что настоящее решение, вероятно, - это другой подход. Слишком многие делают только последнее. - person Niels Brinch; 30.05.2012
comment
Помните, что изменение сортировки столбца должно выполняться осторожно. Это могло вызвать несоответствие параметров сортировки и изменить семантику других запросов. - person Frédéric; 30.08.2013

Изменить подборку:

ALTER TABLE dbo.MyTable 
ALTER COLUMN CharCol varchar(10)**COLLATE Latin1_General_CI_AS** NOT NULL;
person Javier Jimenez Matilla    schedule 19.12.2014

Что касается акцентов, вы можете перечислить их все (здесь для французского языка), если вы не можете обновить схему базы данных или получить весь список в ОЗУ:

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;
person Guillaume Blanchet    schedule 16.09.2019

Вот код, который позволяет сравнивать без акцента:

Игнорирование букв с диакритическими знаками при сравнении строк

Я буду иметь порядочность не копировать код, чтобы автор мог получить репутацию за свой ответ. Теперь, отвечая на ваш вопрос:

Вы получите этот фрагмент кода и будете использовать его так:

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

Вы даже превращаете этот код в метод расширения. У меня есть :)

person Adriano Carneiro    schedule 14.09.2011
comment
Как это убирает акценты со значения на стороне SQL? Как есть, не будет ли он сравнивать только значение SQL в верхнем регистре с неакцентированным (в верхнем регистре) значением C #? - person Kirk Woll; 14.09.2011
comment
@Kirk - Вы правы, но я не уверен, что это возможно на стороне SQL. Я собирался опубликовать то же самое решение. - person Justin Morgan; 14.09.2011
comment
@Adrian Метод, который вы мне показали, действительно удаляет акцентуацию, но я не могу вызвать его на стороне SQL, потому что LINQ не находит перевод в БД, как указали Кирк и Джастин. Не могли бы вы, ребята, сказать, что есть способ заставить его работать, не касаясь базы данных? - person Smur; 14.09.2011
comment
@Felipe, я почти уверен, что это невозможно с прямым Linq-To-Sql. Однако вы можете написать хранимую процедуру (или TVF), которая объединяет предложения по сопоставлению, описанные в другом месте. Затем вы можете добавить вызов метода для этого SP в тексте данных. - person Kirk Woll; 15.09.2011
comment
@Kirk Я вижу, тогда мне пришлось бы создать для этого «метод» прямо в моей базе данных SQL Server. Кажется, довольно просто. - person Smur; 16.09.2011
comment
Очевидно, это не будет работать с LINQ-to-Sql или LINQ-to-Entities. - person QuantumHive; 15.11.2016

Следуя решению Дунк по изменению сопоставления всей базы данных, вот полное руководство, посвященное индексам, ключам и т. Д .:

https://www.codeproject.com/Articles/302405/The-Easy-way-of-changing-Collation-of-all-Database

(Просто не забудьте сначала прочитать все комментарии.)

person LePatay    schedule 14.03.2018
comment
Поскольку это не новый ответ, а скорее обновление уже принятого ответа, считаете ли вы, что его нужно опубликовать в качестве ответа? ИМО, комментарий будет уместнее. - person Eduard Malakhov; 14.03.2018
comment
У меня репутация ниже 50, я не могу комментировать сообщения других пользователей! Иначе было бы с удовольствием :) - person LePatay; 14.03.2018