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.

жизнь становится легкой!