LINQ не может использовать string.contains?

Это мой код:

string queryString = "Marco".ToLower();
utenti = db.User.Where(p => 
        queryString.Contains(p.Nickname.ToLower()) ||
            queryString.Contains(p.Nome.ToLower()) ||
            queryString.Contains(p.Cognome.ToLower())).ToList();

но я получаю:

Поддерживаются только аргументы, которые могут быть оценены клиентом для метода String.Contains.

Почему? Не могу ли я использовать .Contains()?

Ответ 1

Попробуйте .IndexOf. Это не LINQ, который не может выполнить Contains, это LINQ to Entities и LINQ to SQL, который не может.

string queryString = "Marco";
utenti = db.User.Where(p => 
    queryString.IndexOf(p.Nickname, StringComparison.OrdinalIgnoreCase) >= 0 ||
        queryString.IndexOf(p.Nome, StringComparison.OrdinalIgnoreCase) >= 0 ||
        queryString.IndexOf(p.Cognom, StringComparison.OrdinalIgnoreCasee) >= 0)
.ToList();

Почему?

LINQ использует отсроченное исполнение. Это означает, что он ждет, пока вы не захотите повторить результаты запроса до того, как он что-нибудь сделает. Существует 3 основных типа LINQ:

  • LINQ to Objects - когда ваш IEnumerable уже находится в куче.
  • LINQ to Entities - когда вы хотите запросить базу данных с помощью Entity Framework.
  • LINQ to SQL - при запросе базы данных с использованием LINQ to SQL.

Отсроченное исполнение в контексте второго 2 означает, что ваш запрос не выполняется в базе данных до тех пор, пока вы не перечислите результаты в блоке foreach или не вызовите метод перечисления, такой как .ToList, .ToArray и т.д. До тех пор ваш запрос просто хранится в виде деревьев выражений в памяти.

Ваш запрос будет работать просто peachy, если db.User был коллекцией в памяти. Однако, когда данные находятся в базе данных, LINQ to Entities (или LINQ to SQL) должны преобразовывать деревья выражений в то, что он вызывает "выражение хранилища" - это просто причудливый разговор для "конвертировать мои выражения LINQ в SQL".

Теперь представьте, что у вас был пользовательский алгоритм С#, который вы хотели использовать для своего запроса, и вы сделали что-то вроде этого:

var result = db.User.Where(x => MyCustomMethod(x));

Сегодня нет возможности LINQ to Entities преобразовать ваш код С# в запрос SQL (выражение хранилища). То же самое происходит с множеством других методов С#, на которые вы полагаетесь ежедневно. Он также не поддерживает .ToLower, .ToUpper, .StartsWith, .EndsWith и т.д. Существует ограниченное количество методов С#, которые могут быть преобразованы для хранения выражений, а .IndexOf просто является одним из них.

Однако имейте в виду, что речь идет только о методе строкового объекта Contains, который не поддерживается для выражений store. LINQ to Entities поддерживает .Contains на IEnumerable s. Следующие действия действительны и будут работать с LINQ to Entities (не уверены в LINQ to SQL):

var idsIWantToFind = new[] { 1, 2, 3 };
var users = db.Where(x => idsIWantToFind.Contains(x.UserId));

Вышеупомянутый эквивалент выполнения предиката SQL WHERE UserId IN (1, 2, 3).

Ответ 2

проблема - приоритет входов. например:

a.Contains(б); или b.Содержание (a);

лучше писать:

p.Nickname.Contains(queryString) ...

вместо

queryString.Contains(p.Nickname) ...