Linqを使用して、階層テーブル/複合パターンのターミナル/リーフノードを照会する
-
03-07-2019 - |
質問
Id、CategoryName、およびParentIdを持つ自己参照テーブルがあります。これは、DBの専門家が隣接モデルと呼ばれると言っているカテゴリに分割できるカテゴリの階層テーブルの典型的なシナリオです。
私が欲しいのは、Linq to SQLを使用して、それ自体が他のサブカテゴリに関連しないサブカテゴリ、つまり特定のカテゴリまたはサブカテゴリの直接の葉ノードであるサブカテゴリを照会することです。
簡単な部分は、サブカテゴリを取得することです。ここにコードを置くのはほとんど恥ずかしいです。しかし、私たちはコードを見たいです。.
IList<Categories> subcategories = context.Where( c => c.ParentId == 1).ToList();
しかし、サブカテゴリのないカテゴリに絞り込んでいると、方向転換します。どんな助けでも大歓迎です。
ご協力ありがとうございます。 ジェフ
更新** これは動作しているように見えますが、誰かがそれが「適切」であることを確認できれば、ありがたいです。したがって、Id = 1のカテゴリの下にリーフノードが必要な場合、次のようにします。
Categories.Where( c => !c.Children.Any ( d => d.ParentId == c.Id)).Where( e => e.ParentId == 1)
&quot;子供&quot; Linqが自己参照アソシエーションに与える名前です。
解決
Any()
メソッドはsql&quot; EXISTS()&quot;に変換されるため、ソリューションは正しいです。関数
および!c.Children.Any(d =&gt; d.ParentId == c.Id))
は、 NOT EXISTS(SELECT * FROM Categories WHERE ParentID = outerRef .ID)
別の方法は、 Count
を使用することです:
Categories.Where( c => c.Children.Count(d => d.ParentId == c.Id) == 0).Where( e => e.ParentId == 1)
ただし、通常、EXISTS()はSQLのCOUNT()よりも優先されるため(パフォーマンス上の理由から)、Any()を使用したソリューションが正しいはずです。
他のヒント
私はあなたの質問を正しく理解すると、自分の子を持たないすべての子要素を取得しようとしていると思います...このクエリ自己は、ノードが親として使用されているかどうかをテストするために自分自身でテーブルを結合します、そうでない場合は結果に表示されます。
テストするものがないため、これが機能するかどうかはわかりません...
(from c in context
join cc in context on c.id equals cc.parentid into temp
from t in temp.DefaultIfEmpty()
where t == null
select c).ToList()