我正在使用标准访问者模式来遍历LINQ表达式树,以便生成动态SQL WHERE子句。
我的问题是,与C#不同,你不能在SQL中使用独立的布尔表达式;你必须将它与1或0进行比较。
鉴于这个假设的lambda表达式:
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
当然,最后一个例子是糟糕的风格,但是我的代码被设计为独立于程序员的技能水平而工作,所以不能满足冗余场景将是我的不良形式。
答案 0 :(得分:5)
以下案例非常简单:
h => h.Enabled == enabled
h => h.Enabled == true
这些是BinaryExpression
个节点,您可以直接将它们翻译成:
WHERE (Enabled = @p0)
WHERE (Enabled = 1)
您需要处理的特殊情况是:
h => h.Enabled
h => !h.Enabled
在表达式树中以不同的方式表示它们(作为MemberExpression
)。因此,您需要特殊情况MemberExpression
并确定它是否正在访问布尔属性。如果是,则将其翻译为规范形式(在第二个示例中检测UnaryExpression
):
WHERE (Enabled = 1)
WHERE (Enabled = 0)
或者,您可以预处理表达式树并将任何特殊情况转换为规范(表达式树)表单。例如,符合条件的任何MemberExpression
节点都可以转换为正确的BinaryExpression
。
答案 1 :(得分:0)
在影响运算符之前,是否无法完全处理操作数?
IE中。评估每个:
h => h.Enabled
h => h.Enabled == enabled
h => h.Enabled == true
到
WHERE (Enabled = 1)
然后在lambda中包含运算符的情况下,使用等效的SQL处理渲染的操作数的集合,以满足运算符的要求。