Criteria List Queries bei Many-To-Many Beziehungen in Grails
Einleitung
In diesem Beitrag wird gezeigt, wie n:m Beziehungen in Grails (Stichwort 'hasMany') innerhalb einer Query abgefragt werden können.
Als Beispiel betrachten wir die Beziehung zwischen einer Person und eines Projekts. Eine Person kann in mehreren Projekten involviert sein. In einem Projekt arbeiten wiederum mehrere Personen. Die Modellierung in Domain-Klassen könnte wie folgt (vereinfacht) aussehen:
class Person {
String firstname
String lastname
static hasMany = [projects:Project]
}
class Project {
String name
static hasMany = [persons:Person]
}
Datenbank-Abfragen
Im Folgenden sollen zwei Abfragen betrachtet werden:
- Liefere alle Personen, deren Vorname "Max" oder "Moritz" ist.
- Liefere alle Projekte, bei welchen Personen mit Vorname "Max" oder "Moritz" beteiligt sind.
Die erste Abfrage kann einfach mit dem dynamischen Finder findAllBy*InList [1] in Grails realisiert werden.
def firstnames = ["Max", "Moritz"]
def result = Person.findAllByFirstnameInList(firstnames)
Die zweite Abfrage kann nicht mehr über einen dynamischen Finder abgehandelt werden. Hierfür verwenden wir ein Criteria [2]. Criteria-Abfragen sind eine geschickte Möglichkeit, um komplexe Queries in Grails-Syntax relativ übersichtlich zu schreiben. Die zweite Abfrage lässt sich wie folgt realisieren:
def firstnames = ["Max", "Moritz"]
def c = Project.createCriteria()
def result = c.list() {
persons {
inList("firstname", firstnames)
}
resultTransformer Criteria.DISTINCT_ROOT_ENTITY
}
Innerhalb der list-Closure des Criterias kann auf die einzelnen Attribute der Domain-Klasse zugegriffen werden - im Beispiel greifen wir auf die Assoziation "persons" zu. Mit der nächsten Closure wird sichergestellt, dass nur jene Personen zurückgeliefert werden, deren Vorname in der angegebenen Liste enthalten ist.
Sowohl der findAllBy-Finder als auch das list-Criteria akzeptieren die typischen Parameter wie max, offset, sort oder order, die vor allem bei Web-Applikationen für tabellarische Darstellungen unumgänglich sind.
Links
[1] findAllBy in der Grails-Dokumentation
[2] createCriteria in der Grails-Dokumentation