原贴地址:http://www.groovyq.net/content/grails%E4%B8%AD%E7%9A%84%E5%91%BD%E5%90%8D%E6%9F%A5%E8%AF%A2
Grails从1.2起已经支持命名查询了,但在按章节分的那个参考文档中并没有详细的说明其用法,倒是在“领域类”的细目说明中给出了基本使用。最近,Peter Ledbrook在“再说Grails 1.3特性”中给出了相关的说明。
命名查询是通过在Domain Class中定一个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)
}
}
}
}
它的典型使用:
Report.inFirstWeek.list()
Report.inWeek(2).list(),要想给命名查询传参数,只要在相应的闭包中定义即可
Report.inFirstWeek.get(3),注意,get中传入的是DomainClass的id,如果查询结果中有此id,那么返回相应记录;反之为null
Report.dilbertsReports.inFirstWeek.list(),级联进行查询不断细化结果集
在命名查询中使用的完全是Criteria DSL,对于有过SQL背景的同学来说可能不是特别习惯,而更愿意去使用HQL。但是从我个人的体验来说,因为我也是这么过来的,如果你放弃了Criteria DSL,那你就放弃了简化代码的大好机会!在查询条件是根据一个查询条件窗体自动产生的场景中,使用Criteria DSL绝对比起自己去拼凑HQL要来得清晰简单,且不易出错。这种例子已经有很多了,在此就不再赘述。
在本文的结尾,我再给出使用Criteria DSL时进行分页、排序的另一种做法。这种做法在文档中并没有记录,但是通过查看源码是可以发现的。其做法跟咱们使用DomainClass.list时的方法完全一模一样,这样就比起自己在Criteria DSL里去写要简便多了。同时,在查询结果较多,需要进行分页显示时,只需要构造一个Criteria即可,而不需要写成2个。废话少说了,看例子便可以明白:
def query ={
def filter= JSON.parse(params.filter)
def filterJob = {
and{
source{
or{
filter.source.each{ key, value ->
if(value){
eq("id", key.split('-')[1] as long)
}
}
}
}
if(filter.category!='all'){
categorys{
eq("id", filter.category as long)
}
}
if(filter.options.resolved!='all'){
eq("resolved", Boolean.valueOf(filter.options.resolved))
}
if(filter.options.paied!='all'){
eq("paied", Boolean.valueOf(filter.options.paied))
}
}
}
def rval= [:]
rval.records= Job.createCriteria().list(params, filterJob)
rval.totalRecords= Job.createCriteria().count(filterJob)
render rval as JSON
}
上面的例子摘自我个人项目中的源码,filterJob闭包是根据一个查询窗体去构造相应的查询条件。由上面可以看出,这要比起自己去拼凑HQL要清晰很多。这里的另一个重点在于这两句:Job.createCriteria().list(params, filterJob)和Job.createCriteria().count(filterJob)。前者查询出结果,并根据params中的分页排序参数去完成相应的分页和排序,后者则得出整个查询的大小。完全跟Grails中generate-all命令产生的代码类似!利用这个做法,我们只需要构造一个DSL即可,否则要是按文档中介绍的把order和分页相关的部分也作为Criteria DSL中一部分定义,那么上面的records和count就得写成2个。
Peter还在其文章中介绍了Grails 1.3的其他特性,有兴趣的可访问原文。