领先一步
VMware 提供培训和认证,助您加速进步。
了解更多上周,我描述了 Grails 如何将插件视为可以从 Maven 兼容存储库中拉取的普通依赖项。虽然这是 1.3 的一个重要新功能,但并非唯一的功能。在这篇文章中,我将介绍一些其他功能,并从我最近才发现的一个功能开始。
开发一个非琐碎的 Grails 应用程序,您很快就会意识到您经常重复使用相同的查询。您应该怎么做?复制粘贴技术很简单,但会留下重大的维护问题。您可以为每个常用查询编写服务方法,但随后会得到相当精细的服务和相当“愚钝”的域模型。这些查询的理想位置是域类本身。
这就是命名查询的用武之地——这项功能在 Grails 1.2 中悄然出现。
[/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 还藏着另一个绝招。
Report.dilbertsReports.inFirstWeek.list()
`Report.dilbertsReports().inFirstWeek()`。或者,如果您想获取伦敦服务器的任何第一周报告,您可以使用
Report.inFirstWeek.inCity("London").list()
`Report.inFirstWeek().inCity('London')`。事实上,只要它们都返回相同类型的域类,您就可以链接任意数量的命名查询。
命名查询提供了一种强大的查询重用技术,该技术实现简单且易于使用。现在,您可以拥有一个非常丰富的域模型,并且客户端代码易于阅读和理解。这有多好?
现在我想快速看一下 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 1.3 功能的介绍。希望您能充分利用命名查询!下次,我将介绍就地插件。