Dato che si sta lavorando con LINQ, suppongo si stia lavorando contro un contesto dati LINQ-to-SQL, giusto? Non ho un DataContext di riserva in giro per testarlo, ma questo dovrebbe darti qualche idea.
Non so se funzionerà comunque con il contesto dei dati, ma la maggior parte di questi sono cose piuttosto semplici (concatenamento di operatore OR e chiamata di metodi Contains) quindi non dovrebbe causare problemi quando la query viene tradotta in SQL.
prima cosa creare una funzione personalizzata che avrebbe costruito la mia predicato:
Func<string, Func<DataItem, bool>> buildKeywordPredicate =
keyword =>
x => x.Title.Contains(keyword)
|| x.Contents.Contains(keyword);
Si tratta di una funzione che prende una singola parola corda e poi tornare un'altra funzione che prende un DataItem e controlla contro la parola chiave.
Fondamentalmente, se si passa in "Stack", si ottiene un predicato: x => x.Title.Contains("Stack") || x.Contents.Contains("Stack")
.
successivo, dato che ci sono molte parole chiave possibili e avete bisogno di catena con un'operazione OR, creo un'altra funzione di supporto per catena 2 predicati insieme con un OR
Func<Func<DataItem,bool>, Func<DataItem, bool>, Func<DataItem, bool>> buildOrPredicate =
(pred1, pred2) =>
x => pred1(x) || pred2(x);
Questa funzione prende 2 predicati e poi unisciti a loro con un'operazione OR.
Avendo questi 2 funzioni, posso quindi costruire il mio in cui predicato in questo modo:
foreach (var word in keywords) {
filter = filter == null
? buildKeywordPredicate(word)
: buildOrPredicate(filter, buildKeywordPredicate(word));
}
La prima riga all'interno del ciclo controlla in fondo se il filtro è nullo. Se lo è, allora vogliamo un semplice filtro per le parole chiave costruito per noi.
Altrimenti se il filtro non è nullo, è necessario concatenare i filtri esistenti con un'operazione OR, quindi passiamo il filtro esistente e un nuovo filtro di parole chiave a buildOrPredicate per fare proprio questo.
E poi possiamo ora creare la parte in cui della query:
var result = data.Where(filter);
Passando nel predicato complicato che abbiamo appena costruito.
Non so se questo sarà diverso dall'utilizzo di PredicateBuilder, ma dal momento che stiamo rimandando la traduzione di query al motore LINQ-to-SQL, non dovrebbero esserci problemi.
Ma come ho detto, non l'ho provato rispetto a un contesto di dati reali, quindi se ci sono problemi puoi scrivere nei commenti.
Ecco il console app che ho costruito a prova: http://pastebin.com/feb8cc1e
Spero che questo aiuti!
EDIT: Per una versione più generica e riutilizzabile che coinvolge correttamente utilizzando le Expression Trees in LINQ, check-out post sul blog di Thomas Petricek: http://tomasp.net/articles/dynamic-linq-queries.aspx
Ciò sfortunatamente funziona solo per le funzioni. Per farlo funzionare con Expression Trees devi usare un trucco del genere: http://tomasp.net/articles/dynamic-linq-queries.aspx –
Questa è una prodezza che hai fatto lì! .. Lo stesso trucco ma più generico e più meraviglia ... Ad ogni modo, ora sono iscritto al tuo blog :-) – chakrit
Grazie, questo ha funzionato. http://tomasp.net/articles/dynamic-linq-queries.aspx - Tomas Petricek – Amir