Problème de hiérarchie - > Remplacer la récursion par Linq Join?
-
07-07-2019 - |
Question
J'ai une table auto-référentielle, qui a l'ID, ParentID (nullable).
La table contient donc de nombreux nœuds. Chaque nœud peut être la racine de la hiérarchie (le parent est nul) ou n’importe quel niveau de la hiérarchie (le parent existe ailleurs dans la table).
Étant donné un nœud de départ arbitraire, existe-t-il une élégante requête linq qui renverra tous les enfants de la hiérarchie à partir de ce nœud?
Merci.
La solution
Si vous souhaitez sélectionner tous les enfants directs d'un nœud, une requête simple, similaire à celle-ci, devrait faire l'affaire:
from item in table
where item.ID == parentID;
select item
Si vous souhaitez sélectionner tous les descendants d'un nœud, cela n'est pas possible avec LINQ, car il nécessite une récursivité ou une pile non fournie par LINQ (et SQL).
Voir aussi:
- StackOverflow: LINQ to SQL pour les tables à auto-référencement?
- CodeProject: T-SQL - Comment obtenir tous les descendants d’un élément donné dans un table hiérarchique
- StackOverflow: Exprimer la récursivité dans LINQ
Autres conseils
En voici un rapide, je viens d'écrire:
class MyTable
{
public int Id { get; set; }
public int? ParentId { get; set; }
public MyTable(int id, int? parentId) { this.Id = id; this.ParentId = parentId; }
}
List<MyTable> allTables = new List<MyTable> {
new MyTable(0, null),
new MyTable(1, 0),
new MyTable(2, 1)
};
Func<int, IEnumerable<MyTable>> f = null;
f = (id) =>
{
IEnumerable<MyTable> table = allTables.Where(t => t.Id == id);
if (allTables
.Where(t => t.ParentId.HasValue && t.ParentId.Value == table
.First().Id).Count() != 0)
return table
.Union(f(
allTables.Where(t => t.ParentId.HasValue && t.ParentId.Value == table
.First().Id).First().Id));
else return table;
};
Mais je pense qu'il est possible d'utiliser SQL avec un Union ALL.
Je sais que c'est un ancien message, mais vous devriez jeter un coup d'œil à cette extension:
http://www.scip.be/index.php?Page=ArticlesNET23
Je l'utilise et cela fonctionne très bien.
Fondamentalement, je vais avec quelque chose comme ceci, comme indiqué dans le lien SO que vous avez proposé.
public IQueryable GetCategories(Category parent)
{
var cats = (parent.Categories);
foreach (Category c in cats )
{
cats = cats .Concat(GetCategories(c));
}
return a;
}
Les CTE sont probablement la meilleure solution, mais j'aimerais garder les choses dans le même niveau pour l'instant.