2

我想用 Grails (GORM) 中的 Criteria API 创建一个查询。查询必须是这样的:

MyEntity.createCriteria().list{
   assoc{
      parent{
         eq("code", val)
      }
   }
}

我需要的是从 String 对象动态构建嵌套闭包。上面示例的字符串将是"assoc.parent.code". 我按点分割字符串(通过做String.split("\\.")),但我不知道如何构造嵌套闭包:

   assoc{
      parent{
         eq("code", val)
      }
   }

动态地基于上面拆分的字符串的数组。

4

2 回答 2

3

怎么样createAlias?。你可以尝试这样的事情:

def path = "assoc.parent.code"

def split = path.split(/\./)

MyEntity.createCriteria().list {
  // this will get you 'createAlias( assoc.parent, alias1 )'
  createAlias split.take( split.size() - 1 ), "alias1"

  // this will get you 'eq(alias1.code, userInput)'
  eq "alias1.${split[-1]}", userInput
}

这个片段不是通用的,但你明白了。


更新

不是传统的,但您可以构建一个包含带有闭包的代码的字符串,并使用以下方法对其进行评估GroovyShell

assoc = 'assoc.parent.child.name'
split = assoc.split( /\./ )
path  = split[-2..0] // will get us 'child.parent.assoc';
                     // we will build it from inside-out

def firstClosure = "{ eq '${split[-1]}', 'john doe' }"
def lastClosure = firstClosure

for (entity in path) {
  def criteriaClosure =  "{ ${entity} ${lastClosure} }"
  lastClosure = criteriaClosure
}

assert lastClosure == "{ assoc { parent { child { eq 'name', 'john doe' } } } }"
def builtClosure = new GroovyShell().evaluate("return " + lastClosure)
assert builtClosure instanceof Closure
于 2013-06-15T14:35:13.530 回答
1

一种更通用的方法是metaClassString 如下,并将其用于任何类型的分隔符
. | , - ~等等。

String.metaClass.convertToClosureWithValue = {op, val ->
    split = delegate.split(op) as List
    if(split.size() == 1) {return "Cannot split string '$delegate' on '$op'"} 

    items = []
    split.each{
        if(it == split.last()){
            items << "{ eq '$it', $val }"
            split.indexOf(it).times{items.push("}")}
        } else {
            items << "{$it"
        }
    }

    println items.join()
    new GroovyShell().evaluate("return " + items.join())
}

assert "assoc.parent.child.name".convertToClosureWithValue(/\./, "John Doe") instanceof Closure
assert "assoc-parent-child-name".convertToClosureWithValue(/\-/, "Billy Bob") instanceof Closure
assert "assoc|parent|child|grandChild|name".convertToClosureWithValue(/\|/, "Max Payne") instanceof Closure
assert "assoc~parent~child~grandChild~name".convertToClosureWithValue('\\~', "Private Ryan") instanceof Closure
assert "assocparentchildname".convertToClosureWithValue(/\|/, "Captain Miller") == "Cannot split string 'assocparentchildname' on '\\|'"

//Print lines from items.join()
{assoc{parent{child{ eq 'name', John Doe }}}}
{assoc{parent{child{ eq 'name', Billy Bob }}}}
{assoc{parent{child{grandChild{ eq 'name', Max Payne }}}}}
{assoc{parent{child{grandChild{ eq 'name', Private Ryan }}}}}
于 2013-06-15T20:01:42.223 回答