Поскольку вы работаете с LINQ, я полагаю, вы работаете с контекстом данных LINQ-to-SQL, верно? У меня нет свободного DataContext, чтобы проверить это, но это должно дать вам некоторые идеи.
Я не знаю, будет ли он работать против контекста данных, но большинство из них довольно простые вещи (оператор OR с цепочкой и вызов метода Contains), поэтому это не должно вызывать проблем при преобразовании запроса в SQL.
Сначала я создаю пользовательскую функцию, которая будет строить мой предикат:
Func<string, Func<DataItem, bool>> buildKeywordPredicate =
keyword =>
x => x.Title.Contains(keyword)
|| x.Contents.Contains(keyword);
Это функция, которая принимает одно строковое ключевое слово, а затем возвращает другую функцию, которая берет DataItem и проверяет его по ключевому слову.
Как правило, если вы перейдете в «Стек», вы получите предикат: x => x.Title.Contains("Stack") || x.Contents.Contains("Stack")
.
Далее, поскольку существует много возможных ключевых слов, и вам необходимо связать их с помощью операции ИЛИ, я создаю еще одну вспомогательную функцию для объединения 2 предикатов вместе с ИЛИ
Func<Func<DataItem,bool>, Func<DataItem, bool>, Func<DataItem, bool>> buildOrPredicate =
(pred1, pred2) =>
x => pred1(x) || pred2(x);
Эта функция принимает 2 предиката, а затем объединяет их с помощью операции ИЛИ.
Имея эти две функции, я могу затем построить свой предикат where следующим образом:
foreach (var word in keywords) {
filter = filter == null
? buildKeywordPredicate(word)
: buildOrPredicate(filter, buildKeywordPredicate(word));
}
Первая строка внутри цикла в основном проверяет, является ли фильтр нулевым. Если это так, то нам нужен простой фильтр ключевых слов, созданный для нас.
Иначе, если фильтр не равен NULL, нам нужно объединить существующие фильтры с помощью операции ИЛИ, поэтому мы передаем существующий фильтр и новый фильтр ключевых слов в buildOrPredicate, чтобы сделать это.
И теперь мы можем создать часть запроса WHERE:
var result = data.Where(filter);
Передача в сложный предикат, который мы только что создали.
Я не знаю, будет ли это отличаться от использования PredicateBuilder, но поскольку мы откладываем преобразование запросов в движок LINQ-to-SQL, проблем быть не должно.
Но, как я уже сказал, я не проверял его в реальном контексте данных, поэтому, если есть какие-то проблемы, вы можете написать в комментариях.
Вот консольное приложение, которое я создал для тестирования: http://pastebin.com/feb8cc1e
Надеюсь, это поможет!
РЕДАКТИРОВАТЬ: Для более общей и многократно используемой версии, которая включает в себя правильное использование деревьев выражений в LINQ, ознакомьтесь с постом Томаса Петричека в блоге: http://tomasp.net/articles/dynamic-linq-queries.aspx