2012-07-18 47 views
6

我正在动态构建createCriteria。到目前为止,一切都很好:在Grails中以动态方式和干燥方式构建createCriteria?

obj是域对象(S),我想回去

rulesList是持有被搜索的领域,运营商使用的地图列表,以及搜索对值

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']){ 
      ... 
     } 
    } 

现在代码看起来很草率和重复。假设我想搜索域对象属性的属性? (例如:我想要返回轮胎属于某个品牌的车辆; vehicle.tires.brand或其驾驶员与名称匹配的车辆; vehicle.driver.name)。我会做这样的事情:

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': 
     ... 
} 

回答

9

首先,你可以通过使用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)适当。最后,搜索“属性的财产”,如果添加

createAlias('driver', 'drv') 
createAlias('garage', 'grg') 

的标准盖顶部,那么你可以在样东西查询eq('drv.name', 'Fred')无需增加中间driver {...}garage {...}节点。

+1

伟大的解决方案,似乎我还没有意识到并充分利用Groovy的全部功能。此外,对于有兴趣了解更多关于createAlias(我对此前一无所知)的任何人,请查看[here](http://adhockery.blogspot.com/2009/06/querying-by-association-redux.html) – Weezle 2012-07-19 13:33:29

+0

谢谢! createAlias解决了我的问题。我不知道为什么它没有在Grails文档的createCriteria页面上提及。 – Ben 2015-07-24 02:32:09