2009-06-02 12 views
24

Ich möchte Stammelemente laden und eifrig laden alle untergeordnete Sammlung und aggregierte Mitglieder.Eager Laden untergeordneten Sammlung mit NHibernate

habe versucht, die SetFetchMode in FluentNHibernate zu verwenden, aber ich bin Duplikate in einer der Kinder Sammlung bekommen, da ich eine Tiefe von 3 Ebenen haben. DistinctRootEntityResultTransformer löscht leider nur die Wurzelduplikationen.

Könnte ich Multi-Abfragen oder ähnliches verwenden, um dies zu archivieren?

Würde dieser Ansatz nicht zu unnötig großen Resultsets aus der Datenbank führen?

Irgendwelche Vorschläge?

Antwort

0

Während es nicht genau das, was Sie suchen, würde ich in diesem Artikel suchen empfehlen:

Eager loading aggregate with many child collections

Wenn man sich den Rest der Website schauen, werden Sie noch mehr Beiträge finden, die diskutieren eifriges Laden und andere großartige nHibernate-Sachen.

+2

In der Tat ein guter Artikel, aber unsicher, ob ich es auf meine Situation anwenden kann. Die Lösung, die im Artikel über das eifrige Laden einer spezifischen root-Entität beschrieben wird, ist mein Problem, dass ich eifrig eine Sammlung von root-Entitäten laden möchte. Wenn ich MultiCritera verwenden möchte, muss ich eine Möglichkeit finden, alle verschiedenen Abfragen zu verbinden, ohne eine bestimmte Entität anzugeben. Vorschläge wie das gemacht werden kann? – Kristoffer

+0

Dieses Beispiel hat nur eine zusätzliche Hierarchieebene, aber keine Enkelkinder, für die MultiQuery/MultiCriteria anscheinend nutzlos ist, da spätere Abfragen keine Ergebnisse früherer Abfragen referenzieren können (wie Abfrage # 1: rootObjects auswählen r link Join fetch children c wo ...; Abfrage # 2: wähle Enkelkinder g, wo Eltern in c). –

8

Eine Lösung gefunden, aber es ist nicht schön. Zuerst gehe ich und finde alle Rechnungs-IDs, dann verwende ich sie in der Multiquery und dann am Ende die Ergebnisse durch ein HashedSet filtern. Wegen der großen Anzahl von Elementen konnte ich manchmal das normale Restriction.In nicht verwenden und musste es als String senden.

Alle vorgeschlagenen Optimierungen?

var criteria = Session.CreateInvoiceBaseCriteria(query, archived) 
    .SetProjection(Projections.Id()); 

var invoiceIds = criteria.List<int>(); 
if (invoiceIds.Count > 0) 
{ 
    var joinedIds = JoinIDs(criteria.List<int>()); // To many ids to send them as parameters. 

    var sql1 = string.Format("from Invoice i inner join fetch i.States where i.InvoiceID in ({0}) order by i.{1} {2}", joinedIds, query.Order, query.OrderType.ToString()); 
    var sql2 = string.Format("from Invoice i inner join fetch i.AttestationRequests where i.InvoiceID in ({0})", joinedIds); 
    var sql3 = string.Format("from Invoice i inner join fetch i.Attestations where i.InvoiceID in ({0})", joinedIds); 

    var invoiceQuery = Session.CreateMultiQuery() 
     .Add(sql1) 
     .Add(sql2) 
     .Add(sql3); 

    var result = invoiceQuery.List()[0]; 

    return new UniqueFilter<Invoice>((ICollection)result); 
} 

return new List<Invoice>(); 
+0

Das ist seltsam, Attests werden als einzelne Abfragen abgerufen. – Kristoffer

+0

+1, Es ist tatsächlich (und leider) der beste Weg (Performance-weise), dies zu erreichen. –

+0

Ich bin in einer ähnlichen Situation (versuche 3 Levels auf einmal zu ziehen). Obwohl Ihre Lösung die Duplikate entfernt, scheint sie nur 2 Ebenen tief zu sein. Ihre ursprüngliche Frage enthielt eine dritte Ebene namens "AttestationRequests.Reminders", die nicht in Ihrer Antwort enthalten ist. – MylesRip

2

Um Ihre Frage zu beantworten: Ja, es führt zu großen Resultsets.

Ich schlage vor, zu:

  • naiverweise nur Ihre Anfragen schreiben, ohne eifrig
  • An bestimmten Orten zu holen, legte ein eifriger holen, aber nur eine pro Abfrage
  • wenn Sie wirklich Performance-Probleme erhalten, die Sie Lösen Sie nicht mit Indizes oder erweitern Sie Abfragen und Mapping-Strategien. Verwenden Sie Ihre Lösung mit den mehreren Abfragen.
Verwandte Themen