Io uso EntityFramework con POCOs.
Supponiamo di avere POCO definiti come questo (semplificato):
class Class1
{
public int ID;
public int SomeNumber;
}
class Class2
{
public int ID;
public int SomeNumber;
}
class Class3
{
public int ID;
public int SomeNumber;
}
class SomeClass
{
public int ID;
public int? Class1ID;
public Class1 Class1;
public int? Class2ID;
public Class2 Class2;
public int? Class3ID;
public Class3 Class3;
}
Voglio recuperare tutti i record SomeClass
dal database, che appartengono a uno di Class1
, Class2
o Class3
dove ClassX.SomeNumber
equivale a un numero.
Ho scritto la query LINQ che assomiglia a questo:
Database DB = new Database(); // object context
var result = DB.SomeClass.ToList();
int SomeNumber = 1; // some number
List<SomeClass> retValue = result
.Where(x =>
{
int Number = 0;
if (x.Class1 != null)
Number = x.Class1.SomeNumber;
else if (x.Class2 != null)
Number = x.Class2.SomeNumber;
else if (x.Class3 != null)
Number = x.Class3.SomeNumber;
return Number == SomeNumber;
})
.ToList();
... tuttavia retValue
non contiene alcun record.
La soluzione
Apparentemente dovevo specificare .Include
istruzioni perché il caricamento lazy era disabilitato e x.Class1
, x.Class2
e x.Class3
avevano sempre il valore null
. Mi vergogno perché non ho dichiarato esplicitamente che il caricamento pigro era disabilitato - il problema sarebbe stato ovvio allora.
Tuttavia grazie al post di Ladislav, ho migliorato il mio codice in questo modo:
Database DB = new Database(); // object context
int SomeNumber = 1; // some number
List<SomeClass> retValue = DB.SomeClass
.Include("Class1")
.Include("Class2")
.Include("Class3")
.Where(x =>
SomeNumber == x.Class1.SomeNumber ||
SomeNumber == x.Class2.SomeNumber ||
SomeNumber == x.Class3.SomeNumber)
.ToList();
Non sapevo che le LINQ-to-Entities dovessero eseguire la coalescenza nulla automatica.
IMHO dovresti essere OK con questo:
Database DB = new Database();
var result = DB.SomeClass.Where(x =>
Number == x.Class1.SomeNumber ||
Number == x.Class2.SomeNumber ||
Number == x.Class3.SomeNumber)
.ToList();
La tua query carica tutti i dati e successivamente valuta la condizione in .NET = devi testare il valore nullo prima di accedere a SomeNumber
ma non è necessario se valuti SomeNumber
in SQL attraverso Linq-to-entities. Linq-to-entities dovrebbe eseguire coal coal null automatico.
Secondo la tua logica, se x.Class1 non è nullo, ma x.Class1.SomeNumber è 3, non controllerà tutte le altre clausole.
Se vuoi controllare, se solo alcuni ClassN.SomeNumber == SomeNumber
, dovresti farlo in questo modo:
int SomeNumber = 1; // some number
List<SomeClass> retValue = result
.Where(x =>
{
if (x.Class1 != null && x.Class1.SomeNumber == SomeNumber)
return true;
else if (x.Class2 != null && x.Class2.SomeNumber == SomeNumber)
return true;
else if (x.Class3 != null && x.Class3.SomeNumber == SomeNumber)
return true;
return false;
})
.ToList();