2009-02-28 19 views
11

Ich habe eine Kurstabelle, die ich basierend auf Suchbegriffen im Suchfeld suchen muss. Hier ist eine Beispielabfrage:LINQ multiple where-Klausel

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

Wie kann ich dies in LINQ konvertieren wo LINQ dynamisch WHERE-Anweisungen auf jedem Schlüsselwörtern basiert erzeugen würde.

Ich habe versucht, PredicateBuilder zu verwenden, es funktioniert gut, solange das Feld VARCHAR ist. Für die "TEXT" -Felder werden die Anführungszeichen nicht erzeugt, was dazu führt, dass der Compiler eine Fehlermeldung gibt. Hier ist die SQL erzeugt durch 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%) 

Hinweis Es gibt kein einziges Zitat für das „Inhalt“ Feld, das ein Textfeld in der Datenbank ist.

Gibt es eine einfache Möglichkeit, WHERE-Anweisung zu erstellen und mit Abfrage anhängen? Weiß jemand wie ich das ohne PredicateBuilder machen kann?

Vielen Dank im Voraus.

Antwort

13

Da Sie mit LINQ arbeiten, nehme ich an, dass Sie gegen einen LINQ-zu-SQL-Datenkontext richtig arbeiten? Ich habe keinen freien DataContext herumliegen, um dies zu testen, aber das sollte Ihnen einige Ideen geben.

Ich weiß nicht, ob es gegen den Datenkontext funktioniert, aber die meisten davon sind ziemlich einfach (Verkettung von OR-Operator und Contains-Methodenaufruf), so sollte es kein Problem verursachen, wenn die Abfrage in SQL übersetzt.

Zunächst erstelle ich eine benutzerdefinierte Funktion, die mein Prädikat bauen würde:

Func<string, Func<DataItem, bool>> buildKeywordPredicate = 
    keyword => 
     x => x.Title.Contains(keyword) 
      || x.Contents.Contains(keyword); 

Dies ist eine Funktion, die einen einzelnen String Schlüsselwort nimmt und dann eine andere Funktion zurück, die eine DataItem nimmt und prüft sie gegen das Schlüsselwort. Wenn Sie "Stack" übergeben, erhalten Sie im Prinzip ein Prädikat: x => x.Title.Contains("Stack") || x.Contents.Contains("Stack").

Als nächstes, da es viele mögliche Keywords sind, und Sie müssen mit einer ODER-Verknüpfung an die Kette, ich eine andere Hilfsfunktion Kette 2 Prädikate zusammen mit einem OR

Func<Func<DataItem,bool>, Func<DataItem, bool>, Func<DataItem, bool>> buildOrPredicate = 
    (pred1, pred2) => 
     x => pred1(x) || pred2(x); 

Diese Funktion nimmt zwei Prädikate und erstellen verbinde sie mit einer ODER-Operation.

diese zwei Funktionen haben, kann ich dann bauen sie meine, wo Prädikat wie folgt aus:

foreach (var word in keywords) {    
    filter = filter == null 
     ? buildKeywordPredicate(word) 
     : buildOrPredicate(filter, buildKeywordPredicate(word)); 
} 

Die erste Zeile in der Schleife prüft grundsätzlich, wenn der Filter null ist. Wenn ja, möchten wir einen einfachen Keyword-Filter für uns erstellen.

Wenn der Filter nicht null ist, müssen wir vorhandene Filter mit einer OR-Operation verketten, also übergeben wir den bestehenden Filter und einen neuen Schlüsselwortfilter an buildOrPredicate, um genau das zu tun.

Und dann können wir jetzt den WHERE-Teil der Abfrage erstellen:

var result = data.Where(filter); 

in dem komplizierten Prädikat Passing wir gerade gebaut haben.

Ich weiß nicht, ob dies anders als PredicateBuilder ist, aber da wir die Query-Übersetzung auf die LINQ-to-SQL-Engine verschieben, sollte es keine Probleme geben.

Aber wie gesagt, ich habe es nicht mit einem echten Datenkontext getestet, also wenn es irgendwelche Probleme gibt, können Sie in die Kommentare schreiben.

Hier ist die Konsole-Anwendung, die ich zu Test gebaut: http://pastebin.com/feb8cc1e

hoffe, das hilft!


EDIT: Für eine allgemeinere und wieder verwendbare Version, die die Expression Bäume in LINQ ordnungsgemäß unter Verwendung beinhaltet Besuche Thomas Petricek Blog-Post: http://tomasp.net/articles/dynamic-linq-queries.aspx

+1

Das wird leider nur für Funktionen arbeiten. Um das mit Expression Trees zu machen, müssen Sie einen Trick wie diesen verwenden: http://tomasp.net/articles/dynamic-linq-queries.aspx –

+0

Das ist etwas, das Sie dort gemacht haben! .. Derselbe Trick, aber allgemeiner und mehr Ehrfurcht ... Wie auch immer, ich bin jetzt ein Abonnent deines Blogs :-) – chakrit

+0

Danke, dieser hat funktioniert. http://tomasp.net/articles/dynamic-linq-queries.aspx - Tomas Petricek – Amir

0

Da Prädikat-Builder den DB-Typ der Eigenschaft nicht kennt, die die Contains-Methode aufgerufen hat, könnte dies ein Problem innerhalb von linq to sql sein. Haben Sie mit einer normalen Abfrage (nicht mit Prädikat-Builder) und einer TEXT-Spalte mit Contains versucht?