where 方法,在Grails 2.0被引入,構建在 Detached Criteria 之上,爲普通查詢提供了一個增強的運行時檢查的查詢DSL。where 方法比動態查詢更靈活,比criteria的代碼更簡潔而且爲撰寫查詢提供了一個強大的機制。
基本查詢
where 方法接受一個閉包看起來非常類似於Groovy的規範集合方法。閉包用規範的Groovy語法定義一個邏輯條件。例如:
def query = Person.where {
firstName == "Bart"
}
Person bart = query.find()
返回的對象是一個 DetachedCriteria 實例,這意味着他不語任何特定的數據庫連接或會話相關聯。意味着你可以使用 where在類層面去定義普通查詢:
class Person {
static simpsons = where {
lastName == "Simpson"
}
…
}
…
Person.simpsons.each {
println it.firstname
}
查詢執行是懶加載,僅僅在使用 DetachedCriteria實例之後才發生。如果你要執行一個立即生效的where樣式的查詢,可以改用 findAll 和 find方法的來完成:
def results = Person.findAll {
lastName == "Simpson"
}
def results = Person.findAll(sort:"firstName") {
lastName == "Simpson"
}
Person p = Person.find { firstName =="Bart" }
每一個Groovy操作映射到一個常規的criteria方法。下表提供了一個Groovy操作映射方法的列示:
Operator |
Criteria Method |
Description |
== |
eq |
Equal to |
!= |
ne |
Not equal to |
> |
gt |
Greater than |
< |
lt |
Less than |
>= |
ge |
Greater than or equal to |
<= |
le |
Less than or equal to |
in |
inList |
Contained within the given list |
==~ |
like |
Like a given string |
=~ |
ilike |
Case insensitive like |
這使我們利用規範的Groovy比較操作符和邏輯來定製複雜的查詢成爲可能:
def query = Person.where {
(lastName != "Simpson" &&firstName !="Fred") || (firstName =="Bart" && age > 9)
}
def results = query.list(sort:"firstName")
Groovy的正則表達式匹配操作符映射到like和ilike查詢。除非在表達式的右邊是一個 Pattern 對象,這種情況下,他們映射到一個 rlike 查詢:
def query = Person.where {
firstName ==~ ~/B.+/
}
注意,只有底層數據庫支持正則表達式, rlike 查詢纔會被支持。
一個 between 條件查詢可以使用 in 關鍵詞來組合一個。
def query = Person.where {
age in 18..65
}
最後,你可以用null和標準的比較運算符來做 isNull 和isNotNull 樣式查詢:
def query = Person.where {
middleName == null
}
查詢組合
由於 where方法的返回值是一個 DetachedCriteria實例,你可以從原來的查詢組合成新的查詢:
def query = Person.where {
lastName == "Simpson"
}
def bartQuery = query.where {
firstName == "Bart"
}
Person p = bartQuery.find()
注意,你不能在where方法閉包中定義變量傳遞,除非他已經明確地被轉換成了 DetachedCriteria 實例。也就是說下面的語句是錯誤的:
def callable = {
lastName == "Simpson"
}
def query = Person.where(callable)
上面的代碼必須這樣寫:
import grails.gorm.DetachedCriteria
def callable = {
lastName == "Simpson"
} as DetachedCriteria<Person>
def query = Person.where(callable)
這如你所看到的,閉包定義是轉換到 (使用Groovy as 關鍵字)一個在Person類中標記的 DetachedCriteria實例。
關聯、分離和取反
就像前面提到的,你可以組合Groovy標準的邏輯運算符 (|| 和 &&),形成關聯和分離:
def query = Person.where {
(lastName != "Simpson" &&firstName !="Fred") || (firstName =="Bart" && age > 9)
}
你還可以使用邏輯比較符!進行取反。
def query = Person.where {
firstName == "Fred" &&!(lastName == 'Simpson')
}
屬性比較查詢
如果你在表達式的兩邊都是用屬性名,那麼相應的屬性比較條件會被自動使用:
def query = Person.where {
firstName == lastName
}
下表描述了每個比較操作映射到每個條件屬性比較法:
Operator |
Criteria Method |
Description |
== |
eqProperty |
Equal to |
!= |
neProperty |
Not equal to |
> |
gtProperty |
Greater than |
< |
ltProperty |
Less than |
>= |
geProperty |
Greater than or equal to |
<= |
leProperty |
Less than or equal to |
查詢關聯
關聯可以被查詢,使用點操作符來指定關聯查詢的屬性名:
def query = Pet.where {
owner.firstName == "Joe" ||owner.firstName =="Fred"
}
你可以將一組條件放進一個閉包方法中進行調用,在哪裏,方法名匹配關聯名:
def query = Person.where {
pets { name == "Jack" || name == "Joe" }
}
這個技術可以結合其他頂層規範:
def query = Person.where {
pets { name == "Jack" } || firstName=="Ed"
}
集合關聯還可以用來查詢集合的大小:
def query = Person.where {
pets.size() == 2
}
下表顯示了查詢集合大小的標準比較運算符:
Operator |
Criteria Method |
Description |
== |
sizeEq |
The collection size is equal to |
!= |
sizeNe |
The collection size is not equal to |
> |
sizeGt |
The collection size is greater than |
< |
sizeLt |
The collection size is less than |
>= |
sizeGe |
The collection size is greater than or equal to |
<= |
sizeLe |
The collection size is less than or equal to |
子查詢
可能會在where查詢中使用子查詢。例如,找出所有年齡大於平均年齡的人:
final query = Person.where {
age > avg(age)
}
下面是相關子查詢的列表:
Method |
Description |
avg |
The average of all values |
sum |
The sum of all values |
max |
The maximum value |
min |
The minimum value |
count |
The count of all values |
property |
Retrieves a property of the resulting entities |
你可以使用of 方法申請添加條件到任何子查詢,通過一個閉包來傳遞條件:
def query = Person.where {
age > avg(age).of { lastName =="Simpson" } &&firstName =="Homer"
}
因爲屬性子查詢返回多個結果,可以使用比較結果作爲條件。例如,下面的例子查詢一個比“simpson”年齡小的人。
Person.where {
age < property(age).of {lastName =="Simpson" }
}
其他函數
有幾個函數可以加入到你的查詢內容中。列示如下:
Method |
Description |
second |
The second of a date property |
minute |
The minute of a date property |
hour |
The hour of a date property |
day |
The day of the month of a date property |
month |
The month of a date property |
year |
The year of a date property |
lower |
Converts a string property to upper case |
upper |
Converts a string property to lower case |
length |
The length of a string property |
trim |
Trims a string property |
目前函數只能應用於領域類的屬性和關聯,你不能在諸如子查詢的結果中使用函數。
例如,下面的查詢尋找所有在2011年出生的人:
def query = Pet.where {
year(birthDate) == 2011
}
你還可以在關聯中應用函數:
def query = Person.where {
year(pets.birthDate) == 2009
}
批量更新和刪除
由於每一個 where 方法調用返回一個 DetachedCriteria 實例,你可以使用 where 查詢執行批量操作。例如,批量更新和刪除。
例如,下面的查詢將所有 lastName爲"Simpson"的人的lastName更新爲"Bloggs":
def query = Person.where {
lastName == 'Simpson'
}
inttotal = query.updateAll(lastName:"Bloggs")
注意,一個批量操作方面的限制是連接查詢(查詢查詢關聯)是不允許的。
批量刪除記錄你可以使用deleteAll 方法:
def query = Person.where {
lastName == 'Simpson'
}
inttotal = query.deleteAll()