使用迭代动态构建Criteria Block

时间:2012-04-11 20:51:07

标签: mongodb grails gorm

我想基于多个过滤器查询属性并动态构建标准

Domain Class
PatientAttr {
   def name
   def value
}

标准构建代码

    if(filters.size() != 0 ){
        def criteria =  PatientAttr.createCriteria()
        def results = criteria.list{
            for (item in filters){
                def name = item.name
                def filter = item.filter
                and{
                    eq 'name', name
                    if(filter[0] == "lt")
                        lt ('value', filter[1] as Double)
                    else if(filter[0] == "gt")
                        gt ('value', filter[1] as Double)
                    else 
                        between ('value', filter[0] as Double, filter[1] as Double)
                }
            }
        } 

我发现只评估列表的最后一个“和”语句。条件构建器是否允许您动态构建条件?

上面的代码应该等同于

        def results = criteria.list{
            and{
                eq 'name', "Serum albumin (g/dL)"
                gt 'value', 3.5 as Float
            }
            and{    
                eq 'name', "M-spike (g/dL)"
                gt 'value', 2.3 as Float
            }
        }

2 个答案:

答案 0 :(得分:1)

我不知道你遇到麻烦的原因,但由于查询的默认连词是and,所以没有理由在你的例子中使用and{}闭包。您的上述查询与以下内容相同:

    def results = criteria.list{
        eq 'name', "Serum albumin (g/dL)"
        gt 'value', 3.5 as Float
        eq 'name', "M-spike (g/dL)"
        gt 'value', 2.3 as Float
    }

如果你想将顶级项目or组合在一起,那么你需要将外部块包装在or{}闭包中:

if(filters.size() != 0 ){
    def criteria =  PatientAttr.createCriteria()
    def results = criteria.list{
        or{
            for (item in filters){
                def name = item.name
                def filter = item.filter
                and{
                    eq 'name', name
                    if(filter[0] == "lt")
                        lt ('value', filter[1] as Double)
                    else if(filter[0] == "gt")
                        gt ('value', filter[1] as Double)
                    else 
                        between ('value', filter[0] as Double, filter[1] as Double)
                }
            }
        }
    } 

这将返回一个结果如下的查询:

  

名称为'血清白蛋白......'且值大于'3.5'    OR
  名称是'M-spike ...',值大于2.3
   OR等

希望这有帮助。

答案 1 :(得分:0)

你的街区

    def results = criteria.list{
        and{
            eq 'name', "Serum albumin (g/dL)"
            gt 'value', 3.5 as Float
        }
        and{    
            eq 'name', "M-spike (g/dL)"
            gt 'value', 2.3 as Float
        }
    }
你是说要表达:

((name == "Serum albumin (g/dL)") or (value == 3.5))
and
((name == "M-spike (g/dL)") or (value == 3.3))

然后你的代码应该是:

if(filters.size() != 0 ){
    def criteria =  PatientAttr.createCriteria()
    def results = criteria.list{
        and{
            for (item in filters){
                def name = item.name
                def filter = item.filter
                or {
                    eq 'name', name
                    if(filter[0] == "lt")
                        lt ('value', filter[1] as Double)
                    else if(filter[0] == "gt")
                        gt ('value', filter[1] as Double)
                    else 
                        between ('value', filter[0] as Double, filter[1] as Double)
                }
            }
        }
    } 

如果你想表达:

((name == "Serum albumin (g/dL)") and (value == 3.5))
and
((name == "M-spike (g/dL)") and (value == 3.3))

然后你的代码应该是:

if(filters.size() != 0 ){
    def criteria =  PatientAttr.createCriteria()
    def results = criteria.list{
        and{
            for (item in filters){
                def name = item.name
                def filter = item.filter
                eq 'name', name
                if(filter[0] == "lt")
                    lt ('value', filter[1] as Double)
                else if(filter[0] == "gt")
                    gt ('value', filter[1] as Double)
                else 
                    between ('value', filter[0] as Double, filter[1] as Double)
            }
        }
    } 

因为和是默认操作,你可以省略和方法。