Utilizzare Linq per eseguire query per nodi terminali / foglia nel modello di tabella gerarchica / composito
-
03-07-2019 - |
Domanda
Ho una tabella autoreferenziale con ID, CategoryName e ParentId. È uno scenario tipico di una tabella gerarchica di categorie che possono essere divise in categorie che gli esperti di DB mi dicono che è chiamato modello di adiacenza.
Quello che voglio è usare Linq to SQL per cercare sottocategorie che a loro volta non sono correlate ad altre sottocategorie, cioè sono nodi foglia immediati di una determinata categoria o sottocategoria.
La parte facile, ho capito, è solo ottenere le sottocategorie. Quasi imbarazzato di inserire qui il codice. Ma ci piace vedere il codice ..
IList<Categories> subcategories = context.Where( c => c.ParentId == 1).ToList();
Ma restringerlo a categorie senza sottocategorie mi sta trasformando. Qualsiasi aiuto sarebbe molto apprezzato.
Grazie per l'aiuto. Jeff
UPDATE ** Sembrerebbe che funzioni, ma se qualcuno potesse confermare che è "corretto" Le sarei grato. Quindi, se voglio nodi foglia in una categoria con Id = 1, farei questo:
Categories.Where( c => !c.Children.Any ( d => d.ParentId == c.Id)).Where( e => e.ParentId == 1)
" Bambini " è il nome che Linq fornisce all'associazione autoreferenziale.
Soluzione
La tua soluzione è corretta poiché il metodo Any ()
si traduce in sql " EXISTS () " funzione
e ! c.Children.Any (d = > d.ParentId == c.Id))
si traduce in una clausola sql simile a NON ESISTE (SELEZIONA * DA Categorie DOVE ParentID = outerRef .ID)
Un altro modo per farlo è usare Count
:
Categories.Where( c => c.Children.Count(d => d.ParentId == c.Id) == 0).Where( e => e.ParentId == 1)
Ma di solito EXISTS () è preferito a COUNT () in sql (per motivi di prestazioni), quindi la soluzione con Any () dovrebbe essere quella giusta.
Altri suggerimenti
Penso che se capisco correttamente la tua domanda stai cercando di ottenere tutti gli elementi figlio che non hanno figli di loro ... questa query si unisce alla tabella su se stessa per verificare se il nodo viene usato come genitore , in caso contrario, viene visualizzato nel risultato.
Non sono sicuro che funzioni perché non ho nulla su cui testarlo ...
(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()