LINQ式ツリーでスタンドアロンのブール式を評価する方法
-
07-07-2019 - |
質問
標準の訪問者パターンを使用して、LINQ式ツリーを反復処理し、動的SQL WHERE句を生成しています。
私の問題は、C#とは異なり、SQLでスタンドアロンのブール式を使用できないことです。 1または0と比較する必要があります。
この仮想のラムダ式を考えると、
h => h.Enabled || h.Enabled == false
このコードを誤って生成するのは簡単です:
WHERE Enabled OR Enabled = 0
またはこのコード:
WHERE (Enabled = 1) OR (Enabled = 1) = 0
もちろん、どちらもSQLエラーを生成します。この問題を回避するには、サブツリーを深く掘り下げて、ケースが何であるかを把握する際に、コードが本当に鈍く見えないようにするには、どのロジックを適用する必要がありますか?
編集:上記の例はもちろん冗長です-ポイントを説明するためだけに使用しています。
このシナリオを作成できる例:
h => h.Enabled
h => h.Enabled == enabled
h => h.Enabled == true
当然、最後の例は貧弱なスタイルですが、私のコードはプログラマーのスキルレベルに依存せずに動作するように設計されているため、冗長なシナリオに対応しないことは私にとっては貧弱な形です。
解決
次のケースは非常に単純です:
h => h.Enabled == enabled
h => h.Enabled == true
これらは BinaryExpression
ノードであり、これらを直接翻訳できます:
WHERE (Enabled = @p0)
WHERE (Enabled = 1)
処理する必要がある特殊なケースは次のとおりです。
h => h.Enabled
h => !h.Enabled
これらは、式ツリーで( MemberExpression
として)異なって表されます。そのため、 MemberExpression
を特殊なケースにして、ブールプロパティにアクセスしているかどうかを判断する必要があります。そうである場合は、正規形式に変換します(2番目の例の UnaryExpression
を検出します):
WHERE (Enabled = 1)
WHERE (Enabled = 0)
別の方法として、式ツリーを前処理して、特殊なケースを正規の(式ツリー)形式に変換できる場合があります。たとえば、基準に適合する MemberExpression
ノードは、正しい BinaryExpression
に変換できます。
他のヒント
演算子を検証する前にオペランドを完全に処理することはできませんか?
つまり。それぞれの評価:
h => h.Enabled
h => h.Enabled == enabled
h => h.Enabled == true
to
WHERE (Enabled = 1)
そして、演算子がラムダに含まれる場合、演算子の要件を満たすために、同等のSQLでレンダリングされたオペランドのコレクションを処理します。