Come valutare un'espressione booleana autonoma in un albero di espressioni LINQ
-
07-07-2019 - |
Domanda
Sto usando il modello di visitatore standard per scorrere un albero delle espressioni LINQ al fine di generare clausole WHERE SQL dinamiche.
Il mio problema è che, diversamente da C #, non puoi usare un'espressione booleana autonoma in SQL; devi confrontarlo con 1 o 0.
Data questa ipotetica espressione lambda:
h => h.Enabled || h.Enabled == false
Sarebbe facile generare erroneamente questo codice:
WHERE Enabled OR Enabled = 0
o questo codice:
WHERE (Enabled = 1) OR (Enabled = 1) = 0
Entrambi ovviamente genereranno un errore SQL. Quale logica dovrei applicare per aggirare questo senza che il mio codice inizi a sembrare davvero ottuso mentre mi immergo nelle sottotitoli per capire quale potrebbe essere il caso?
EDIT: l'esempio sopra è ovviamente ridondante - lo sto usando solo per illustrare un punto.
Esempi che potrebbero creare questo scenario:
h => h.Enabled
h => h.Enabled == enabled
h => h.Enabled == true
Naturalmente, l'ultimo esempio è uno stile scadente, ma il mio codice è stato progettato per funzionare indipendentemente dal livello di abilità del programmatore, quindi non soddisfare scenari ridondanti sarebbe una forma scadente da parte mia.
Soluzione
I seguenti casi sono piuttosto semplici:
h => h.Enabled == enabled
h => h.Enabled == true
Questi sono nodi BinaryExpression
e puoi tradurli direttamente in:
WHERE (Enabled = @p0)
WHERE (Enabled = 1)
I casi speciali che è necessario gestire sono:
h => h.Enabled
h => !h.Enabled
Questi sono rappresentati diversamente nell'albero delle espressioni (come MemberExpression
). Pertanto, dovrai specificare il MemberExpression
e stabilire se sta accedendo a una proprietà booleana o meno. In tal caso, lo traduci nella forma canonica (rilevando il UnaryExpression
nel secondo esempio):
WHERE (Enabled = 1)
WHERE (Enabled = 0)
In alternativa, potresti essere in grado di pre-elaborare l'albero delle espressioni e tradurre eventuali casi speciali nella loro forma canonica (albero delle espressioni). Ad esempio, tutti i nodi MemberExpression
che soddisfano i criteri potrebbero essere trasformati nel BinaryExpression
corretto.
Altri suggerimenti
Non è possibile elaborare completamente gli operandi prima di sviluppare gli operatori?
Ie. Valuta ciascuno di:
h => h.Enabled
h => h.Enabled == enabled
h => h.Enabled == true
a
WHERE (Enabled = 1)
e quindi nel caso in cui gli operatori siano inclusi nella lambda, elabora la raccolta di operandi renderizzati con SQL equivalente per soddisfare i requisiti degli operatori.