2

(編集:私は間違った質問をしました。私が抱えている本当の問題は、LINQ-to-SQL述語を単一の述語に構成することで終わりました-しかし、これはいくつかの良い答えを得たので、私はそれを残しました!)

次の検索テキストがあるとします。

"keyword1 keyword2 keyword3   ... keywordN"

私は次のSQLで終わりたい:

SELECT [columns] FROM Customer 
  WHERE 
    (Customer.Forenames LIKE '%keyword1%' OR Customer.Surname LIKE '%keyword1%')
  AND
     (Customer.Forenames LIKE '%keyword2%' OR Customer.Surname LIKE '%keyword2%')
  AND 
    (Customer.Forenames LIKE '%keyword3%' OR Customer.Surname LIKE '%keyword3%')
  AND
    ...
  AND 
    (Customer.Forenames LIKE '%keywordN%' OR Customer.Surname LIKE '%keywordN%')

事実上、検索テキストをスペースで分割し、各トークンをトリミングし、各トークンに基づいてマルチパート OR 句を作成し、句を AND 結合します。

私はこれをLinq-to-SQLで行っていますが、サブ述語の任意の長いリストに基づいて述語を動的に作成する方法がわかりません。句の数がわかっている場合、述語を手動で構成するのは簡単です。

dataContext.Customers.Where(
    (Customer.Forenames.Contains("keyword1") || Customer.Surname.Contains("keyword1")
    &&
    (Customer.Forenames.Contains("keyword2") || Customer.Surname.Contains("keyword2")
    &&
    (Customer.Forenames.Contains("keyword3") || Customer.Surname.Contains("keyword3")
);

しかし、検索語の任意のリストを処理したいと考えています。私はどこまでも

Func<Customer, bool> predicate = /* predicate */;
foreach(var token in tokens) {
    predicate = (customer 
        => predicate(customer) 
        && 
         (customer.Forenames.Contains(token) || customer.Surname.Contains(token));
}

それは StackOverflowException を生成します-おそらく、割り当ての RHS の predicate() が実際には実行時まで評価されず、その時点で自分自身を呼び出すことになるためです...または何か。

要するに、2 つの述語が指定された場合に、指定された演算子を使用して 2 つのソース述語を構成する単一の述語を返す手法が必要ですが、Linq-to-SQL で明示的にサポートされている演算子に限定されます。何か案は?

4

2 に答える 2

3

別のテクニックを提案します

できるよ:

var query = dataContext.Customers;

そして、サイクル内で行う

foreach(string keyword in keywordlist)
{
    query = query.Where(Customer.Forenames.Contains(keyword) || Customer.Surname.Contains(keyword));
}
于 2010-09-23T21:58:52.803 に答える
1

これをより簡潔で宣言的な方法で記述したい場合は、ループと可変変数Aggregateの代わりに拡張メソッドを使用することもできます。foreach

var query = keywordlist.Aggregate(dataContext.Customers, (q, keyword) => 
    q.Where(Customer.Forenames.Contains(keyword) || 
            Customer.Surname.Contains(keyword)); 

これは初期状態として取得され、指定された集計関数 ( Gnomo が提案するようdataContext.Customersに呼び出すだけです) を使用して、リスト内のすべてのキーワードに対してこの状態 (クエリ) を更新します。Where

于 2010-09-23T22:12:24.170 に答える