Как оператор в Entity Framework? - PullRequest
81 голосов
/ 23 июня 2009

Мы пытаемся реализовать оператор "LIKE" в Entity Framework для наших сущностей со строковыми полями, но он не поддерживается. Кто-нибудь еще пытался сделать что-то подобное?

В этом сообщении в блоге кратко изложена проблема, с которой мы столкнулись. Мы могли бы использовать содержит, но это соответствует только тривиальному случаю для LIKE. Объединение содержит, начинается с, заканчивается с, и indexof приводит нас туда, но требует перевода между стандартными подстановочными знаками и кодом Linq to Entities.

Ответы [ 9 ]

146 голосов
/ 23 июня 2009

Я ничего не знаю об EF, но в LINQ to SQL вы обычно выражаете предложение LIKE с помощью String.Contains:

where entity.Name.Contains("xyz")

переводится как

WHERE Name LIKE '%xyz%'

(используйте StartsWith и EndsWith для другого поведения.)

Я не совсем уверен, полезно ли это, потому что я не понимаю, что вы имеете в виду, когда говорите, что пытаетесь реализовать НРАВИТСЯ. Если я неправильно понял, дайте мне знать, и я удалю этот ответ:)

33 голосов
/ 03 февраля 2012

У меня была такая же проблема.

На данный момент я согласился с фильтрацией Wildcard / Regex на стороне клиента на основе 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-сервера, поскольку оно использует нестандартную функцию PATINDEX.

29 голосов
/ 07 июля 2012

Это старая публикация, но для тех, кто ищет ответ, эта ссылка должна помочь. Перейдите на этот ответ , если вы уже используете EF 6.2.x. На этот ответ , если вы используете EF Core 2.x

Короткая версия:

SqlFunctions.PatIndex метод - возвращает начальную позицию первого вхождения шаблона в указанном выражении или нули, если шаблон не найден, во всех допустимых типах данных текста и символов

Пространство имен: System.Data.Objects.SqlClient Сборка: System.Data.Entity (в System.Data.Entity.dll)

Небольшое объяснение также появляется в этой ветке форума .

15 голосов
/ 22 ноября 2017

Обновление: в EF 6.2 есть оператор like

Where(i => DbFunctions.Like(searchstring ,like expression)
10 голосов
/ 29 сентября 2017

В 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 метода.

5 голосов
/ 23 июня 2009

Это специально упоминается в документации как часть 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%'

http://msdn.microsoft.com/en-us/library/bb399359.aspx

2 голосов
/ 23 августа 2014

если вы используете 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 '

0 голосов
/ 15 июля 2015

Вы можете очень легко использовать реальный лайк в 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

Также запомните пространство имен в атрибуте <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

0 голосов
/ 22 июля 2009

re: «мы хотели бы иметь возможность совпадать на бла бла-фу bar foo? Bar? Foo * bar? И других сложных шаблонах». Я на самом деле не пробовал это (пока не нужно), но вы пытались использовать System.Text.RegularExpressions.RegEx?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...