Linq-to-SQL: объединение (ИЛИ) нескольких фильтров «Содержит»? - PullRequest
5 голосов
/ 21 декабря 2010

У меня возникли проблемы с поиском лучшего способа сделать это, и я был бы признателен за любую помощь.

По сути, я настраиваю фильтр, который позволяет пользователю просматривать историю элементов аудита, связанных с произвольным «фильтром» имен пользователей.

Источник данных - это база данных SQL Server, поэтому я беру «источник» IQueryable (либо прямую ссылку на таблицу из объекта контекста db, либо, возможно, IQueryable, полученный в результате дополнительных запросов), применяяФильтр WHERE, а затем возвращение результирующего объекта IQueryable .... но я немного озадачен тем, как выполнить ИЛИ, используя этот подход.

Я подумал о том, чтобы пойти по пути выражений, потому что я знаю, как их ИЛИ, но я не смог понять, как это сделать с помощью оценки типа «Содержит», поэтому яв настоящее время использую UNION, но я боюсь, что это может оказать негативное влияние на производительность, и мне интересно, может ли оно дать мне именно то, что мне нужно, если в фильтр добавляются другие фильтры (помимо показанной здесь имени пользователя)произвольный порядок.

Вот мой пример кода:

public override IQueryable<X> ApplyFilter<X>(IQueryable<X> source)
{
    // Take allowed values...
    List<string> searchStrings = new List<string>();

    // <SNIP> (This just populates my list of search strings)

    IQueryable<X> oReturn = null;

    // Step through each iteration, and perform a 'LIKE %value%' query
    string[] searchArray = searchStrings.ToArray();
    for (int i = 0; i < searchArray.Length; i++)
    {
        string value = searchArray[i];
        if (i == 0)
            // For first step, perform direct WHERE
            oReturn = source.Where(x => x.Username.Contains(value));
        else
            // For additional steps, perform UNION on WHERE
            oReturn = oReturn.Union(source.Where(x => x.Username.Contains(value)));
    }
    return oReturn ?? source;
}

Это похоже на неправильный способ сделать что-то, но, похоже, он работает, так что мой вопрос во-первых, есть лилучший способ сделать это?Кроме того, есть ли способ сделать «Содержит» или «Нравится» с выражениями?

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

============================================

ETA: В соответствии с данным решением, вот мой новый код (на тот случай, если кому-то это интересно):

public override IQueryable<X> ApplyFilter<X>(IQueryable<X> source)
{
    List<string> searchStrings = new List<string>(AllowedValues);

    // <SNIP> build collection of search values 

    string[] searchArray = searchStrings.ToArray();

    Expression<Func<X, bool>> expression = PredicateBuilder.False<X>();

    for (int i = 0; i < searchArray.Length; i++)
    {
        string value = searchArray[i];
        expression = expression.Or(x => x.Username.Contains(value));
    }
    return source.Where(expression);
}

(Одно замечание, которое я заметил: следуя примеру PredicateBuilder, пустая коллекция строк поиска будет возвращать false (false || value1 || ...), тогда как в моей исходной версии я предполагал, что пустой список должен просто соединиться снефильтрованный источник. Как я уже думал об этом, новая версия, кажется, имеет больше смысла для моих потребностей, поэтому я принял это)

=============================================

1 Ответ

7 голосов
/ 21 декабря 2010

Вы можете использовать PredicateBuilder из LINQkit для динамического построения вашего запроса.

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