質問
自己参照のカテゴリテーブルがあります。各カテゴリには、CategoryID、ParentCategoryID、CategoryName などが含まれます。各カテゴリには任意の数のサブ カテゴリを含めることができ、それらのサブ カテゴリにはそれぞれ任意の数のサブ カテゴリを含めることができます。したがって、基本的にツリーの深さは X レベルになります。
次に、製品がリーフ (サブ) カテゴリに関連付けられます。LINQ to SQLを使用して、特定のカテゴリのすべての製品(すべてのリーフ子孫に関連付けられたすべての製品)を取得する方法はありますか?
これは再帰的な問題のように感じます。代わりにストアド プロシージャを使用した方がよいでしょうか?
解決
linq-to-sql がこの問題に対する適切な答えを持っているとは思えません。SQL Server 2005 を使用しているため、CTE を使用して階層クエリを実行できます。ストアド プロシージャまたはインライン クエリ (DataContext.ExecuteQuery を使用) のいずれかが機能します。
他のヒント
さて、ここに LINQ を使用したひどい急ぎの実装があります。これは使用しないでください:-)
public IQueryable GetCategories(Category parent)
{
var cats = (parent.Categories);
foreach (Category c in cats )
{
cats = cats .Concat(GetCategories(c));
}
return a;
}
パフォーマンスの高いアプローチは、すべてのノードのすべての祖先のノードと祖先のペアを含むまったく異なるテーブルを維持する挿入/変更/削除トリガーを作成することです。このように、ルックアップは O(N) になります。
ノードに属するすべての製品とそのすべての子孫を取得するためにこれを使用するには、ターゲット ノードを祖先として持つすべてのカテゴリ ノードを選択するだけです。その後、これらのカテゴリのいずれかに属する製品を選択するだけです。
これを処理する方法は、いくつかの拡張メソッド (フィルター) を使用することです。これを実装したプロジェクトからいくつかのサンプルコードを作成しました。特に、ParentPartner オブジェクトと SubPartners List を設定している行に注目してください。
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;
}