Я следую советам здесь, пытаясь усилить оператор, что sql не становится созданным, пока перечислитель не смещен. Однако я получаю следующую ошибку на коде ниже. Я использую Linq2Entities, не linq2sql. Существует ли способ сделать это в Linq2entities?
Метод 'булевская переменная Как (Система. Строка, Система. Строка)', не может использоваться на клиенте; это только для перевода в SQL.
query = db.MyTables.Where(x => astringvar.Contains(x.Field1));
if (!String.IsNullOrEmpty(typeFilter))
{
if (typeFilter.Contains('*'))
{
typeFilter = typeFilter.Replace('*', '%');
query = query.Where(x=> SqlMethods.Like(x.Type, typeFilter));
}
else
{
query = query.Where(x => x.Type == typeFilter);
}
}
Примечания: дб является объектом, отображающимся на SQL-сервер.
Я не знаю, как можно заставить Entity Framework использовать "настоящий" оператор LIKE, но возможным обходным путем было бы выразить выражение LIKE в терминах of StartsWith
, Contains
and EndsWith
Например:
LIKE 'a%' => StartsWith("a")
LIKE '%a' => EndsWith("a")
LIKE '%a%' => Contains("a")
LIKE 'a%b' => StartsWith("a") && EndsWith("b")
LIKE 'a%b%' => StartsWith("a") && Contains("b")
И так далее ...
Обратите внимание, что это не совсем эквивалентно использованию LIKE в SQL: например, LIKE '% abc% bcd%'
приведет к Contains ("abc") && Contains ("bcd")
. Это будет соответствовать "abcd", даже если исходное условие LIKE не совпадет. Но в большинстве случаев этого должно быть достаточно.
Вот пример реализации с использованием PredicateBuilder
и LinqKit для построения выражений на основе шаблона LIKE:
public static class ExpressionHelper
{
public static Expression<Func<T, bool>> StringLike<T>(Expression<Func<T, string>> selector, string pattern)
{
var predicate = PredicateBuilder.True<T>();
var parts = pattern.Split('%');
if (parts.Length == 1) // not '%' sign
{
predicate = predicate.And(s => selector.Compile()(s) == pattern);
}
else
{
for (int i = 0; i < parts.Length; i++)
{
string p = parts[i];
if (p.Length > 0)
{
if (i == 0)
{
predicate = predicate.And(s => selector.Compile()(s).StartsWith(p));
}
else if (i == parts.Length - 1)
{
predicate = predicate.And(s => selector.Compile()(s).EndsWith(p));
}
else
{
predicate = predicate.And(s => selector.Compile()(s).Contains(p));
}
}
}
}
return predicate;
}
}
И вот как вы могли бы его использовать:
var expr = ExpressionHelper.StringLike<YourClass>(x => x.Type, typeFilter);
query = query.AsExpandable().Where(expr.Compile());
Я только что попробовал это с простой моделью EF, и, похоже, она работает нормально :)
Класс SqlMethods
предназначен для использования с LINQ-to-SQL. Когда вы используете из него методы (которые в общедоступной документации не рекомендуется делать, это не для общего пользования), поставщик IQueryable
для LINQ-to-Entities не знает, что с ним делать и как перевести это.
Если у вас есть один подстановочный знак в начале или конце фильтра, вы можете использовать методы StartsWith
или EndsWith
в классе String
и LINQ-to-Entities будет поддерживать это.
Однако в этом случае у вас есть переменное количество подстановочных знаков, поэтому вам придется спуститься до уровня ESQL и построить запрос на его основе, как указано в ответе Nix .
Вы можете выполнить ESQL и сделать что-то вроде следующего ..
db.MyTables.Where("it.Type like '" + typeFilter + "'").ToList();