views:

551

answers:

4

I'm using the standard visitor pattern to iterate through a LINQ expression tree in order to generate dynamic SQL WHERE clauses.

My issue is that unlike C#, you can't use a standalone boolean expression in SQL; you have to compare it to either 1 or 0.

Given this hypothetical lambda expression:

h => h.Enabled || h.Enabled == false

It would be easy to mistakenly generate this code:

WHERE Enabled OR Enabled = 0

or this code:

WHERE (Enabled = 1) OR (Enabled = 1) = 0

Both of course will generate an SQL error. What logic should I apply to get around this without my code starting to look really obtuse as I delve deep into subtrees to figure out what the case may be?

EDIT: The example above is of course redundant - I am only using it to illustrate a point.

Examples that could create this scenario:

h => h.Enabled
h => h.Enabled == enabled
h => h.Enabled == true

Naturally that last example is poor style, but my code is being designed to work independent of the programmer's skill level, so to not cater for redundant scenarios would be poor form on my part.

A: 

I'm probably reading this wrong, but isn't

h => h.Enabled || h.Enabled == false

redundant? as the Enabled can only be true or false thus the above will always evaluate to true?

Jaimal Chohan
Yep, that's what the last line of my question says. I'm illustrating a point though, that it is possible to pass in expressions in either form. The example is academic; what I'm looking for is how such a case would be dealt with.
Nathan Ridley
Apart from showing off a difference in SQL syntax compared to LINQ, I still don't undersant what your trying to accomplish. It's equivalent to [WHERE Enabled = 1 OR Enabled = 0].
Jaimal Chohan
Here's two scenarios - somebody may call h => h.Enabled OR somebody may call h => h.Enabled == enabled. My example covers both examples in one line. Now, back to the question...
Nathan Ridley
Ahh, now that makes sense. Can you not evaluate the value of the RHS (in the baove example, the RHS being the variable <enabled>) to either 1 or 0?
Jaimal Chohan
I think you need to read the question again, noting the first 3 code snippets I put down.
Nathan Ridley
A: 

you could do it like this instead h => true :D

sda
A: 

Is it not possible to process the operands completely before eveluating the operators?

Ie. Eval each of:

h => h.Enabled
h => h.Enabled == enabled
h => h.Enabled == true

to

WHERE (Enabled = 1)

and then in the case where operators are included in the lambda, process the collection of rendered operands with the equivalent SQL to meet the operator requirements.

cottsak
+2  A: 

The following cases are pretty straight forward:

h => h.Enabled == enabled
h => h.Enabled == true

These are BinaryExpression nodes, and you can directly translate them into:

WHERE (Enabled = @p0)
WHERE (Enabled = 1)

The special case(s) that you need to handle are:

h => h.Enabled
h => !h.Enabled

Those are represented differently in the expression tree (as a MemberExpression). So you would need to special case the MemberExpression and determine if it's accessing a boolean property or not. If it is, then you translate it into the canonical form (detecting the UnaryExpression in the second example):

WHERE (Enabled = 1)
WHERE (Enabled = 0)

Alternatively, you might be able to pre-process the expression tree and translate any special cases into their canonical (expression tree) form. For example, any MemberExpression nodes that fit the criteria could be transformed into the correct BinaryExpression.

Brannon