Dado que está trabajando con LINQ, supongo que está trabajando en un contexto de datos LINQ-to-SQL ¿verdad? No tengo un DataContext de repuesto por ahí para probar esto, pero esto debería darte algunas ideas.
No sé si funcionará contra el contexto de datos, pero la mayoría de estas son cosas bastante básicas (encadenando el operador OR y contiene la llamada al método) por lo que no debería causar problemas cuando la consulta traduce a SQL.
Primero crear una función personalizada que construiría mi predicado:
Func<string, Func<DataItem, bool>> buildKeywordPredicate =
keyword =>
x => x.Title.Contains(keyword)
|| x.Contents.Contains(keyword);
Ésta es una función que toma una sola palabra clave de cadena y luego regresar otra función que toma un DataItem y comprueba contra la palabra clave.
Básicamente, si pasa en "Pila", obtendrá un predicado: x => x.Title.Contains("Stack") || x.Contents.Contains("Stack")
.
A continuación, ya que hay muchas palabras clave posibles y que necesita para la cadena con una operación OR, puedo crear otra función auxiliar para la cadena 2 predicados junto con un OR
Func<Func<DataItem,bool>, Func<DataItem, bool>, Func<DataItem, bool>> buildOrPredicate =
(pred1, pred2) =>
x => pred1(x) || pred2(x);
Esta función toma 2 predicados y luego únelos con una operación OR.
Tener esos 2 funciones, entonces me puedo construir mi donde predicado como esto:
foreach (var word in keywords) {
filter = filter == null
? buildKeywordPredicate(word)
: buildOrPredicate(filter, buildKeywordPredicate(word));
}
La primera línea dentro del bucle básicamente comprueba si el filtro es nulo. Si es así, entonces queremos que se cree un filtro de palabras clave simple para nosotros.
De lo contrario, si el filtro no es nulo, debemos encadenar los filtros existentes con una operación OR, por lo que pasamos el filtro existente y un nuevo filtro de palabra clave a buildOrPredicate para hacer justamente eso.
Y entonces ahora podemos crear la parte WHERE de la consulta:
var result = data.Where(filter);
Pasando en el predicado complicada que sólo hemos construido.
No sé si esto será diferente al uso de PredicateBuilder pero dado que estamos posponiendo la traducción de consultas al motor LINQ-to-SQL, no debería haber ningún problema.
Pero como he dicho, no lo he probado contra un contexto de datos real, por lo que si hay algún problema puede escribir en los comentarios.
Aquí está la aplicación de consola que he construido a prueba: http://pastebin.com/feb8cc1e
Espero que esto ayude!
EDIT: Para una versión más genérica y reutilizable que consiste en utilizar adecuadamente los árboles de expresión en LINQ, echa un vistazo a el blog de Thomas Petricek: http://tomasp.net/articles/dynamic-linq-queries.aspx
Esto desafortunadamente trabajar sólo para funciones. Para hacer que esto funcione con Expression Trees debes usar un truco como este: http://tomasp.net/articles/dynamic-linq-queries.aspx –
¡Esa es una hazaña que hiciste allí! .. El mismo truco pero más genérico y más genial ... De todos modos, ahora soy un suscriptor de tu blog :-) – chakrit
Gracias, este funcionó. http://tomasp.net/articles/dynamic-linq-queries.aspx - Tomas Petricek – Amir