2010-12-02 9 views
2

Gruppierung habe ich ein Hibernate Criteria-Objekt, das ich bauen thusly:Prevent Hibernate N + 1 Wählt, wenn sie von einer Entität

Criteria obsCriteria = hibernateTemplate.getSessionFactory() 
    .getCurrentSession().createCriteria(Observation.class); 

ProjectionList projection = Projections.projectionList() 
    .add(Projections.rowCount()) 
    .add(Projections.avg("value").as("avgScore")) 
    .add(Projections.avg("type.score")) 
    .add(Projections.max("date")) 
    .add(Projections.groupProperty("observedSubject")); 
criteria.setProjection(projection); 

Dies erzeugt ein korrektes Ergebnis für mich, aber die „observedSubject“ Eigentum ist eine Einheit. Wenn ich set_sql auf true setze, sah ich, dass nach der ersten Abfrage (die 18 Zeilen zurückgegeben hat) 18 selects vorhanden waren, um die observedSubject-Entitäten zu erhalten. Ich habe es versucht:

criteria.setFetchMode("observedSubject", FetchMode.JOIN); 

Aber das hat nicht funktioniert. Als eine Art Stich in der Dunkelheit versuchte ich:

criteria.createAlias("observedSubject", "observedSubject", Criteria.FULL_JOIN); 

Aber das hat auch nicht funktioniert. Gibt es eine Möglichkeit, dieses Verhalten zu verhindern?

Antwort

0

Haben Sie observedSubject zu FetchType.LAZY annotiert? Ist dies nicht der Fall, kehrt der Ruhezustand zum Standardverhalten zurück, dh EAGER wird abgerufen.

Wenn Sie wollen das Kind Vereinigung zur Laufzeit tun geholt, aber Sie wollen nicht getrennt SELECT Anrufe für jeden Verein, setzen @BatchSize über die Assoziation und Hibernate wird Batch die SELECT Anrufe, Dinge effizienter zu machen.

+0

Vielen Dank, dass Sie diese schlimme Frage beantwortet haben. Ich brauche die Daten im ObservedSubject - deshalb wird es zur Projektionsliste hinzugefügt. Ich habe die von Ihnen vorgeschlagene @BatchSize-Annotation ausprobiert, aber ich denke nicht, dass sie sich auf solche Anfragen bezieht, wenn Sie die Criteria-API verwenden, oder? Ein Ansatz, an den ich gedacht habe, war, eine Ansicht mit allen gewünschten Verknüpfungen (einschließlich der Felder des beobachteten Subjekts) zu erstellen und basierend auf dieser Ansicht eine unveränderbare Entität zu erstellen. Das spart die N + 1-Abfragen, aber es ist nicht sehr nah an dem, was ich vorher versucht habe, also frage ich mich immer noch, ob es einen Weg gibt, es zu tun. – jhericks

+0

Ja, '@ BatchSize' funktioniert für Kriterienabfragen. Ich habe '@BatchSize (size = 16)' auf die Get-Methode für eine untergeordnete Assoziation gesetzt, und Hibernate verwendet 'IN' (in Gruppen von 16) anstelle von' = 'beim Abrufen der untergeordneten Elemente. Die Art und Weise zu tun, ist es, zuerst die Eltern zu erhalten, und dann die Schleife auf der Liste, die Kinder bekommen: \t 'für (Parent T: Eltern) { \t \t if (! P.getChildren() = null) { \t \t \t p.getChildren(). Size(); // zwingt die Last \t \t} ' – atrain

+0

Der erste Teil Ihres Kommentars klingt wie, was ich will, aber dann bin ich durch diesen letzten Teil verwirrt. Das 'N' in 'N + 1' ist die Anzahl der Eltern in diesem Szenario, also wenn ich die Eltern durchlaufen muss, würde es immer noch die N + 1 Anfragen machen (so sah es für mich aus, nachdem ich mich beworben habe @BatchSize). – jhericks