2008-10-25 8 views
4

Étant donné un EmployeeId, comment puis-je construire une requête Linq to Sql pour trouver tous les ancêtres de l'employé? Chaque EmployeeId a un SupervisorId associé (voir ci-dessous). Par exemple, une requête des ancêtres de EmployeeId 6 (Frank Black) doit renvoyer Jane Doe, Bob Smith, Joe Bloggs et Head Honcho.Linq to Sql - Requête hiérarchique pour trouver des ancêtres

Si nécessaire, je peux mettre en cache la liste de tous les employés pour améliorer les performances.

MISE À JOUR:

J'ai créé la méthode brute suivante pour accomplir la tâche. Il traverse la relation employee.Supervisor jusqu'au noeud racine. Cependant, cela lancera un appel de base de données pour chaque employé. Quelqu'un a une méthode plus succincte ou plus performante? Merci.

private List<Employee> GetAncestors(int EmployeeId) 
{ 
    List<Employee> emps = new List<Employee>(); 
    using (L2STestDataContext dc = new L2STestDataContext()) 
    { 
     Employee emp = dc.Employees.FirstOrDefault(p => p.EmployeeId == EmployeeId); 
     if (emp != null) 
     { 
      while (emp.Supervisor != null) 
      { 
       emps.Add(emp.Supervisor); 
       emp = emp.Supervisor; 
      } 
     } 
    } 
    return emps; 
} 

Répondre

1

Tout d'abord, vous êtes invités à utiliser les requêtes hiérarchiques dans mon LINQ Extension Methods project. Je pense que cela pourrait vous aider à simplifier votre code.

Le problème ici est que cela créera un appel de base de données pour chaque nœud de la hiérarchie. Dans le cas de votre exemple, vous aurez 5 allers-retours à la base de données.

Je voudrais aller un chemin différent et créer une procédure stockée pour le faire pour moi et retourner l'ensemble des objets Employee. Puisque vous déconnectez les objets avant de les renvoyer (en supprimant le contexte), vous pouvez simplement créer un nouvel objet à partir du jeu de résultats de la procédure stockée.

1

Une solution simple qui évite de charger toute la table des employés (mais a une profondeur de traversal limitée) est ...

var emps = dc.Employees.Where(e => (e.EmployeeId == EmployeeId) || 
            (e.SupervisorId == EmployeeId) || 
            (e.Supervisor.SupervisorId == EmployeeId) || 
            (e.Supervisor.Supervisor.SupervisorId == EmployeeId) || 
            ...); 

En fin de compte, vous devez utiliser un common table expression pour aplatir la hiérarchie, mais LINQ to SQL doesn ne supporte pas actuellement cela. Vous pourriez envisager d'écrire votre propre méthode d'extension (comme celle de la bibliothèque d'Omer mais en utilisant IQueryable au lieu de IEnumerable pour supporter l'exécution côté serveur).