2009-02-28 29 views
11

私は検索ボックスに入力したキーワードに基づいて検索する必要のあるコーステーブルを持っています。ここ はサンプルクエリです:LINQ multiple where句

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

私は文は、各キーワードに基づいてWHERE LINQを動的に生成するLINQでこれを変換するにはどうすればよいです。

フィールドがVARCHARである限り、PredicateBuilderは正常に動作しました。 "TEXT"フィールドの場合、引用符は生成されず、コンパイラはエラーメッセージを表示します。ここで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%) 

お知らせによって生成されたSQLは、データベース内のテキストフィールドである「内容」欄には、単一引用符がありませんです。

WHEREステートメントを作成してクエリを添付する簡単な方法はありますか?誰も私がPredicateBuilderなしでこれを行う方法を知っていますか?

ありがとうございます。

答えて

13

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")が得られます。

次に、そこに多くの可能なキーワードは、あなたはOR演算でチェーンにそれを必要とするので、私はOR

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

と一緒にチェーン2の述語に別のヘルパー関数を作成し、この関数は、その後2つの述語を取り、それらをOR操作で結合する。

これらの2つの機能を持って、私はそれから構築することができ、私のところこのような述語:

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

フィルタがnullの場合、ループ内の最初の行は基本的にチェックします。そうであれば、簡単なキーワードフィルタが必要です。

フィルタがnullでない場合、OR演算を使用して既存のフィルタを連結する必要があるため、既存のフィルタと新しいキーワードフィルタをbuildOrPredicateに渡してその処理を行います。

そして、我々は今、クエリのWHEREの部分を作成することができます。

私達はちょうど構築した複雑な述語を渡す
var result = data.Where(filter); 

これはPredicateBuilderを使用した場合とは異なりますが、我々はLINQツーSQLエンジンにクエリの翻訳を延期しているので、何か問題があってはならない場合、私は知りません。

しかし、私が言ったように、私は実際のデータコンテキストに対してそれをテストしていないので、問題があればコメントに書き込むことができます。

は、ここで私がテストに構築されたコンソールアプリケーションです:http://pastebin.com/feb8cc1e

は、この情報がお役に立てば幸い!


EDIT:適切にLINQで式ツリーを利用含まれ、より汎用的かつ再利用可能なバージョンについては、トーマスPetricekのブログ記事をチェックアウト:http://tomasp.net/articles/dynamic-linq-queries.aspx

+1

これは生憎のみの機能のために動作します。これをExpression Treesで動作させるには、次のようなトリックを使用する必要があります:http://tomasp.net/articles/dynamic-linq-queries.aspx –

+0

これはあなたがそこでやったことです!とにかく、私は今あなたのブログの購読者です:-) – chakrit

+0

ありがとう、これは働いた。 http://tomasp.net/articles/dynamic-linq-queries.aspx - Tomas Petricek – Amir

0

述語のビルダーはContainsメソッドが呼び出されたプロパティのDB型を知らないため、linqからsqlの内部で問題が発生している可能性があります。あなたは通常のクエリ(述語ビルダーではない)とTEXT列にContainsを試しましたか?