2012-07-18 6 views
6

Sto lavorando alla creazione di un createCriteria in modo dinamico. Fin qui, tutto bene:Costruisci creaCriteria in Grails dinamicamente e in modo DRY?

obj è l'oggetto di dominio (s) Voglio tornare

rulesList è un elenco di mappe, che detengono il campo da cercare sul, all'operatore di utilizzare, e il valore per la ricerca contro

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 
      } 
     } 
    } 
} 

Il codice sopra riportato funziona bene ed è solo un po 'prolisso con le istruzioni switch. Ma cosa succede se voglio aggiungere funzionalità per scegliere di abbinare QUALSIASI delle regole o TUTTE quelle? Avrei bisogno di mettere condizionatamente le regole in un or{}. Non riesco a fare qualcosa di simile

if(groupOp == 'or'){ 
    or{ 
} 

prima di andare attraverso il rulesList e poi

if(groupOp == 'or'){ 
    } 
} 

dopo. Tutto quello che posso pensare di fare è quello di ripetere il codice per ogni condizione:

if(groupOp == 'or'){ 
    or{ 
     rulesList.each { rule -> 
      switch(rule['op']){ 
       ... 
      } 
     } 
    } 
} 
else{ 
    rulesList.each { rule -> 
     switch(rule['op']){ 
      ... 
     } 
    } 

Ora il codice è alla ricerca piuttosto sciatta e ripetitivo. Supponiamo di voler cercare su una proprietà di una proprietà dell'oggetto dominio? (Es: Voglio restituire veicoli i cui pneumatici sono di una certa marca: vehicle.tires.brand o veicoli i cui driver corrispondono a un nome; vehicle.driver.name). Avrei dovuto fare qualcosa di simile:

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

risposta

9

Prima di tutto, è possibile semplificare il vostro grande switch utilizzando un GString per il nome del metodo:

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

Lo stesso trucco funziona per la e/o:

"${(groupOp == 'or') ? 'or' : 'and'}"() { 
    rulesList.each { rule -> 
    switch(rule['op']){ 
     ... 
    } 
    } 
} 

o si potrebbe assegnare la chiusura ad una prima variabile e quindi chiamare o or(theClosure) o and(theClosure) a seconda dei casi. Infine, per la "proprietà di una proprietà" di ricerca, se si aggiunge

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

alla parte superiore della chiusura criteri allora si può interrogare su cose come eq('drv.name', 'Fred') senza dover aggiungere il driver {...} o garage {...} nodo intervenire.

+1

Grande soluzione, sembra che non stia ancora realizzando e sfruttando tutta la potenza di Groovy. Inoltre, per chiunque sia interessato a saperne di più su createAlias ​​(di cui non sapevo nulla in precedenza), guarda oltre [qui] (http://adhockery.blogspot.com/2009/06/querying-by-association-redux.html) – Weezle

+0

Grazie ! createAlias ​​ha risolto il mio problema. Non ho idea del motivo per cui non è menzionato nella pagina createCriteria della documentazione di Grails. – Ben