Domanda

Ho una tabella corso che ho bisogno di cercare base a parole chiave digitate nella casella di ricerca. Ecco una query di esempio:

SELECT * FROM Courses WHERE 
Title LIKE '%word%' OR Title LIKE '%excel%' OR 
Contents LIKE '%word%' OR Contents LIKE '%excel%'

Come posso convertire questo in LINQ in cui LINQ sarebbe generare dinamicamente DOVE affermazioni previsionali basate sulle parole chiave ciascuno.

Ho cercato di PredicateBuilder utente funziona bene fino a quando il campo è VARCHAR. Per i campi "testo" le virgolette non sono generate in tal modo causando compilatore per dare un messaggio di errore. Ecco l'SQL generato da PredicateBuilder

SELECT [t0].[CoursesID], [t0].[Title], [t0].[Contents], [t0].[Active], 
FROM [dbo].[Courses] AS [t0]
WHERE ([t0].[Title] LIKE '%word%') OR ([t0].[Contents] LIKE %word%) OR 
([t0].Title] LIKE '%excel%') OR ([t0].[Contents] LIKE %excel%)

Avviso non esiste una sola citazione per il campo "Contenuto", che è un campo di testo nel database.

C'è un modo semplice per costruire WHERE e fissarla con la domanda? Qualcuno sa come posso fare questo senza PredicateBuilder?

Grazie in anticipo.

È stato utile?

Soluzione

Dal momento che si sta lavorando w / LINQ Suppongo che si sta lavorando contro un contesto dati LINQ to SQL giusto? Non ho un DataContext ricambio in giro per verificare questo, ma questo dovrebbe darvi alcune idee.

Non so se funzionerà contro contesto dati, però, ma la maggior parte di questi sono roba abbastanza di base (concatenamento operatore OR e contiene il metodo di chiamata) in modo che non dovrebbe causare problemi quando la query si traduce in SQL.

Per 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);

Questa è una funzione che prende una singola parola corda e poi tornare un'altra funzione che prende un DataItem e controlla contro la parola.

In sostanza, se si passa in "Stack", si otterrà un predicato:. x => x.Title.Contains("Stack") || x.Contents.Contains("Stack")

Poi, 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 ad 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 unirle 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 linea all'interno del ciclo di verifica della se il filtro è nullo. Se lo è, allora vogliamo un semplice filtro parola chiave costruito per noi.

Altrimenti se il filtro non è nullo, abbiamo bisogno di catena dei filtri esistenti con un'operazione OR, per cui si passa il filtro esistente e un nuovo filtro parola chiave per buildOrPredicate di fare proprio questo.

E poi possiamo ora creare la parte in cui della query:

var result = data.Where(filter);

Passaggio nel predicato complicato che abbiamo appena costruito.

Non so se questo sarà diverso dall'utilizzo di PredicateBuilder ma visto che stiamo rimandando traduzione query al motore di LINQ to SQL, non ci dovrebbe essere alcun problema.

Ma come ho detto, ho havn't provato contro un contesto reale di dati, quindi se ci sono problemi è possibile scrivere nei commenti.

Ecco il console app che ho costruito a prova: http://pastebin.com/feb8cc1e

Spero che questo aiuti!


Modifica Per una versione più generico e riutilizzabile che coinvolge correttamente utilizzando le Expression Trees in LINQ, controlla post sul blog di Thomas Petricek: http://tomasp.net/articles/dynamic-linq-queries.aspx

Altri suggerimenti

Come costruttore predicato non conosce il tipo DB della proprietà Contiene metodo viene chiamato in poi, credo che questo potrebbe essere un problema all'interno di LINQ to SQL. Hai provato con una query normale (non con il costruttore predicato) e una colonna di testo con Contiene?

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top