Skip to content
Open
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ The link:../api/org/grails/datastore/gorm/GormEntity.html#where(groovy.lang.Clos
def query = Person.where {
firstName == "Bart"
}

Person bart = query.find()
----

Expand All @@ -43,9 +44,10 @@ class Person {
static DetachedCriteria<Person> simpsons = where {
lastName == "Simpson"
}
...
}

...

Person.simpsons.each { Person p ->
println p.firstname
}
Expand All @@ -58,9 +60,11 @@ Query execution is lazy and only happens upon usage of the <<detachedCriteria,De
def results = Person.findAll {
lastName == "Simpson"
}

def results = Person.findAll(sort:"firstName") {
lastName == "Simpson"
}

Person p = Person.find { firstName == "Bart" }
----

Expand All @@ -87,6 +91,7 @@ It is possible use regular Groovy comparison operators and logic to formulate co
def query = Person.where {
(lastName != "Simpson" && firstName != "Fred") || (firstName == "Bart" && age > 9)
}

def results = query.list(sort:"firstName")
----

Expand Down Expand Up @@ -129,9 +134,11 @@ Since the return value of the `where` method is a <<detachedCriteria,DetachedCri
DetachedCriteria<Person> query = Person.where {
lastName == "Simpson"
}

DetachedCriteria<Person> bartQuery = query.where {
firstName == "Bart"
}

Person p = bartQuery.find()
----

Expand All @@ -142,6 +149,7 @@ Note that you cannot pass a closure defined as a variable into the `where` metho
def callable = {
lastName == "Simpson"
}

def query = Person.where(callable)
Comment thread
gsartori marked this conversation as resolved.
----

Expand All @@ -154,6 +162,7 @@ import grails.gorm.DetachedCriteria
def callable = {
lastName == "Simpson"
} as DetachedCriteria<Person>

def query = Person.where(callable)
----

Expand Down Expand Up @@ -262,42 +271,60 @@ Operator,Criteria Method,Description
*<=*,sizeLe,The collection size is less than or equal to
|===

==== Query Aliases and Sorting

If you define a query for an association an alias is automatically generated for the query. For example the following query:
==== Sorting

Sorting with `where` queries is performed by passing `sort` and (optionally) `order` arguments to the `list` method of a <<detachedCriteria,Detached Criteria>>.

===== Single-field Sorting

To sort by a single property:

[source,groovy]
----
def query = Pet.where {
owner.firstName == "Fred"
def query = Person.where {
firstName == "Jack"
}

def results = query.list(sort: "firstName")
----

Will generate an alias for the `owner` association such as `owner_alias_0`. These generated aliases are fine for most cases, but are not useful if you want to later sort or use a projection on the results. For example the following query will fail:
By default, sorting is ascending. You can specify the direction explicitly using the `order` argument:
Comment thread
gsartori marked this conversation as resolved.

[source,groovy]
----
// fails because a dynamic alias is used
Pet.where {
owner.firstName == "Fred"
}.list(sort:"owner.lastName")
def results = query.list(sort: "firstName", order: "desc")
----

If you plan to sort the results then an explicit alias should be used and these can be defined by simply declaring a variable in the `where` query:
===== Multi-field Sorting

To sort by multiple fields, pass a `Map` to the `sort` argument:

[source,groovy]
----
def query = Pet.where {
def o1 = owner <1>
o1.firstName == "Fred" <2>
}.list(sort:'o1.lastName') <3>
def results = query.list(sort: [
firstName: "asc",
birthDate: "desc"
])
Comment thread
gsartori marked this conversation as resolved.
----

This sorts results first by `firstName` ascending and then by `birthDate` descending.

===== Sorting with Associations

When sorting by properties of associated entities, you must define an explicit alias within the `where` query:

[source,groovy]
----
def query = Pet.where {
def o = owner
o.firstName == "Fred"
}

<1> Define an alias called `o1`
<2> Use the alias in the query itself
<3> Use the alias to sort the results
def results = query.list(sort: "o.lastName")
----

By assigning the name of an association to a local variable it will automatically become an alias usable within the query itself and also for the purposes of sorting or projecting the results.
Without an explicit alias, sorting on association properties may fail due to dynamically generated aliases.

==== Subqueries

Expand All @@ -307,7 +334,7 @@ It is possible to execute subqueries within where queries. For example to find a
[source,groovy]
----
final query = Person.where {
age > avg(age)
age > avg(age)
}
----

Expand All @@ -330,7 +357,7 @@ You can apply additional criteria to any subquery by using the `of` method and p
[source,groovy]
----
def query = Person.where {
age > avg(age).of { lastName == "Simpson" } && firstName == "Homer"
age > avg(age).of { lastName == "Simpson" } && firstName == "Homer"
}
----

Expand Down Expand Up @@ -363,7 +390,7 @@ Criteria and where queries can be seamlessly mixed:
----
def results = Person.withCriteria {
notIn "firstName", Person.where { age < 18 }.firstName
}
}
----

Subqueries can be used with projections:
Expand All @@ -380,10 +407,11 @@ Correlated queries that span two domain classes can be used:
----
def employees = Employee.where {
region.continent in ['APAC', "EMEA"]
}.id()
def results = Sale.where {
}.id()

def results = Sale.where {
employee in employees && total > 100000
}.employee.list()
}.employee.list()
----

And support for aliases (cross query references) using simple variable declarations has been added to where queries:
Expand Down Expand Up @@ -455,6 +483,7 @@ Since each `where` method call returns a <<detachedCriteria,DetachedCriteria>> i
DetachedCriteria<Person> query = Person.where {
lastName == 'Simpson'
}

int total = query.updateAll(lastName:"Bloggs")
----

Expand All @@ -467,5 +496,6 @@ To batch delete records you can use the `deleteAll` method:
DetachedCriteria<Person> query = Person.where {
lastName == 'Simpson'
}

int total = query.deleteAll()
----