Bonjour à vous, Geeks !
me voici toujours entrain de me dépatouiller avec mes histoires de récursivité. Voici donc mon souci : tout d’abord les entités :

But : Je souhaite créer un TreeView (WPF) qui permet affiche de façon les employés.
J’ai donc une classe GroupEmployee qui récupère les employés :
public class GroupEmployee
{
public object Key { get; set; }
public int Count { get; set; }
public IEnumerable<GroupEmployee> SubEmployees { get; set; }
}
Maintenant mon souci c’est de trouver la requête pour peupler (enfin itérer sur) SubEmployees :
[code] var context = new DataClasses1DataContext();
var employees = context.Employees.ToList();
var query = from emp in employees
group emp by emp.EmployeeID into g
select new GroupEmployee { Key = g.Key, Count = g.Count(), SubEmployees=...};[/code]
Mais qu’est-ce que je mets pour SubEmployees ?
C’est à ce moment que j’implore votre aide :crying:
En tout cas, Merci 
EDIT : il manquait le diagramme…
Va voir du côté des CTE sous Sql Server 2005, c’est un type de requête qui permet la récursivité.
Par contre je doute que ca puisse être attaqué avec Linq to Sql, donc tu risques de devoir charger tes données à la main.
Sinon, pourquoi tu ne charges pas tout le beau monde dans une liste, que tu parcours ensuite pour créer ta hiérarchie ? Pas forcément plus complexe que de tout vouloir mettre dans ta requête Linq (et risquer de se retrouver avec du sql spaghetti)
T’as un bel exemple d’énumérateur capable d’utiliser une fonction de récursivité à la fin de ce message sur les forums MSDN.
Euh, pour moi, ton group by est foireux…
ce serait pas plutot “group emp by emp.ReportsTo into g” ?
Sinon, personnellement je ne m’y prendrais pas comme ca, mais plutot un truc du genre:
[code][…]
var rootEmployees = from emp in allEmployees
where emp.ReportsTo = null
select new EmployeeNode { Data = emp, ReportingEmployees = BuildReportingEmployeesFromPreloadedEmpList(emp, allEmployees)};
[…]
IEnumerable BuildReportingEmployeesFromPreloadedEmpList(Employee emp, List empCache)
{
return from subEmp in empCache
where subEmp.ReportsTo = emp
select new EmployeeNode { Data = emp, ReportingEmployees = BuildReportingEmployeesFromPreloadedEmpList(emp, empCache)};
}[/code]
L’avantage, c’est que si tu utilises un controle virtualisé, ton arbre se construira au fur et à mesure que tu déplies les noeuds (voir le blog de Beatriz Costa, pour les détails de comment tu virtualise un treeview).
[edit]Tab + espace, ca fait poster prématurément ^^[/edit]
Ah ouai nickel c’est exactement ça ! Effectivement j’étais dans les choux avec mon histoire de Group By… C’est effectivement un emp.ReportsTo qui m’intéressait. En revanche j’ai toujours un souçi avec la récursivité (décidément), je n’arrive pas à générer le paramètre empCache dans la méthode :
[code]var context = new DataClasses1DataContext();
var allEmployees = context.Employees.ToList();
var rootEmployees = from emp in allEmployees
where emp.ReportsTo == null
select new EmployeeNode { Data = emp, ReportingEmployees = BuildReportingEmployeesFromPreloadedEmpList(emp, allEmployees) };
this.DataContext = rootEmployees;
}
IEnumerable BuildReportingEmployeesFromPreloadedEmpList(Employee emp, List empCache)
{
return from subEmp in empCache
where subEmp.ReportsTo == emp.EmployeeID
select new EmployeeNode { Data = emp, ReportingEmployees = BuildReportingEmployeesFromPreloadedEmpList(emp, empCache) };
}[/code]
Pour l’instant ça me fait un Treeview infini (normal puisque empCache correspond toujours à allEmployees). Il faudrait que j’arrive à construire la liste des employees de emp
EDIT : petite coquille dans le code…
Ton treeview n’est pas infini, au bout d’un moment, tu dois tomber sur des employee dont aucun autre “Reports to” ^^
En fait, voilà ce que ça me donne :

et le xaml associé :
[code]
<Window.Resources>
<HierarchicalDataTemplate DataType="{x:Type local:EmployeeNode}" ItemsSource="{Binding ReportingEmployees}">
<TextBlock Text="{Binding Path=Data.FirstName}" />
</HierarchicalDataTemplate>
</Window.Resources>
<DockPanel>
<TreeView Width="500" x:Name="EmployeesTree" DockPanel.Dock="Left" ItemsSource="{Binding}" />
</DockPanel>
[/code]
Au temps pour moi :
[code]IEnumerable BuildReportingEmployeesFromPreloadedEmpList(Employee emp, List empCache)
{
return from subEmp in empCache
where subEmp.ReportsTo == emp.EmployeeID
select new EmployeeNode { Data = emp, ReportingEmployees = BuildReportingEmployeesFromPreloadedEmpList(emp, empCache) };
}
doit devenir
IEnumerable BuildReportingEmployeesFromPreloadedEmpList(Employee emp, List empCache)
{
return from subEmp in empCache
where subEmp.ReportsTo == emp.EmployeeID
select new EmployeeNode { Data = subEmp, ReportingEmployees = BuildReportingEmployeesFromPreloadedEmpList(subEmp, empCache) };
}[/code]
Ok, bah merci beaucoup parce que je commençais à avoir une calvitie :)) En effet, j’avais bien mis le subEmp dans la méthode BuildReportingEmployeesFromPreloadedEmpList, mais j’avais laissé Data = emp, au lieu subEmp… quel busard…
Thx !