领先一步
VMware 提供培训和认证,以加速您的进步。
了解更多上周,我描述了Grails 如何将插件视为可从兼容 Maven 的存储库中提取的普通依赖项。虽然这是 1.3 的主要新特性,但它并非唯一的新特性。在这篇文章中,我将介绍其他一些特性,首先介绍一个我最近才发现的特性。
开发一个非平凡的 Grails 应用程序,您很快就会意识到您经常一遍又一遍地使用相同的查询。您应该怎么做?复制粘贴技术很简单,但会给您带来主要的维护问题。您可以为每个常用查询编写服务方法,但是这样最终会导致非常细粒度的服务和相当愚蠢的领域模型。这些查询的理想位置是在领域类本身。
这就是命名查询的用武之地——一个在 Grails 1.2 中悄然出现的特性。
基本思想是,一个报表可以关于一个或多个服务器,并且它可能在一个月内生成多次。所以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 的标准查询 DSL 来编写查询。如果您一直推迟学习标准查询 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,因此您现在可以根据自己的意愿注释测试用例。