Je construis une application WPF en utilisant Visual Studio 2015 contre Entity Framework 6 et SQL Server 2008. J'ai ces deux tables:
Employee ----------------------------- EmployeeId FirstName LastName ... other columns EmployeeStatus ----------------------------- EmployeeStatusId EmployeeId (Foreign Key to Employee.EmployeeId) ValidEmployeeStatusId
L'application doit récupérer tous les employés dont EmployeeStatus.ValidEmployeeStatusId
n'est pas 2 et non 4 (Inactif et Absence). J'ai écrit cette requête LINQ, mais elle s'exécute pour toujours et ne renvoie jamais aucun résultat:
var query = (from e in context.Employees from es in context.EmployeeStatus .Where(x => e.employeeID == x.employeeID && (x.validEmployeeStatusID != 2 && x.validEmployeeStatusID != 4) .DefaultIfEmpty() select new EmployeeViewModel { EmployeeId = e.employeeID, /* set other properties*/ }); return await Task.Run(() => new ObservableCollection<EmployeeViewModel>(query));
Qu'est-ce que je fais mal?
Mise à jour : J'ai découvert ce qui me tue sur la lenteur … Chaque EmployeeViewModel
appelait la database dans son ctor pour peupler certaines ObservableCollections. Transformé ces propriétés en static
et ajouté un static bool
; si c'est faux, remplissez les propriétés et définissez bool sur true. Toutes les instances utilisent donc les mêmes données pour les propriétés qui appelaient la database. Pour ~ 4000 loggings, c'était beaucoup d'appels.
Vous pouvez get le résultat souhaité avec une jointure à gauche.
var query = (from e in context.Employees join es in context.EmployeeStatus on e.employeeID equals es.employeeID into empStatuses from emps in empStatuses.DefaultIfEmpty() where emps.validEmployeeStatusID != 2 && emps.validEmployeeStatusID != 4 select new EmployeeViewModel { EmployeeId = e.employeeID, /* set other properties*/ });
Je pense que vous n'avez pas besoin d'effectuer une join
Essayez cette requête
var query = (from e in context.Employees where e.EmployeeStatus.validEmployeeStatusID != 2 && e.EmployeeStatus.validEmployeeStatusID != 4 select new EmployeeViewModel { EmployeeId = e.employeeID, /* set other properties*/ });
Vous pouvez essayer !Any
requête LINQ basée qui devrait être traduite en requête SQL NOT EXISTS
, qui est une bonne alternative à une jointure de nos jours. De plus, il évite la duplication d'loggings d'employés qui se produit lors de l'utilisation de jointures.
var query = (from e in context.Employees where !context.EmployeeStatus.Any(s => e.employeeID == s.employeeID && (s.validEmployeeStatusID == 2 || s.validEmployeeStatusID == 4)) select new EmployeeViewModel { EmployeeId = e.employeeID, /* set other properties*/ });
Vous pouvez également essayer la version de jointure suivante (en fait antijoin ) de la requête:
var query = (from e in context.Employees join s in context.EmployeeStatus .Where(x => x.validEmployeeStatusID == 2 || x.validEmployeeStatusID == 4)) on e.employeeID equals s.employeeID into statusGroup from s in statusGroup.DefaultIfEmpty() where s == null select new EmployeeViewModel { EmployeeId = e.employeeID, /* set other properties*/ });