3

問題文

人の名前を検索するクエリがあるとします。

var result = (from person in container.people select person)
             .Where(p => p.Name.Contains(some_criterion)

これは、次のような句を含むSQLクエリに変換されます。

WHERE NAME LIKE '%some_criterion%'

データベースが名前列のインデックスを効果的に使用できないため、これにはパフォーマンスに影響があります(間違っていない場合は、インデックススキャンとインデックスシーク)。

これを修正するために、代わりにStartsWith()だけを使用して、次のようなlike句を使用してクエリを生成することを決定できます。

WHERE NAME LIKE 'some_criterion%'

これにより、SQLサーバーはインデックスシークを使用して、一部の機能を犠牲にしてパフォーマンスを提供できます。

ユーザーに選択肢を提供できるようにしたいと思います。デフォルトでStartsWithを使用するように動作しますが、ユーザーがContains()を使用して検索する「追加の柔軟性」が必要な場合は、それを使用する必要があります。

私は何を試しましたか

これは些細なことだと思い、続けて文字列に拡張メソッドを実装しました。ただし、もちろん、LINQはこれを受け入れず、例外がスローされます。

これで、もちろん、ifまたはswitchステートメントを使用して、それぞれのケースのクエリを作成できますが、これを「より高いレベルで」またはより一般的に解決したいと思います。つまり、実際のアプリケーションは複雑であるため、ifステートメントを使用してユースケースを区別することはできません。これは、多くの繰り返しと混乱につながるでしょう。さまざまな動作(Contains、StartsWith、EndsWith)をなんとかしてカプセル化できるようにしたいと思っています。

質問

どこを見ればいいですか、何を探すべきですか?これはIQueryablesとの構成可能性の場合ですか?私はかなり困惑しています!

4

3 に答える 3

8

物事を過度に複雑にするのではなく、ifステートメントを使用するのはどうですか?

var query = from person in container.people 
            select person;

if (userWantsStartsWith)
{
    query = from p in query
            where p.Name.Contains(some_criterion)
            select p;
}
else
{
    query = from p in query
            where p.Name.StartsWith(some_criterion)
            select p;
}

アップデート

もっと複雑なものが本当に必要な場合は、LinqKitを見てみてください。それはあなたが次のことをすることを可能にします。

var stringFunction = Lambda.Expression((string s1, string s2) => s1.Contains(s2));

if (userWantsStartsWith)
{
    stringFunction = Lambda.Expression((string s1, string s2) => s1.StartsWith(s2));
}

var query = from p in container.people.AsExpandable()
            where stringFunction.Invoke(p.Name, some_criterion)
            select p;

これはあなたの要件を満たしていると思います

さまざまな動作(Contains、StartsWith、EndsWith)をなんとかしてカプセル化できるようにしたいと思っています。

于 2013-03-18T14:10:06.177 に答える
2

クエリを列挙する前に、クエリを動的に変更できます。

var query = container.people.AsQueryable();

if (contains)
{
    query = query.Where(p => p.Name.Contains(filter));
}
else
{
    query = query.Where(p => p.Name.StartsWith(filter));
}
于 2013-03-18T14:12:29.957 に答える
0

disを試してください:

var result = (from person in container.people select person)
                .Where(p => some_bool_variable ? p.Name.Contains(some_criterium) : p.Name.StartsWith(some_criterium));

実際のクエリは非常に巨大で、他のいくつかと統合されています。これは、私の問題の状態のように、私が探している解決策ではありません

クエリが巨大であると考えてください。すべてを処理するストアドプロシージャを定義し、クエリパラメータに固有のストアドプロシージャを呼び出すことはできません(おそらく、メインによって呼び出されるいくつかのストアドプロシージャ、たとえば、名前によるem検索の1つ、年齢による別の検索など)。コードを明確に保つために、異なるソート順など)?

于 2013-03-18T14:12:52.980 に答える