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

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

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

 CodeNotFound14 июн. 2018 г., 10:41
Идти кthis answer  если вы уже используете EF 6.2.x. кthis answer если вы используете EF Core 2.x

Ответы на вопрос(9)

Решение Вопроса

эта ссылка должно помочь Идти кэтот ответ если вы уже используете EF 6.2.x. кэтот ответ если вы используете EF Core 2.x

Укороченная версия:

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

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

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

 17 окт. 2012 г., 15:27
как принятый ответ тот, который ссылается на форум MSDN, который ссылается на этот вопросanswer below?
 05 авг. 2016 г., 17:46
Dup этого старшеanswer на этот вопрос. (Не своей первой части, а альтернативного решения.)
 24 нояб. 2014 г., 22:18
Приведенный ниже ответ хорош для простых шаблонов, но если я хочу сказать «ГДЕ ИМЯ НРАВИТСЯ» abc [0-9]% »& quot; или какой-либо другой более сложный шаблон, просто использование Contains () не совсем его обрезает.
 17 мая 2014 г., 02:20
Ответ заключался в использовании метода SqlFunctions.PatIndex. Связанная ветка форума должна была предоставить немного больше «фона» Информация.

"мы" хотели бы иметь возможность совпадать на блаblah foobar foo? bar? foo * bar? и другие сложные шаблоны. & quot; Я на самом деле не пробовал это (пока не нужно), но пытались ли вы использовать System.Text.RegularExpssions.RegEx?

 brien22 июл. 2009 г., 13:16
Регулярное выражение будет выполняться на веб-сервере, а не в БД. По сути, для этого потребуется вернуть всю таблицу из SQL Server, а затем выполнить фильтрацию. Это будет работать для некоторых небольших случаев, но нам нужно искать большие (ish) объемы данных. Хорошее предложение, тем не менее, это была моя первая мысль тоже.

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") ... это действительно переводится наSQL LIKE скорее, чемCHARINDEX мы видим дляContains метод.

На данный момент я согласился с фильтрацией 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 & gt; = 4.0:

Use SqlFunctions.PatIndex:

http://msdn.microsoft.com/en-us/library/system.data.objects.sqlclient.sqlfunctions.patindex.aspx

Like this:

var q = EFContext.Products.Where(x =>
SqlFunctions.PatIndex("%CD%BLUE%", x.ProductName) > 0);

Note: this solution is for SQL-Server only, because it uses non-standard PATINDEX function.

 29 мар. 2012 г., 16:11
работал удовольствие, спасибо за это!
 22 янв. 2014 г., 22:39
Хотя PatIndex & quot; работает & quot ;, он вернется, чтобы укусить вас, PatIndex в предложении where не использует индексы для столбца, по которому вы хотите фильтровать.
 23 янв. 2014 г., 08:46
@ BlackICE это ожидается. При поиске по внутреннему тексту (% CD% BLUE%) сервер не сможет использовать индексы. По возможности, поиск текста с самого начала (CD% BLUE%) более эффективен.
 23 янв. 2014 г., 14:34
@surfen patindex хуже, чем этот, хотя он не будет использовать индекс даже без% впереди, поиск (СИНИЙ CD%) с patindex не будет использовать индекс столбцов.

учаете сообщение об ошибке?

// 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

 brien23 июн. 2009 г., 17:02
Это хорошо компилируется, но не работает во время выполнения.
 23 июн. 2009 г., 17:13
Сообщение об ошибке?..
 brien23 июн. 2009 г., 17:19
Я отредактировал вопрос со ссылкой на сообщение в блоге, описывающее ту же проблему, что и у нас.
 23 июн. 2009 г., 17:01
Я бы хотел остаться в стороне от Entity SQL на случай, если в будущем вы захотите отойти от EF. Будьте осторожны и придерживайтесь опций Contains (), StartsWith () и EndsWith () в исходном ответе.
 23 июн. 2009 г., 17:12
Код, который я разместил, не работает во время выполнения? Это происходит по ссылке Microsoft.

добавлять

    <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:Runtime/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

я написал 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 ".

 24 окт. 2016 г., 08:20
у меня есть ошибка в PredicateBuilder
 24 окт. 2016 г., 10:04
спасибо за ваш комментарий Ронель, я могу чем-нибудь помочь? что такое сообщение об ошибке?

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

но в LINQ to SQL вы обычно выражаете предложение LIKE, используя String.Contains:

where entity.Name.Contains("xyz")

переводит на

WHERE Name LIKE '%xyz%'

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

Я не совсем уверен, полезно ли это, потому что я не понимаю, что вы имеете в виду, когда говорите, что пытаетесьimplement ЛАЙК. Если я полностью не понял, дайте мне знать, и я удалю этот ответ :)

 brien23 июн. 2009 г., 16:50
Ну, мы хотели бы иметь возможность соответствоватьblah *blah Foobar foo?bar ?fooбар? и другие сложные модели. Наш нынешний подход аналогичен тому, что вы упомянули, мы конвертировали бы эти запросы в операции, используя has, indexof, начальные с, концевые и т. Д. Я просто надеялся, что найдется более универсальное решение.
 23 июн. 2009 г., 16:49
обратите внимание, что "WHERE Name LIKE"% xyz% "" не сможет использовать индекс, поэтому, если таблица огромна, она может работать не так хорошо ...
 23 июн. 2009 г., 18:02
@Jon Skeet: насколько мне известно, функциональность LIKE соответствует стандарту ANSI и почти одинакова в SQL Server, Oracle и DB2.
 17 авг. 2012 г., 19:58
Одна вещь, которую я видел при использовании этих операторов и MS SQL, состоит в том, что EF добавляет их в качестве экранированных параметров «Имя LIKE @ p__linq__1 ESCAPE N» «~». который в моем очень ограниченном сценарии использования работает намного медленнее, чем если строка поиска находится просто в запросе «Имя как»% xyz% ». Для сценариев, которые у меня есть, я все еще использую StartsWith и Contains, но я делаю это с помощью динамического linq, потому что это вводит параметр в оператор SQL, который в моем сценарии создает более эффективный запрос. Не уверен, что это EF 4.0 или нет. Вы также можете использовать ObjectQueryParameters для достижения того же самого ...
 23 июн. 2009 г., 16:52
Не то, чтобы я знал - я подозреваю, что сложные шаблоны в конечном итоге становятся более специфичными для БД и их трудно выразить в общем виде.

Ваш ответ на вопрос