領先一步
VMware 提供培訓和認證,助力您快速進步。
瞭解更多上週,我描述了 Grails 如何將外掛視為普通的依賴項,可以從 Maven 相容的倉庫中拉取。儘管這是 1.3 版本的主要新特性,但並非唯一。在本文中,我將介紹其他一些特性,首先是我最近才發現的一個特性。
開發一個非平凡的 Grails 應用,您很快就會意識到經常需要反覆使用相同的查詢。您該怎麼辦?複製貼上技術很簡單,但會導致主要的維護問題。您可以為每個通用查詢編寫服務方法,但這會導致服務粒度過細,並且領域模型變得相當愚蠢。這些查詢的理想位置是在領域類本身上。
這就是命名查詢的作用所在——一個在 Grails 1.2 中悄然出現的特性。
基本思想是,一份報告可以關於一臺或多臺伺服器,並且每月可能生成一次或多次。所以dow代表“星期幾”(day of week),而wom代表“月度周次”(week of month)。每臺伺服器都有一個關聯的位置,在這個大大簡化的模型中,它僅僅是一個城市名稱。
現在考慮一下應用程式可能想從這個模型中提取什麼樣的資訊:也許是所有在月度第一週生成的報告,或者所有關於特定伺服器的報告。我們可以向Report類新增靜態方法來提供此類查詢,但命名查詢為我們提供了一些額外的優勢,稍後您將看到。
正如您對 Grails 的預期一樣,建立命名查詢非常簡單。只需向相關的領域類新增一個靜態的namedQueries屬性,併為其分配一個閉包
class Report {
String name
static hasMany = [frequencies: Frequency, servers: Server]
static namedQueries = {
inFirstWeek {
frequencies {
eq("wom", 1)
}
}
inWeek { wom ->
frequencies {
eq("wom", wom)
}
}
dilbertsReports {
servers {
eq("mgrEmail", "[email protected]")
}
}
inCity { city ->
servers {
location {
eq("city", city)
}
}
}
}
上面的程式碼設定了四個查詢:inFirstWeek、inWeek、dilbertsReports 和 inCity。然後,您可以在可以使用動態查詢器的地方使用它們,例如在控制器動作或服務方法中。如果您想檢索所有在月度第一週生成的報告,請像這樣呼叫相關的命名查詢
Report.inFirstWeek.list()
如果您想獲取所有在月度其他周生成的報告,請使用inWeek代替
Report.inWeek(2).list()
看到如何向命名查詢傳遞引數了嗎?只需確保您的命名查詢閉包聲明瞭適當數量的引數。
希望您能看到宣告和使用命名查詢是多麼容易,但在繼續之前,有幾點需要澄清。
首先,您必須使用 Grails 的 criteria DSL 編寫查詢。如果您一直推遲學習 criteria DSL,那麼現在您有了充分的理由停止拖延!
其次,您將 DSL 呼叫為靜態屬性(如果您不向其傳遞任何引數)或方法,然後是標準的 GORM 檢索方法,例如list(), get()或動態查詢器。這意味著您可以向命名查詢新增額外的過濾。還需要指出的是,get()只有在命名查詢結果包含所需實體的情況下,才會返回領域例項。否則,get()將簡單地返回null.
換句話說,假設inFirstWeek查詢返回 ID 為 1、3 和 6 的領域例項。那麼
Report.inFirstWeek.get(3)
將返回 ID 為 3 的領域例項,而
Report.inFirstWeek.get(2)
將返回null,即使Report.get(2)返回一個真實的領域例項。因此,命名查詢就像一個過濾器。
到目前為止,一切順利。命名查詢與get(), list()和動態查詢器的結合方式可能已經足以成為您立即使用它們的理由。但 Grails 1.3 還藏著另一個絕招。
Report.dilbertsReports.inFirstWeek.list()
或者,如果我想獲取所有關於倫敦伺服器的第一週報告,我可以使用
Report.inFirstWeek.inCity("London").list()
實際上,您可以鏈式呼叫任意數量的命名查詢,只要它們都返回相同型別的領域類。
命名查詢提供了一種強大的查詢重用技術,實現和使用都非常簡單。現在您可以擁有一個非常豐富的領域模型,並且客戶端程式碼易於閱讀和理解。這有多棒?
現在我想快速看一下其他 Grails 1.3 特性。
def book = Book.get(10)
assert !book.dirty
book.title = "Unknown"
assert book.dirty
assert book.isDirty("title")
assert !book.isDirty("author")
看到如何檢查單個欄位是否已修改了嗎?
grails.sitemesh.default.layout = 'defaultLayout'
或者建立檔案grails-app/views/layouts/application.gsp。第一種方法會從grails-app/views/layouts/defaultLayout.gsp.
對於所有測試愛好者來說,Grails 終於預設捆綁了 JUnit 4,所以您現在可以隨心所欲地註解您的測試用例了。至此,我將結束關於 Grails 1.3 特性的這一部分。希望您能好好利用命名查詢!下次,我將介紹 in-place 外掛。