Подтвердить что ты не робот

Как использовать SQL 'LIKE' с LINQ to Entities?

У меня есть текстовое поле, которое позволяет пользователю указать строку поиска, включая wild cards, например:

Joh*
*Johnson
*mit*
*ack*on

Прежде чем использовать LINQ to Entities, у меня была хранимая процедура, которая взяла эту строку в качестве параметра и сделала:

SELECT * FROM Table WHERE Name LIKE @searchTerm

И тогда я просто сделаю String.Replace('*', '%'), прежде чем передать его.

Теперь с LINQ to Entities я пытаюсь выполнить одно и то же. Я знаю, что есть StartsWith, EndsWith и Содержит поддержку, но она не будет поддерживать ее так, как мне нужно.

Я читал о "SqlMethods.Like" и пробовал это:

var people = from t in entities.People
             where SqlMethods.Like(t.Name, searchTerm)
             select new { t.Name };

Однако я получаю следующее исключение:

LINQ to Entities does not recognize the method 'Boolean Like(System.String, 
System.String)' method, and this method cannot be translated into a store 
expression.

Как получить эту же функциональность с помощью LINQ to Entities?

4b9b3361

Ответ 2

Как заставить его работать без проблем:

в вашей модели EDMX, добавьте:

    <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:ConceptualModels> <Schema Namespace="Your.Namespace"...

Затем в любом месте вашего кода добавьте этот метод расширения:

    //prior to EF 6 [System.Data.Objects.DataClasses.EdmFunction("Your.Namespace", "String_Like")]

    //With EF 6
    [System.Data.Entity.DbFunction("Your.Namespace", "String_Like")]
    public static bool Like(this string input, string pattern)
    {
        /* Turn "off" all regular expression related syntax in
         * the pattern string. */
        pattern = Regex.Escape(pattern);

        /* Replace the SQL LIKE wildcard metacharacters with the
         * equivalent regular expression metacharacters. */
        pattern = pattern.Replace("%", ".*?").Replace("_", ".");

        /* The previous call to Regex.Escape actually turned off
         * too many metacharacters, i.e. those which are recognized by
         * both the regular expression engine and the SQL LIKE
         * statement ([...] and [^...]). Those metacharacters have
         * to be manually unescaped here. */
        pattern = pattern.Replace(@"\[", "[").Replace(@"\]", "]").Replace(@"\^", "^");

        return Regex.IsMatch(input, pattern, RegexOptions.IgnoreCase);
    }

И там у вас есть.

Теперь вы можете сделать:

(from e in Entities
 where e.Name like '%dfghj%'
 select e)

или

string [] test = {"Sydney", "Melbourne", "adelaide", "ryde"};

test.Where(t=> t.Like("%yd%e%")).Dump();

Ответ 3

Ну, ваши варианты:

  • Используйте Contains. Я знаю, что вам это не нравится, но, возможно, это может быть сделано для работы.
  • Выберите функцию из SqlFunctions. Все они поддерживаются в L2E.
  • Создайте собственную функцию.
  • +1 для @Yury для ESQL.

Ответ 4

Вы можете сделать это:

using System.Data.Entity;  // EntityFramework.dll v4.3
var queryResult=db.Accounts.AsQueryable().Where(x => x.Name.Contains(queryKey));

потому что Linq to Entity не может преобразовать метод Contains() в SQL, но Linq to SQL может это сделать. Я попытался найти метод, который может сделать приведение, наконец, AsQueryable(), а также общую версию AsQueryable<T>(). Я обнаружил, что могу сделать это, используя его таким образом в моем случае, но любой побочный эффект, который у меня есть, я не знаю, возможно, он потеряет некоторые функции в Entity.

Ответ 5

решение заключается в использовании SQLFunctions.PatIndex

var result = from c in items
             where SqlFunctions.PatIndex(searchstring.ToLower(), c.fieldtoSearch) > 0
             select c;

где 'searchstring' - это шаблон для поиска     'fieldtoSearch' - это поле для поиска

Patindex() поддерживает поиск с использованием поиска по строкам. Поиск нечувствителен к регистру.

Ответ 6

var people = from t in entities.People
                 where t.Name.ToLower().Contains(searchTerm.ToLower())
                 select new { t.Name };

EDIT. Я могу смешивать синтаксис. Обычно я использую методы расширения; но содержит будет работать.

Ответ 7

Вы даже можете добавить поддержку метода .Like() в LINQ to Entities, чтобы вместо предлагаемого (и рабочего)

var people = entities.People.Where("it.Name LIKE @searchTerm", new ObjectParameter("searchTerm", searchTerm));

просто

var people = entities.People.Where(p => p.Name.Like(searchTerm));

См. http://jendaperl.blogspot.com/2011/02/like-in-linq-to-entities.html

Ответ 8

Вы можете делать все эти операторы с помощью LINQ как

string _search = "blow";
// joh* OR joh%
items.Where(i => i.Name.StartsWith(_search, StringComparison.OrdinalIgnoreCase));
// *son OR %son
items.Where(i => i.Name.EndsWith(_search, StringComparison.OrdinalIgnoreCase));
// *hns* OR %hns%
items.Where(i => i.Name.ToLower().Contains(_search));

Ответ 9

Во время фильтрации вам не нужно использовать знак процента. например;

если я хочу проверить ItemName, не содержит '-', я сделаю это как

!

Item.ItemName.Contains( "-" )

В SQL он преобразуется в NOT LIKE '% -%'

Ответ 10

Мы используем Database First и EntityFramework.

"Составьте свою собственную функцию". подход работает для нас вместе с nuget EntityFramework.CodeFirstStoreFunctions.

1 Шаг: создайте функцию в db следующим образом:

CREATE FUNCTION [dbo].[StringLike]
(
      @a nvarchar(4000),
      @b nvarchar(4000)
)
RETURNS bit
AS
BEGIN
    RETURN 
    (SELECT CASE
            WHEN (SELECT 1 WHERE @a LIKE @b) = 1 THEN 1
            ELSE 0
            END)  
END

2 Шаг: установите nuget EntityFramework.CodeFirstStoreFunctions

3 Шаг: создайте метод в вашем коде, как это (я создаю шахту в классе DbContext):

[DbFunction("CodeFirstDatabaseSchema", "StringLike")]
public static bool Like(string input, string pattern)
{
    throw new NotSupportedException("Direct calls are not supported.");
}

4 Шаг: инициализировать EntityFramework.CodeFirstStoreFunctions.

protected override void OnModelCreating(DbModelBuilder modelBuilder)
{
    modelBuilder.Conventions.Add(new FunctionsConvention("dbo", this.GetType()));
}

5 Шаг: теперь вы можете использовать этот метод в своем запросе linq.