Linq to Entities: использование ToLower() в полях NText
Я использую SQL Server 2005 с чувствительной к регистру базами данных.
В функции поиска мне нужно создать запрос Linq To Entities (L2E) с предложением "where", которое сравнивает несколько строк с данными в базе данных с этими правилами:
- Сравнение - это режим "Содержит", а не строгое сравнение: легко, поскольку метод "Содержит() разрешен в L2E
- Сравнение должно быть нечувствительным к регистру: я использую ToLower() для обоих элементов для выполнения нечувствительного сравнения.
Все это работает очень хорошо, но я столкнулся со следующим Исключением:
Msgstr "Тип аргумента ntext недействителен для аргумента 1 нижней функции" в одном из моих полей.
Кажется, что поле является полем NText, и я не могу выполнить ToLower().
Что я могу сделать, чтобы иметь возможность нечувствительности к регистру Contains() в этом поле NText?
Ответы
Ответ 1
Никогда не используйте .ToLower()
для сравнения без учета регистра. Вот почему:
- Возможно, это неверно (сопоставление ваших клиентов может быть, скажем, турецким, а не сортировкой по БД).
- Это очень неэффективно; SQL Emitted является
LOWER
вместо =
с несинхронной регистрацией.
Вместо этого используйте StringComparison.OrdinalIgnoreCase
или StringComparison.CurrentCultureIgnoreCase
:
var q = from f in Context.Foos
where f.Bar.Equals("hi", StringComparison.OrdinalIgnoreCase)
select f;
Но для Contains()
существует проблема: в отличие от Equals
, StartsWith
и т.д., она не имеет перегрузки для аргумента StringComparison
. Зачем? Хороший вопрос; спросите Microsoft.
Это в сочетании с ограничением SQL Server на LOWER
означает, что нет простого способа сделать то, что вы хотите.
Возможные обходные пути могут включать:
- Используйте полный текстовый индекс и выполните поиск в процедуре.
- Используйте
Equals
или StartsWith
вместо этого, если это возможно для вашей задачи
- Изменить сортировку по умолчанию столбца по умолчанию?
Ответ 2
Используйте здесь выражение лямбда и создайте список посредников, который может обрабатывать нижнее предложение.
var q = Context.Foos.ToList().Where(s => s.Bar.ToLower().Contains("hi"));
Не очень эффективный, но он работает. Если у вас есть дополнительные предикаты в вашем предложении where, то это работает в ваших интересах:
var q = Context.Foos.Where(p => p.f1 == "foo" && p.f2 == "bar").
ToList().Where(s => s.Bar.ToLower().Contains("hi"));
Ответ 3
как мы знаем, это очень "потрепанная" ситуация.
и это меня сильно задевает.
Сегодня я решил создать представление как:
выберите * из таблицыName
где theColumn нравится "% key%"
затем загрузите это представление в EF.
жизнь становится легкой!