Grails 我可以在Groovy中将闭包附加到另一个闭包吗?

Grails 我可以在Groovy中将闭包附加到另一个闭包吗?,grails,groovy,gorm,Grails,Groovy,Gorm,我在Grails中有两个非常相似的方法,比如“通过操作系统计算统计数据”和“通过浏览器计算统计数据”——实际上这两个方法都准备了一些东西,然后在数据库上运行类似的查询,然后对结果进行处理。方法不同的唯一部分是在我的方法中运行的查询-< /p> def summary = c.list { eq('browser', Browser.get(1)) // OR eq('os', OS.get(1)) between('date', dates.start, dates.end) }

我在Grails中有两个非常相似的方法,比如“通过操作系统计算统计数据”和“通过浏览器计算统计数据”——实际上这两个方法都准备了一些东西,然后在数据库上运行类似的查询,然后对结果进行处理。方法不同的唯一部分是在我的方法中运行的查询-< /p>
def summary = c.list {
    eq('browser', Browser.get(1)) // OR eq('os', OS.get(1))
    between('date', dates.start, dates.end)
}
我突然想到,重构它的理想方法是将闭包的第一行作为方法参数传递。像

doStats (Closure query) {
    ...
    def summary = c.list {
        query
        between('date', dates.start, dates.end)
    }
}
我试过了,但是“查询”被忽略了。我尝试了query(),但是query子句在定义的地方执行,所以这也不起作用。我想我可以把整个闭包作为一个参数传递,但这似乎是错误的——将来查询可能会变得更复杂


有谁有更好的想法吗?

您使用的标准DSL可能不同于普通groovy闭包

要执行您的要求,您可以使用此处描述的方法-

并将查询放入私有方法

更优雅的解决方案是在grails中使用命名查询-

看这张照片

  recentPublicationsWithBookInTitle {
       // calls to other named queries…
       recentPublications()
       publicationsWithBookInTitle()
  }

示例-

不确定是否使用Grails标准构建器,但使用其他构建器,您可以执行以下操作:

doStats (Closure query) {
    def summary = c.list {
        query( it )
        between('date', dates.start, dates.end)
    }
}
并通过以下方式拨打:

def f = { criteria ->
    criteria.eq( 'browser', Browser.get( 1 ) )
}
doStats( f )

如果不是,您可能最好查看命名查询

我发现
leftShift
运算符对于从两个单独的查询组合闭包非常有用。您可以做的是:

Closure a = { /*...*/ }
Closure b = { /*...*/ }
Closure c = a << b
闭包a={/*…*/}
闭包b={/*…*/}

闭包c=a谢谢,我喜欢命名查询的想法。但讽刺的是,使用它我不会得到更干净的代码。除非你有更好的主意:doStats(Long domainId,String object){if(object='browser'){Stats.browserSummary(domainId)}else{Stats.osSummary(domainId)}}好的,我可以使用布尔值,但我基本上只需要使用内联条件查询中直接传入的Long和String就可以得到相同的结果。
def criteria = {
    projection Projections.distinct(Projections.property('id'))
    and {
        eq 'owner.id', userDetails.id

        if (filter.groupId) {
            eq 'group.id', filter.groupId
        }
    }
}

List<Long> ids = Contact.createCriteria().list(criteria << {
    maxResults filter.max
    firstResult filter.offset
})

Integer totalCount = Contact.createCriteria().count(criteria)