LINQ to SQL pour les tables auto-référencées ?
-
09-06-2019 - |
Question
J'ai une table Catégories auto-référencée.Chaque catégorie a un CategoryID, un ParentCategoryID, un CategoryName, etc.Et chaque catégorie peut avoir n'importe quel nombre de sous-catégories, et chacune de ces sous-catégories peut avoir n'importe quel nombre de sous-catégories, et ainsi de suite.Donc, fondamentalement, l’arbre peut avoir une profondeur de X niveaux.
Ensuite, les produits sont associés aux (sous) catégories feuilles.Existe-t-il un moyen d'obtenir tous les produits d'une catégorie donnée (qui seraient tous les produits associés à tous ses descendants feuilles) à l'aide de LINQ to SQL ?
Cela ressemble à un problème récursif.Vaut-il mieux utiliser une procédure stockée à la place ?
La solution
Je ne pense pas que Linq-to-sql ait une bonne réponse à ce problème.Puisque vous utilisez SQL Server 2005, vous pouvez utiliser les CTE pour effectuer des requêtes hiérarchiques.Une procédure stockée ou une requête en ligne (utilisant DataContext.ExecuteQuery) fera l'affaire.
Autres conseils
Eh bien, voici une implémentation terriblement précipitée utilisant LINQ.N'utilisez pas ça :-)
public IQueryable GetCategories(Category parent)
{
var cats = (parent.Categories);
foreach (Category c in cats )
{
cats = cats .Concat(GetCategories(c));
}
return a;
}
L'approche performante consiste à créer un déclencheur d'insertion/modification/suppression qui maintient une table entièrement différente contenant des paires nœud-ancêtre pour tous les ancêtres de tous les nœuds.De cette façon, la recherche est O(N).
Pour l'utiliser pour obtenir tous les produits appartenant à un nœud et tous ses descendants, vous pouvez simplement sélectionner tous les nœuds de catégorie qui ont votre nœud cible comme ancêtre.Après cela, il vous suffit de sélectionner tous les produits appartenant à l’une de ces catégories.
La façon dont je gère cela consiste à utiliser certaines méthodes d'extension (filtres).J'ai rédigé un exemple de code à partir d'un projet sur lequel je l'ai implémenté.Regardez spécifiquement les lignes où je remplis un objet ParentPartner et une liste de sous-partenaires.
public IQueryable<Partner> GetPartners()
{
return from p in db.Partners
select new Partner
{
PartnerId = p.PartnerId,
CompanyName = p.CompanyName,
Address1 = p.Address1,
Address2 = p.Address2,
Website = p.Website,
City = p.City,
State = p.State,
County = p.County,
Country = p.Country,
Zip = p.Zip,
ParentPartner = GetPartners().WithPartnerId(p.ParentPartnerId).ToList().SingleOrDefault(),
SubPartners = GetPartners().WithParentPartnerId(p.PartnerId).ToList()
};
}
public static IQueryable<Partner> WithPartnerId(this IQueryable<Partner> qry, int? partnerId)
{
return from t in qry
where t.PartnerId == partnerId
select t;
}
public static IQueryable<Partner> WithParentPartnerId(this IQueryable<Partner> qry, int? parentPartnerId)
{
return from p in qry
where p.ParentPartner.PartnerId == parentPartnerId
select p;
}