2009-08-03 4 views
7

Ich habe eine rekursive Eins-zu-viele-Beziehung, die den Standard-Lazy-Wert von True hat. Welchen Code kann ich gegen die NH-API schreiben, die den ENTIRE-Baum effizient abruft, WENN ich im SubCategories-Mapping lazy = "false" hätte?Eagerly laden rekursive Beziehung

Hier ist die rekursive einer Eins-zu-viele-Beziehung:

<class name="Category" lazy="false"> 
    ... 
    <list name="SubCategories" fetch="subselect"> 
      <key column="ParentCategoryID"/> 
      <index column="PositionInList"/> 
      <one-to-many class="Category"/> 
    </list> 

ich nicht angeben faul = „false“ auf der Liste, da Faulheit ist in etwa der Hälfte der Anfragen erforderlich ich ausführen müssen. Ich habe fetch = "subselect" auf der Liste als eine Optimierung für, wenn es mir gelingt, den gesamten Baum abzurufen.

Ich habe die ICriteria API versucht:

session.CreateCriteria<Category>().SetFetchMode("SubCategories", FetchMode.Eager).Add(Restrictions.IsNull("ParentCategory")).SetResultTransformer(CriteriaSpecification.DistinctRootEntity).List<Category>(); 

aber, dass nur eifrig nur die erste Stufe in der Hierarchie geladen.

Antwort

8

See Ayende Website: Efficiently Selecting a Tree. Ich habe diese Technik erfolgreich in meinen eigenen Anwendungen verwendet. Mit ICriteria, sieht es wie folgt aus:

session.CreateCriteria<Category>() 
    .SetFetchMode("SubCategories", FetchMode.Join) 
    .SetResultTransformer(new DistinctRootEntityResultTransformer()) 
    .List<Category>() 
    .Where(x => x.ParentCategory == null); 

Der wesentliche Unterschied zwischen dieser Version und was Sie versucht ist, wie die „parent == null“ Filter angewendet wird. Es muss von der Abfrage weggelassen werden, die an die Datenbank gesendet wird, um die gesamte Struktur abzurufen - aber wir brauchen die Abfrage, um nur die Wurzelknoten der Struktur zurückzugeben, also verwenden wir linq, um diese nach der zu finden Datenbankabfrage wurde abgeschlossen.

0

nicht sicher, ob es aber einen Blick auf hilft nehmen: map a tree in NHibernate

+0

Ja, das ist ein nützlicher Artikel und ich habe es bereits gelesen. Als ich vor einigen Monaten das schnelle Laden von Bäumen untersuchte, fand ich den Abschnitt "Eager Load Vorfahren und Nachkommen" relevant. Meine Datenbank ist jedoch SQL Compact und unterstützt keine CTEs (hierarchische Abfragen). Eine einzelne Abfrage zu schreiben, die das Problem löst, ist daher unmöglich. – HappyNomad

1

Ich benutzte Daniels Code als Basis für die Lösung des Problems. Ich experimentierte auch mit der äquivalenten HQL, die ich unten geteilt habe. Die HQL lief etwas schneller, aber ich ging mit ICriteria, da ich dann zwischen FetchModel.Join und FetchModel.Lazy wählen konnte.

session.CreateQuery("from Category as c left join fetch c.SubCategories") 
    .SetResultTransformer(new DistinctRootEntityResultTransformer()) 
    .List<Category>() 
    .Where(c => c.ParentCategory == null);