2012-07-18 71 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