更多 Grails 1.3 功能

工程 | Peter Ledbrook | 2010 年 5 月 24 日 | ...

上週,我描述了 Grails 如何將外掛視為可以從 Maven 相容儲存庫中拉取的普通依賴項。雖然這是 1.3 的一個重要新功能,但並非唯一的功能。在這篇文章中,我將介紹一些其他功能,並從我最近才發現的一個功能開始。

命名查詢

GORM 提供了三種不同的資料庫查詢方式
  • 動態查詢器,例如 Book.findByTitleAndAuthorLike(...);
  • Criteria 查詢,使用漂亮的 DSL;以及
  • HQL,Hibernate 的類似 SQL 的查詢語言。
這三個功能提供了易用性和強大功能的強大組合,為您提供了所需的靈活性。然而,仍然缺少一些東西。

開發一個非瑣碎的 Grails 應用程式,您很快就會意識到您經常重複使用相同的查詢。您應該怎麼做?複製貼上技術很簡單,但會留下重大的維護問題。您可以為每個常用查詢編寫服務方法,但隨後會得到相當精細的服務和相當“愚鈍”的域模型。這些查詢的理想位置是域類本身。

這就是命名查詢的用武之地——這項功能在 Grails 1.2 中悄然出現。

一個例子

讓我們考慮一個與報告相關的簡單域模型:[caption id="attachment_4791" align="alignnone" width="398"]Domain model for reports[/caption]

基本思想是,一份報告可以涉及一個或多個伺服器,並且可能每月生成一次或多次。所以dow代表“一週中的某一天”,而wom代表“一個月中的第幾周”。每臺伺服器都有一個關聯的位置,在這個大大簡化的模型中,這只是一個城市名稱。

現在考慮一下應用程式可能想從這個模型中提取哪些資訊:也許是本月第一週生成的所有報告,或者是關於特定伺服器的所有報告。我們可以將靜態方法新增到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,現在您有一個很好的理由停止拖延!

其次,您可以像呼叫標準 GORM 檢索方法(例如list(), get()find()` 或 `findAll()`)或動態查詢器一樣,透過靜態屬性(如果您不向其傳遞任何引數)或方法來呼叫 DSL。這意味著您可以為命名查詢新增額外的過濾。還值得指出的是,get()`Report.get(reportId)` 將僅在命名查詢的結果包含所需實體時才返回域例項。否則,get()`Report.get(reportId)` 將簡單地返回null.

null。換句話說,假設inFirstWeek查詢返回 ID 為 1、3 和 6 的域例項。那麼

Report.inFirstWeek.get(3)

`Report.get(3)` 將返回 ID 為 3 的域例項,而

Report.inFirstWeek.get(2)

`Report.get(2)` 將返回nullnull,即使Report.get(2)返回一個真實的域例項。因此,命名查詢充當過濾器。

到目前為止,一切都很好。命名查詢與get(), list()`find()` 和 `findAll()` 以及動態查詢器結合使用的方式,可能足以立即使用它們。但 Grails 1.3 還藏著另一個絕招。

鏈式查詢

任意組合命名查詢聽起來怎麼樣?好吧,透過連結命名查詢,您就可以擁有它。例如,如果您想獲取 Dilbert 在本月第一週生成的所有報告,您可以呼叫
Report.dilbertsReports.inFirstWeek.list()

`Report.dilbertsReports().inFirstWeek()`。或者,如果您想獲取倫敦伺服器的任何第一週報告,您可以使用

Report.inFirstWeek.inCity("London").list()

`Report.inFirstWeek().inCity('London')`。事實上,只要它們都返回相同型別的域類,您就可以連結任意數量的命名查詢。

命名查詢提供了一種強大的查詢重用技術,該技術實現簡單且易於使用。現在,您可以擁有一個非常豐富的域模型,並且客戶端程式碼易於閱讀和理解。這有多好?

現在我想快速看一下 Grails 1.3 的其他一些功能。

其餘的精彩

Grails 1.3 版本還包含了一些更小但仍然有用的功能。其中最重要的是升級到 Groovy 1.7(Grails 1.2 及更早版本基於 Groovy 1.6)。

Groovy 1.7

Groovy 1.7 版本包含許多修復和增強功能,但也許其中兩個對 Grails 開發人員來說是最重要的:
  1. 支援匿名類和內部類——因此與 Wicket 等框架的整合應該會容易得多。
  2. Power asserts——您現在可以使用 Groovy 的`assert`關鍵字,而不是 JUnit/TestNG 的替代方案,以獲得有關斷言失敗原因的令人印象深刻的診斷資訊。我最喜歡的新功能!

髒檢查

不,這與家務活無關!正如你們中的許多人所知,Hibernate 會自動檢查域例項是否已被修改,並在會話結束時持久化更改。GORM 現在允許您透過`isDirty()`方法
def book = Book.get(10)
assert !book.dirty

book.title = "Unknown"
assert book.dirty
assert book.isDirty("title")
assert !book.isDirty("author")

方法訪問此功能。看看您還可以檢查單個欄位是否已被修改?

全域性佈局

正如您可能知道的,Grails 允許您透過 `` 標籤或約定顯式地將佈局應用於檢視。它不允許您為檢視指定一個預設佈局作為備選方案。這個缺陷現在得到了糾正,您可以透過 Config.groovy 中的設定<meta>或透過建立檔案
grails.sitemesh.default.layout = 'defaultLayout'

`grails-app/views/layouts/application.gsp`來指定預設佈局。第一種方法將從`grails-app/views/layouts/defaultLayout.gsp`載入佈局。.

JUnit 4

對於所有熱衷於測試的開發者,Grails 現在預設包含 JUnit 4,因此您可以隨心所欲地為測試用例添加註解。

至此,我將結束本期 Grails 1.3 功能的介紹。希望您能充分利用命名查詢!下次,我將介紹就地外掛。

獲取 Spring 新聞通訊

透過 Spring 新聞通訊保持聯絡

訂閱

領先一步

VMware 提供培訓和認證,助您加速進步。

瞭解更多

獲得支援

Tanzu Spring 提供 OpenJDK™、Spring 和 Apache Tomcat® 的支援和二進位制檔案,只需一份簡單的訂閱。

瞭解更多

即將舉行的活動

檢視 Spring 社群所有即將舉行的活動。

檢視所有