Ich verwende EntityFramework mit POCOs.
Angenommen, ich habe POCOs wie folgt definiert (vereinfacht):
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;
}
Ich möchte alle SomeClass
Datensätze aus der Datenbank SomeClass
, die entweder zu Class1
, Class2
oder Class3
wobei ClassX.SomeNumber
einer Zahl entspricht.
Ich habe die LINQ-Abfrage geschrieben, die folgendermaßen aussieht:
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();
... aber retValue
enthält keinen Datensatz.
Die Lösung
Anscheinend musste ich .Include
Anweisungen angeben, weil Lazy Loading deaktiviert war und x.Class1
, x.Class2
und x.Class3
immer den null
. Ich schäme mich, weil ich nicht ausdrücklich gesagt habe, dass Lazy Loading deaktiviert war - das Problem wäre dann offensichtlich gewesen.
Dank Ladislavs Post habe ich meinen Code jedoch so verbessert:
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();
Ich wusste nicht, dass LINQ-to-Entities eine automatische Null-Koaleszenz durchführen sollten.
IMHO sollten Sie mit diesem gerade einverstanden sein:
Database DB = new Database();
var result = DB.SomeClass.Where(x =>
Number == x.Class1.SomeNumber ||
Number == x.Class2.SomeNumber ||
Number == x.Class3.SomeNumber)
.ToList();
Ihre Abfrage lädt alle Daten, und nachdem Sie die Bedingung in .NET ausgewertet haben, müssen Sie vor dem Zugriff auf SomeNumber
Nullwert testen. SomeNumber
ist jedoch nicht erforderlich, wenn Sie SomeNumber
in SQL über Linq-to-Entities auswerten. Linq-to-Entities sollten ein automatisches Null-Coalescing durchführen.
Entsprechend Ihrer Logik gilt: Wenn x.Class1 nicht null ist, aber x.Class1.SomeNumber = 3, werden alle anderen Klauseln nicht geprüft.
Wenn Sie überprüfen möchten, ob nur einige ClassN.SomeNumber == SomeNumber
, dann sollten Sie dies folgendermaßen tun:
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();