Как оператор в Entity Framework?
мы пытаемся реализовать оператор "LIKE" в Entity Framework для наших сущностей со строковыми полями, но он, похоже, не поддерживается. Кто-нибудь пытался сделать что-то подобное?
этой блоге суммирует проблему, которую мы имеем. Мы могли бы использовать contains, но это соответствует только самому тривиальному случаю для LIKE. Объединение contains, startswith, endswith и indexof приводит нас туда, но требует перевода между стандартными подстановочными знаками и Linq к коду сущностей.
9 ответов:
Это старый пост сейчас, но для тех, кто ищет ответ,этой ссылке должно помочь.
короткая версия:
SqlFunctions.PatIndex метод-возвращает начальную позицию первого вхождения шаблона в указанное выражение или нули, если шаблон не найден, на всех допустимых текстовых и символьных типах данных
Пространство Имен: Системы.Данные.Объекты.Поставщики sqlclient сборочная система.Данные.Лица (в Система.Данные.Сущность.dll)
немного объяснения также появляется в этом ветке форума.
Я ничего не знаю о EF на самом деле, но в LINQ to SQL вы обычно выражаете подобное предложение с помощью строки.Содержит:
where entity.Name.Contains("xyz")переводится как
WHERE Name LIKE '%xyz%'(использовать
StartsWithиEndsWithдля других поведение.)Я не совсем уверен, что это полезно, потому что я не понимаю, что вы имеете в виду, когда говорите, что пытаетесь реализовать нравится. Если я неправильно понял полностью, дайте мне знать, и я удалю этот ответ:)
У меня была та же проблема.
на данный момент я согласился с фильтрацией подстановочных знаков/регулярных выражений на стороне клиента на основеhttp://www.codeproject.com/Articles/11556/Converting-Wildcards-to-Regexes?msg=1423024#xx1423024xx
здесь
LIKEоператор добавляется вEntity Framework Core 2.0:var query = from e in _context.Employees where EF.Functions.Like(e.Title, "%developer%") select e;по сравнению с
... where e.Title.Contains("developer") ...это действительно переводится наSQLLIKE, а неCHARINDEXвидимContainsметод.
это специально упоминается в документации как часть Entity SQL. Вы получаете сообщение об ошибке?
// LIKE and ESCAPE // If an AdventureWorksEntities.Product contained a Name // with the value 'Down_Tube', the following query would find that // value. Select value P.Name FROM AdventureWorksEntities.Product as P where P.Name LIKE 'DownA_%' ESCAPE 'A' // LIKE Select value P.Name FROM AdventureWorksEntities.Product as P where P.Name like 'BB%'
Если вы используете MS Sql, я написал 2 метода расширения для поддержки символа % для поиска подстановочных знаков. (LinqKit требуется)
public static class ExpressionExtension { public static Expression<Func<T, bool>> Like<T>(Expression<Func<T, string>> expr, string likeValue) { var paramExpr = expr.Parameters.First(); var memExpr = expr.Body; if (likeValue == null || likeValue.Contains('%') != true) { Expression<Func<string>> valExpr = () => likeValue; var eqExpr = Expression.Equal(memExpr, valExpr.Body); return Expression.Lambda<Func<T, bool>>(eqExpr, paramExpr); } if (likeValue.Replace("%", string.Empty).Length == 0) { return PredicateBuilder.True<T>(); } likeValue = Regex.Replace(likeValue, "%+", "%"); if (likeValue.Length > 2 && likeValue.Substring(1, likeValue.Length - 2).Contains('%')) { likeValue = likeValue.Replace("[", "[[]").Replace("_", "[_]"); Expression<Func<string>> valExpr = () => likeValue; var patExpr = Expression.Call(typeof(SqlFunctions).GetMethod("PatIndex", new[] { typeof(string), typeof(string) }), valExpr.Body, memExpr); var neExpr = Expression.NotEqual(patExpr, Expression.Convert(Expression.Constant(0), typeof(int?))); return Expression.Lambda<Func<T, bool>>(neExpr, paramExpr); } if (likeValue.StartsWith("%")) { if (likeValue.EndsWith("%") == true) { likeValue = likeValue.Substring(1, likeValue.Length - 2); Expression<Func<string>> valExpr = () => likeValue; var containsExpr = Expression.Call(memExpr, typeof(String).GetMethod("Contains", new[] { typeof(string) }), valExpr.Body); return Expression.Lambda<Func<T, bool>>(containsExpr, paramExpr); } else { likeValue = likeValue.Substring(1); Expression<Func<string>> valExpr = () => likeValue; var endsExpr = Expression.Call(memExpr, typeof(String).GetMethod("EndsWith", new[] { typeof(string) }), valExpr.Body); return Expression.Lambda<Func<T, bool>>(endsExpr, paramExpr); } } else { likeValue = likeValue.Remove(likeValue.Length - 1); Expression<Func<string>> valExpr = () => likeValue; var startsExpr = Expression.Call(memExpr, typeof(String).GetMethod("StartsWith", new[] { typeof(string) }), valExpr.Body); return Expression.Lambda<Func<T, bool>>(startsExpr, paramExpr); } } public static Expression<Func<T, bool>> AndLike<T>(this Expression<Func<T, bool>> predicate, Expression<Func<T, string>> expr, string likeValue) { var andPredicate = Like(expr, likeValue); if (andPredicate != null) { predicate = predicate.And(andPredicate.Expand()); } return predicate; } public static Expression<Func<T, bool>> OrLike<T>(this Expression<Func<T, bool>> predicate, Expression<Func<T, string>> expr, string likeValue) { var orPredicate = Like(expr, likeValue); if (orPredicate != null) { predicate = predicate.Or(orPredicate.Expand()); } return predicate; } }использование
var orPredicate = PredicateBuilder.False<People>(); orPredicate = orPredicate.OrLike(per => per.Name, "He%llo%"); orPredicate = orPredicate.OrLike(per => per.Name, "%Hi%"); var predicate = PredicateBuilder.True<People>(); predicate = predicate.And(orPredicate.Expand()); predicate = predicate.AndLike(per => per.Status, "%Active"); var list = dbContext.Set<People>().Where(predicate.Expand()).ToList();в ef6 и он должен перевести на
.... from People per where ( patindex(@p__linq__0, per.Name) <> 0 or per.Name like @p__linq__1 escape '~' ) and per.Status like @p__linq__2 escape '~'', @п__в LINQ__0 = '%он%привет%', @п__LINQ на__1 = '%Привет%', @п__в LINQ_2 = '%активных'
re: "мы хотели бы иметь возможность соответствовать на бла мля фубар ФОО?бар ?фу*бар? и другие сложные узоры." Я на самом деле не пробовал это (пока не нужно), но вы пробовали использовать систему.Текст.RegularExpressions.Регулярное выражение?
вы можете использовать реальный, как в ссылке на объекты довольно легко
добавить
<Function Name="String_Like" ReturnType="Edm.Boolean"> <Parameter Name="searchingIn" Type="Edm.String" /> <Parameter Name="lookingFor" Type="Edm.String" /> <DefiningExpression> searchingIn LIKE lookingFor </DefiningExpression> </Function>для вашего EDMX в этом теге:
edmx-файла:edmx в/edmx-файла:рантайм/edmx-файла:ConceptualModels/схемы
также помните, пространство имен в
<schema namespace="" />атрибутзатем добавьте класс расширения в указанное выше пространство имен:
public static class Extensions { [EdmFunction("DocTrails3.Net.Database.Models", "String_Like")] public static Boolean Like(this String searchingIn, String lookingFor) { throw new Exception("Not implemented"); } }этот метод расширения теперь будет отображаться на функцию EDMX.
подробнее здесь: http://jendaperl.blogspot.be/2011/02/like-in-linq-to-entities.html
Comments