Как оператор в Entity Framework?



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



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

644   9  

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

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

Where(i => DbFunctions.Like(searchstring ,like expression)

здесь 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%'

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

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

    Ничего не найдено.