2017-01-23 6 views
1

Ich habe folgende Delegatendeklaration:zu Linq-Abfrage in EF Core-Passing Delegierten

_exclude = (subject) => 
    !subject.IsDeleted && subject.Location.Department.Company.GroupId.Equals(_groupId); 

Ziel ist es, die Wiederverwendung der:

private Func<Employee, bool> _exclude; 

dann an anderer Stelle in meinem Code ich den Wert auf diesen Satz über alle Abfragen filtern. Das funktioniert gut, wenn ich werde einen Mitarbeiter weist wie folgt materialisieren:

Employee theEmployee = db.Employees 
    .Include(e=>e.Location) 
    .ThenInclude(e => e.Department) 
    .ThenInclude(e => e.Company) 
    .Where(e => e.EmployeeId == EmployeeId && _exclude(e)) 
    .FirstOrDefault(); 

aber es funktioniert nicht, wenn ich wollte nur einen einzigen Wert abgerufen werden, wie zum Beispiel EmployeeId:

string employeeId = db.Employees 
    .Include(e=>e.Location) 
    .ThenInclude(e => e.Department) 
    .ThenInclude(e => e.Company) 
    .Where(e => e.EmployeeId == EmployeeId && _exclude(e)) 
    .Select(e => e.EmployeeId) 
    .FirstOrDefault(); 

Die oben schlägt fehl, eine NullReferenceException in der Func-Delegat _exclude, weil subject.Location-Wert ist Null, das bedeutet, dass der Mitarbeiter an den Delegaten übergeben ist nicht vollständig materialisiert gemäß Includes.

Was kann die Ursache dafür sein, dass das Mitarbeiterdiagramm erfolgreich erstellt wird, wenn ein vollwertiger Mitarbeiter benötigt wird, aber für die Projektionsabfrage fehlschlägt oder wie sollte die Abfrage in diesem Fall zusammengesetzt sein?

Ich bin mit EF-Core

+0

Überprüfen Sie die Daten, die Positionen dieser Mitarbeiter zu sehen, Sie sind vorbei, ich denke, was passiert ist, dass es nicht angebracht ist, ein Standort für einen Ihrer Mitarbeiter – Zinov

+0

@Zinov, jeder Mitarbeiter hat einen Standort, es ist Pflichtfeld im Backend. Denken Sie daran, dass es für den vollen Angestellten großartig funktioniert, wenn es nicht auch scheitern sollte. –

+0

Grund für die Verwendung von 'Func <...>' anstelle von 'Ausdruck >'? –

Antwort

3

Was kann die Ursache sein, dass es erfolgreich die Mitarbeiter Graph materialisieren, wenn ein vollwertiges Mitarbeiter benötigt wird, aber nicht für die Projektion Abfrage

In beiden Fällen ist die _exclude(e) wird nicht in SQL übersetzt, aber im Speicher ausgewertet, und es schlägt im zweiten Szenario wegen der Ignored includes und dem Mangel an Lazy Loading-Unterstützung fehl.

Es ist immer besser, Expression<Func<...>> zu verwenden, wenn möglich, weil sie in SQL übersetzt und auf Datenbankseite ausgewertet werden, so dass es keine Rolle spielt.

In Ihrem Fall ist es ganz einfach, die Art der _exclude Variable (die Lambda-Syntax der Zuweisung es bleibt gleich) und die Verwendung Where stattdessen auf && gekettet zu ändern:

private Expression<Func<Employee, bool>> _exclude; 

(Semantik basierend auf den Filter, es sollte wirklich _include oder _filter genannt werden, aber trotzdem)

und

_exclude = (subject) => 
    !subject.IsDeleted && subject.Location.Department.Company.GroupId.Equals(_groupId); 

Jetzt funktioniert das:

Employee theEmployee = db.Employees 
    .Include(e=>e.Location) 
    .ThenInclude(e => e.Department) 
    .ThenInclude(e => e.Company) 
    .Where(e => e.EmployeeId == EmployeeId) 
    .Where(_exclude) 
    .FirstOrDefault(); 

sowie das:

string employeeId = db.Employees 
    // not needed, but will not hurt if used, will be ignored anyway 
    //.Include(e=> e.Location) 
    //.ThenInclude(e => e.Department) 
    //.ThenInclude(e => e.Company) 
    .Where(e => e.EmployeeId == EmployeeId) 
    .Where(_exclude) 
    .Select(e => e.EmployeeId) 
    .FirstOrDefault();