Сравнение нечувствительных к регистру строк не работает в С#?

Основываясь на ответе на этот вопрос:

Как выполнить сравнение строк без учета регистра?

Я пытаюсь сделать сравнение без учета регистра без использования Compare или ToLower:

var user = db.Users.FirstOrDefault(s => String.Equals(s.Username, username, StringComparison.OrdinalIgnoreCase));

Однако я получаю сообщение об ошибке:

Неправильное количество аргументов, предоставленных для вызова метода 'Boolean Equals (System.String, System.String, System.StringComparison) '

Что я делаю неправильно?

Ответы

Ответ 1

Сравнение строк с StringComparison.OrdinalIgnoreCase работает в памяти или с IEnumerable<T>. Вы пытаетесь использовать его с IQueryable<T>, но поставщик вашего запроса не понимает его.

В Linq-to-Sql вы можете использовать SqlMethods.Like(s.UserName, userName), например:

var user = db.Users.FirstOrDefault(s => SqlMethods.Like(s.UserName, userName));

SqlMethods находится в пространстве имен System.Data.Linq.SqlClient.

Метод Like нечувствителен к регистру, поэтому вы должны получить ожидаемый результат.

EDIT: Я попытался и получил "LINQ to Entities не распознает метод Boolean Like(System.String, System.String), и этот метод не может быть переведен в выражение хранилища".

Это, по-видимому, известная проблема с EF (ссылка).

Это работает для меня:

db.Users.FirstOrDefault(
     s => s.Username.Equals(username, StringComparison.OrdinalIgnoreCase)
);

Похоже, что хотя EF затрудняет перевод статического Equals в SQL, у него нет проблем с переводом экземпляра Equals. Это очень хорошая находка - это упрощает чтение и исполнение.

Вы также можете использовать более простой метод с ToUpperCase или ToLowerCase, но это может помешать оптимизаторам запросов использовать индексы:

// Warning: this may not perform well.
var user = db.Users.FirstOrDefault(s => s.UserName.ToUpperCase() == userName.ToUpperCase());