Мы пытаемся реализовать оператор "LIKE" в Entity Framework для наших объектов со строковыми полями, но он, похоже, не поддерживается. Кто-нибудь еще пытался сделать что-то подобное?
Как оператор в Entity Framework?
Ответ 1
Это старый пост сейчас, но для тех, кто ищет ответ, эта ссылка должна помочь.
Укороченная версия:
Метод SqlFunctions.PatIndex - возвращает начальную позицию первого вхождения шаблона в указанном выражении или нули, если шаблон не найден, для всех допустимых типов текстовых и символьных данных
Пространство имен: System.Data.Objects.SqlClient Assembly: System.Data.Entity (в System.Data.Entity.dll)
Немного объяснения также появляется в этой теме форума.
Ответ 2
Я ничего не знаю о EF, но в LINQ to SQL вы обычно выражаете предложение LIKE с помощью String.Contains:
where entity.Name.Contains("xyz")
переводится на
WHERE Name LIKE '%xyz%'
(Используйте StartsWith
и EndsWith
для другого поведения.)
Я не совсем уверен, что это полезно, потому что я не понимаю, что вы имеете в виду, когда говорите, что пытаетесь реализовать LIKE. Если я неправильно понял, дайте мне знать, и я удалю этот ответ:)
Ответ 3
У меня была та же проблема.
В настоящее время я установил фильтрацию подстановочных знаков на стороне клиента на основе http://www.codeproject.com/Articles/11556/Converting-Wildcards-to-Regexes?msg=1423024#xx1423024xx - он прост и работает так, как ожидалось.
Я нашел еще одно обсуждение этой темы: http://forums.asp.net/t/1654093.aspx/2/10
Это сообщение выглядит многообещающим, если вы используете Entity Framework >= 4.0:
Использовать SqlFunctions.PatIndex:
http://msdn.microsoft.com/en-us/library/system.data.objects.sqlclient.sqlfunctions.patindex.aspx
Вот так:
var q = EFContext.Products.Where(x => SqlFunctions.PatIndex("%CD%BLUE%", x.ProductName) > 0);
Примечание. Это решение предназначено только для SQL-Server, поскольку оно использует нестандартную функцию PATINDEX.
Ответ 4
Обновление: в EF 6.2 есть похожий оператор
Where(i => DbFunctions.Like(searchstring ,like expression)
Ответ 5
В Entity Framework Core 2.0
добавлен оператор LIKE
:
var query = from e in _context.Employees
where EF.Functions.Like(e.Title, "%developer%")
select e;
Сравнивая с ... where e.Title.Contains("developer") ...
, он действительно переведен на SQL
LIKE
, а не CHARINDEX
, который мы видим для метода Contains
.
Ответ 6
Он специально упоминается в документации как часть 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%'
Ответ 7
Если вы используете 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 '~'
', @p__linq__0 ='% He% llo% ', @p__linq__1 ='% Hi% ', @p__linq_2 ='% Active '
Ответ 8
re: "мы хотели бы иметь возможность сопоставлять blah blah foobar foo? bar? foo * bar? и другие сложные шаблоны". Я на самом деле не пробовал это (пока не нужно), но попробовали ли вы использовать System.Text.RegularExpressions.RegEx?
Ответ 9
Вы можете использовать реальное, как в Link to Entities, довольно легко
Добавить
<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