grails - 在 Grails 中以 DRY 方式动态构建 createCriteria?

标签 grails groovy createcriteria

我正在 build 一个 createCriteria动态。到现在为止还挺好:
obj是我想要返回的域对象rulesList是一个 map 列表,其中包含要搜索的字段、要使用的运算符和要搜索的值

def c = obj.createCriteria()
l = c.list (max: irows, offset: offset) {
    switch(obj){           //constrain results to those relevant to the user
        case Vehicle:
            eq("garage", usersGarage)
            break
        case Garage:
            users {
                idEq(user.id)
            }
            break
    }
    rulesList.each { rule ->
        switch(rule['op']){
            case 'eq':
                eq("${rule['field']}", rule['value'])
                break
            case 'ne':
                ne("${rule['field']}", rule['value'])
                break
            case 'gt':
                gt("${rule['field']}", rule['value'])
                break;
            case 'ge':
                ge("${rule['field']}", rule['value'])
                break
            case 'lt':
                lt("${rule['field']}", rule['value'])
                break
            case 'le':
                le("${rule['field']}", rule['value'])
                break
            case 'bw':
                ilike("${rule['field']}", "${rule['value']}%")
                break
            case 'bn':
                not{ilike("${rule['field']}", "${rule['value']}%")}
                break
            case 'ew':
                ilike("${rule['field']}", "%${rule['value']}")
                break
            case 'en':
                not{ilike("${rule['field']}", "%${rule['value']}")}
                break
            case 'cn':
                ilike("${rule['field']}", "%${rule['value']}%")
                break
            case 'nc':
                not{ilike("${rule['field']}", "%${rule['value']}%")}
                break
            }
        }
    }
}

上面的代码工作正常,只是用 switch 语句看起来有点冗长。但是如果我想添加功能来选择匹配任何规则或所有规则怎么办?我需要有条件地将规则放入 or{} .我不能做类似的事情
if(groupOp == 'or'){
    or{
}

在我通过 rulesList 然后
if(groupOp == 'or'){
    }
}

之后。我能想到的就是为每个条件重复代码:
if(groupOp == 'or'){
    or{
        rulesList.each { rule ->
            switch(rule['op']){
                ...
            }
        }
    }
}
else{
    rulesList.each { rule ->
        switch(rule['op']){
            ...
        }
    }

现在代码看起来很草率和重复。假设我想搜索域对象的属性的属性? (例如:我想归还轮胎为特定品牌的车辆;车辆.轮胎.品牌,或驾驶员与名称匹配的车辆:车辆.驾驶员.名称)。我是否必须做类似的事情:
switch(rule['op']){
    case 'eq':
        switch(thePropertiesProperty){
            case Garage:
                garage{
                    eq("${rule['field']}", rule['value'])
                }
                break
            case Driver:
                driver{
                     eq("${rule['field']}", rule['value'])
                }
                break
        }
        break
    case 'ne':
        ...
}

最佳答案

首先,您可以通过使用 GString 作为方法名称来简化您的大开关:

case ~/^(?:eq|ne|gt|ge|lt|le)$/:
  "${rule['op']}"("${rule['field']}", rule['value'])
  break

同样的技巧适用于和/或:
"${(groupOp == 'or') ? 'or' : 'and'}"() {
  rulesList.each { rule ->
    switch(rule['op']){
        ...
    }
  }
}

或者您可以先将闭包分配给一个变量,然后调用 or(theClosure)and(theClosure)作为适当的。最后,对于“property of a property”搜索,如果添加
createAlias('driver', 'drv')
createAlias('garage', 'grg')

到条件闭包的顶部,然后您可以查询诸如 eq('drv.name', 'Fred') 之类的内容无需添加中间的 driver {...}garage {...}节点。

关于grails - 在 Grails 中以 DRY 方式动态构建 createCriteria?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/11550507/

相关文章:

grails - 如何在createCriteria中修剪属性

grails - Grails:插件[controllers:3.3.9]无法将更改重新加载到文件

Grails - 按查询中的两个字段排序

grails - 比较两个Groovy日期

grails - 从 "View"发送数据到 "Controller"

sql - 在条件查询中转换SQL语句

grails 2.4 java 8 和 tomcat 7.0.55.2

java - 如何接受 byte[] 作为对 POST 的响应

grails - 强制 @GrailsCompileStatic 检查请求为 AbstractMultipartHttpServletRequest

grails - 如何使用createCriteria比较收集项目?