Linq To Sql – query con campi a null
Lavorando su un progetto winform in vb.net e linq to sql mi sono imbattuto in un problema in cui ho perso un pò di tempo per venirne a capo.
Praticamente il problema di fondo è quello di scrivere una query linq che recuperi dei record filtrandoli su un campo che può essere anche NULL (nell’esempio il campo che contiene anche valori a NULL è il campo CF).
Quindi avere sia i record che soddisfano la condizione del parametro sia quelli che hanno il campo a NULL.
In t-sql la query sarebbe scritta più o meno in questa maniera:
SELECT * FROM Anagrafica WHERE NOME = @Nome AND((@cf IS NULL) OR (cf = @cf))
Con questo tipo di query sto semplicemente chiedendo di restituirmi tutti i record il cui campo Nome è uguale al parametro @Nome e il codice fiscale è uguale al parametro @cf oppure è NULL.
La stessa può essere scritta anche con l’uso della funzione ISNULL()
SELECT * FROM Anagrafica WHERE NOME = @Nome and (ISNULL(cf,'') = ISNULL(@cf, '') or CF = ISNULL(@cf,CF))
Ora per simulare lo stesso comportamento in una query Linq dobbiamo avvalerci di un piccolo workaround, o meglio, quello che non ho capito è come poter simulare la funzione ISNULL() in Linq, su stackoverflow consigliano di usare i tipi nullable.
Andiamo a vedere come tutto questo si traduce in codice VB.NET
Dim db As New testDataContext Dim qy = From p In db.Test Where p.Nome = If(ComboBox1.SelectedIndex = -1, p.Nome, CStr(ComboBox1.SelectedValue)) _ And (If(p.CF, "") = (CStr(IIf(TextBox1.Text = "", If(p.CF, ""), TextBox1.Text)))) Select p
Come potete vedere nella And specifichiamo If(p.CF,””) dove praticamente Linq lo traduce in t-sql usando la funzione COALESCE il che significa che dove il campo CF risulta NULL verrà rimpiazzato con un carattere vuoto che per il motore database è gestito diversamente dal valore NULL.
La seconda cosa che andiamo a fare è quella di controllare che il valore che mettiamo nella nostra casella di testo (per servircene come parametro) non sia vuoto, perchè se così fosse dobbiamo fare in modo che il confronto venga effettuato con la stesso identico operatore di sinistra (ovvero come se facessimo AND 1=1).
Per farlo mi sono servito di una Iif(expr,TruePart,FalsePart).
Se invece di voler utilizzare l’operatore di uguaglianza volessimo effettuare una Like sul parametro passato, allora la query link si semplifica ulteriormente eliminando un pò di If:
Dim qy = From p In db.Anagrafica Where p.Nome = If(ComboBox1.SelectedIndex = -1, p.Nome, CStr(ComboBox1.SelectedValue)) _ And If(p.CF, "").Contains(TextBox1.Text) Select p
Come potete vedere con la Like non c’è bisogno di ricontrollare se la nostra textbox sia vuota o meno.
Sinceramente non so se questo che ho utilizzato è il metodo migliore e il più pulito per poter recuperare anche i record a NULL, sinceramente in rete ho trovato molto poco, il che mi fa pensare che venga utilizzato sicuramente un altro approccio per fare la stessa cosa.
Ovviamente agendo lato sql server le possibilità sarebbero molte, si può creare una stored procedure e richiamarla da LINQ, oppure possiamo fare una vista della tabella che contiene i valore null e sostituirli con gli apici sfruttando la funzione ISNULL(CAMPO,”), oppure potremmo ancora mettere un default su campo in modo da non avere più valori NULL (quest’ultima soluzione la trovo un pò sporca soprattutto se nel db vengono utilizzate parecchie stored procedure che filtrano i valori a NULL con la sintassi standard Where Campo IS NULL in questa maniera ci sarebbe parecchio codice da andare a riscrivere 🙂 )
ottobre 15, 2011
· admin · 2 Comments
Tags: linq, LinqToSQL, SQL, SQL Server · Posted in: Coding, Develop, Programmazione, SQL
2 Responses
Adriana - febbraio 25, 2012
thanks for share!
Demetrius I. May - aprile 27, 2013
Se si utilizza questo parametro, non è possibile utilizzare il parametro PrimarySMTPAddress.
Leave a Reply