4 Stimmen

Grails N+1 Abfrage

Meine Grails-App verwendet die Spring Security und hat die üblichen User, UserRole und Role Klassen. Die Art und Weise, wie diese Klassen modelliert sind, ist etwas ungewöhnlich, da es keine hasMany Zuordnungen in User oder Role gibt. Stattdessen werden die Klassen ausschließlich durch UserRole referenziert.

class UserRole implements Serializable {
  User user
  Role role
}

Mein Verständnis ist, dass die Beziehung aus Leistungsgründen so modelliert wurde, speziell um die Möglichkeit von N+1 Abfragen zu reduzieren.

In einem Teil meiner Anwendung muss ich alle Benutzer und ihre Rollen laden. Bewusst für das vorher genannte Problem versuchte ich es so:

def usersByRole = UserRole.createCriteria().list {
  fetchMode("user", FetchMode.JOIN)
  fetchMode("role", FetchMode.JOIN)
}

Jedoch, wenn ich auf die User-Objekte zugreifen möchte

usersByRole.each { it.user }

Wird eine separate Abfrage ausgegeben, um die Daten aus der User Tabelle abzurufen, wodurch ich genau auf das Problem stoße, das ich zu vermeiden versucht habe. Ich habe auch das Folgende versucht, allerdings leidet es unter dem gleichen Problem.

def usersByRole = UserRole.createCriteria().list {
  fetchMode("user", FetchMode.SELECT)
  fetchMode("role", FetchMode.SELECT)
}

Ich muss gestehen, dass ich nicht ganz klar über den Unterschied zwischen FetchMode.JOIN und FetchMode.SELECT bin. Falls also jemand mich darüber aufklären könnte, wäre es dankbar.

6voto

Burt Beckwith Punkte 74817

Ich habe mehrere Kombinationen ausprobiert, aber die Ergebnisse waren dieselben - wenn Sie sich den generierten SQL ansehen, gibt es kein Join in der ursprünglichen Abfrage, daher müssen zusätzliche Abfragen ausgeführt werden, um die Benutzer und Rollen zu laden.

Andere hatten Probleme mit dieser Domain-Klasse - es scheint, als gäbe es einen Fehler in GORM mit einem zusammengesetzten Schlüssel, der aus Domain-Klassen besteht, oder so etwas Ähnlichem. Normalerweise sind die Leute mit einem HQL-Workaround zufrieden, und hoffentlich werden Sie es auch sein :)

def usersByRole = UserRole.executeQuery(
   'select ur from UserRole ur ' +
   'left join fetch ur.user ' +
   'left join fetch ur.role')

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X