Linq SqlMethods.Like не удается - PullRequest
7 голосов
/ 06 апреля 2010

Я следую советам здесь , пытаясь использовать утверждение, что sql не создается до тех пор, пока не отключится перечислитель.Однако я получаю следующую ошибку в коде ниже.Я использую Linq2Entities, а не linq2sql.Есть ли способ сделать это в Linq2entities?

Метод 'Boolean Like (System.String, System.String)' нельзя использовать на клиенте;это только для перевода в SQL.

            query = db.MyTables.Where(x => astringvar.Contains(x.Field1));

            if (!String.IsNullOrEmpty(typeFilter))
            {
                if (typeFilter.Contains('*'))
                {
                    typeFilter = typeFilter.Replace('*', '%');
                    query = query.Where(x=> SqlMethods.Like(x.Type, typeFilter));
                }
                else
                {
                    query  = query.Where(x => x.Type == typeFilter);
                }
            }

Примечания: db - это сущность, сопоставляемая с сервером sql.

Ответы [ 4 ]

11 голосов
/ 06 апреля 2010

Я не знаю, как заставить Entity Framework использовать «настоящий» оператор LIKE, но возможный обходной путь - это выражение LIKE в выражениях StartsWith, Contains и EndsWith

Например:

LIKE 'a%' => StartsWith("a")
LIKE '%a' => EndsWith("a")
LIKE '%a%' => Contains("a")
LIKE 'a%b' => StartsWith("a") && EndsWith("b")
LIKE 'a%b%' => StartsWith("a") && Contains("b")

И так далее ...

Обратите внимание, что это не совсем эквивалентно использованию LIKE в SQL: например, LIKE '%abc%bcd%' приведет к Contains("abc") && Contains("bcd"). Это будет соответствовать "abcd", даже если исходное условие LIKE не будет. Но в большинстве случаев этого должно быть достаточно.

Вот пример реализации, использующий PredicateBuilder и LinqKit для построения выражений на основе шаблона LIKE:

public static class ExpressionHelper
{
    public static Expression<Func<T, bool>> StringLike<T>(Expression<Func<T, string>> selector, string pattern)
    {
        var predicate = PredicateBuilder.True<T>();
        var parts = pattern.Split('%');
        if (parts.Length == 1) // not '%' sign
        {
            predicate = predicate.And(s => selector.Compile()(s) == pattern);
        }
        else
        {
            for (int i = 0; i < parts.Length; i++)
            {
                string p = parts[i];
                if (p.Length > 0)
                {
                    if (i == 0)
                    {
                        predicate = predicate.And(s => selector.Compile()(s).StartsWith(p));
                    }
                    else if (i == parts.Length - 1)
                    {
                        predicate = predicate.And(s => selector.Compile()(s).EndsWith(p));
                    }
                    else
                    {
                        predicate = predicate.And(s => selector.Compile()(s).Contains(p));
                    }
                }
            }
        }
        return predicate;
    }
}

А вот как вы можете его использовать:

var expr = ExpressionHelper.StringLike<YourClass>(x => x.Type, typeFilter);
query = query.AsExpandable().Where(expr.Compile());

Я только что попробовал это с простой моделью EF, и, кажется, работает нормально :) 1026 *

4 голосов
/ 06 апреля 2010

Класс SqlMethods предназначен для использования с LINQ-to-SQL. Когда вы используете методы из этого (что публичная документация запрещает делать, это не для общего пользования), поставщик IQueryable для LINQ-to-Entities не знает, что с ним делать или как это перевести.

Если у вас был один подстановочный знак в начале или конце фильтра, то вы можете использовать методы StartsWith или EndsWith в классе String, и LINQ-to-Entities будет поддерживать это.

Однако в этом случае у вас есть переменное число подстановочных знаков, поэтому вам придется опуститься до уровня ESQL и построить запрос из него, как указано в ответе Nix .

4 голосов
/ 06 апреля 2010

Вы можете сделать ESQL и сделать что-то вроде следующего ..

     db.MyTables.Where("it.Type like '" + typeFilter + "'").ToList();
0 голосов
/ 15 июля 2015

Вы можете использовать реальный как в Ссылка на объекты

Добавить

    <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

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