Сравнение Linq, Expressions, NHibernate и Like - PullRequest
6 голосов
/ 04 августа 2009

Я пытаюсь сделать аналогичное сравнение на основе внешнего параметра (переданного в форме поиска), который определяет тип сравнения ("%string" или "string%" или "%string%")

Я думал в следующем направлении:

query = query.Where(
    Entity.StringProperty.Like("SearchString", SelectedComparsionType)
)

Как метод, чем на основе выбранного типа возврата .StartsWith() или .EndsWith() или .SubString()

Мои знания выражений явно далеки от совершенства, так как я не смог создать метод, который мог бы дать правильный результат (сравнение на стороне сервера в SQL, как с StartsWith методом).

Ответы [ 4 ]

17 голосов
/ 10 августа 2009

Простой способ

Просто используйте

if (comparison == ComparisonType.StartsWith)
    query = query.Where(e => e.StringProperty.StartsWith("SearchString"));
else if ...

Трудный путь

Если вы хотите сделать что-то подобное, либо убедитесь, что ваш поставщик LINQ каким-то образом проинформирован об этом новом методе, и как он переводится в SQL (маловероятно), либо не позволяйте вашему методу когда-либо достичь поставщика LINQ, и предоставьте провайдер что-то понимает (сложно). Например, вместо

query.Where(e => CompMethod(e.StringProperty, "SearchString", comparsionType))

вы можете создать что-то вроде

var query = source.WhereLike(e => e.StringProperty, "SearchString", comparsionType)

со следующим кодом

public enum ComparisonType { StartsWith, EndsWith, Contains }

public static class QueryableExtensions
{
    public static IQueryable<T> WhereLike<T>(
        this IQueryable<T> source,
        Expression<Func<T, string>> field, 
        string value,
        SelectedComparisonType comparisonType)
    {
        ParameterExpression p = field.Parameters[0];
        return source.Where(
            Expression.Lambda<Func<T, bool>>(
                Expression.Call(
                    field.Body, 
                    comparisonType.ToString(), 
                    null, 
                    Expression.Constant(value)),
            p));
    }
}

Вы даже можете добавить дополнительные критерии таким образом

var query = from e in source.WhereLike(
                e => e.StringProperty, "SearchString", comparsionType)
            where e.OtherProperty == 123
            orderby e.StringProperty
            select e;

Очень, очень трудный путь

(технически) можно было бы переписать дерево выражений до того, как провайдер его увидит, так что вы можете использовать запрос, который вы имели в виду, но вам нужно будет

  • создать Where(this IQueryable<EntityType> source, Expression<Func<EntityType, bool>> predicate) для перехвата Queryable.Where,
  • переписать дерево выражений, заменив CompMethod, где бы он ни находился, одним из String методов,
  • вызовите оригинал Queryable.Where с переписанным выражением
  • и, прежде всего, прежде всего, следуйте вышеприведенному методу расширения!

Но это, вероятно, слишком сложно для того, что вы имели в виду.

1 голос
/ 04 августа 2009

Звучит так, как будто вы хотите использовать:

query = query.Where(
Entity.StringProperty.Contains("SearchString")
)

Это должно соответствовать:

WHERE StringProperty LIKE '%SearchString%'

Это также должно работать для более продвинутых масок поиска, таких как "Mr? Sm% th", но мне еще не приходилось тестировать подобные строки поиска.


ОБНОВЛЕНИЕ: на основании редактирования ОП

Звучит так, будто вы просите что-то вроде следующего:

   public enum SelectedComparsionType
    {
        StartsWith,
        EndsWith,
        Contains
    }

public static bool Like(this string searchString, string searchPattern, SelectedComparsionType searchType)
{
    switch (searchType)
    {
        case SelectedComparsionType.StartsWith:
            return searchString.StartsWith(searchPattern);
        case SelectedComparsionType.EndsWith:
            return searchString.EndsWith(searchPattern);
        case SelectedComparsionType.Contains:
        default:
            return searchString.Contains(searchPattern);
    }
}

Это позволит вам писать код по вашему усмотрению, например:

query = query.Where(
Entity.StringProperty.Like("SearchString", SelectedComparsionType.StartsWith)
)

Однако, лично , я бы заменил любое использование SelectedComparsionType прямым вызовом требуемой строковой функции. * 1024 то есть *

query = query.Where(
Entity.StringProperty.StartsWith("SearchString")
)

Поскольку это все равно будет сопоставлено с запросом SQL 'LIKE'.

0 голосов
/ 04 августа 2009

Это именно то, что я имел в виду, спасибо. У меня уже было что-то подобное, но оно не переводилось на SQL. Например, это сработало, если я сделал это напрямую:

Entity.StringProperty.EndsWith("SearchString");

Это не сработало, если бы я использовал специальный метод:

CompMethod("BaseString","SearchString",SelectedComparsionType.EndsWith)

Думаю, это как-то связано с оценкой выражений, я просто не знаю, что именно.

0 голосов
/ 04 августа 2009

Вам будет лучше использовать Regex для решения этой проблемы.

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