2012-07-18 8 views
6

Estoy trabajando en la construcción de un createCriteria dinámicamente. Hasta ahora, todo bien:¿Crear createCriteria en Grails dinámicamente y de manera SECA?

obj es el objeto (s) de dominio que quiero volver

rulesList es una lista de los mapas que mantienen el campo para ser buscado en adelante, el operador de usar, y el valor de realizar la búsqueda

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

El código anterior funciona bien y es solo un poco detallado con las instrucciones de cambio. Pero, ¿qué ocurre si deseo agregar funcionalidad para elegir hacer corresponder CUALQUIERA de las reglas o TODAS? Tendría que poner las reglas condicionalmente en un or{}. No puedo hacer algo como

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

antes de ir a través de la rulesList y luego

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

después. Todo lo que puedo pensar que hacer es repetir el código para cada condición:

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

Ahora el código es un aspecto muy descuidado y repetitivo. ¿Supongamos que quiero buscar en una propiedad de una propiedad del objeto de dominio? (Por ejemplo, quiero devolver los vehículos cuyas llantas son de una determinada marca; vehicle.tires.brand, o vehículos cuyos conductores coincidan con un nombre; vehicle.driver.name). Tendría que hacer algo como:

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

Respuesta

9

En primer lugar, se puede simplificar su gran cambio mediante el uso de un GString para el nombre del método:

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

El mismo truco funciona para el y/o:

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

o podría asignar el cierre de una primera variable y luego llamar a cualquiera or(theClosure) o and(theClosure) según corresponda. Por último, para la "propiedad de una propiedad" de búsqueda, si se agrega

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

a la parte superior del cierre criterios, entonces se puede consultar en cosas como eq('drv.name', 'Fred') sin tener que agregar el nodo intervenir driver {...} o garage {...}.

+1

gran solución, parece que todavía no estoy dando cuenta y aprovechar todo el poder de maravilloso. Además, para cualquier persona interesada en aprender más sobre createAlias ​​(que no sabía nada de antes) mirar por encima de [aquí] (http://adhockery.blogspot.com/2009/06/querying-by-association-redux.html) – Weezle

+0

Gracias ! createAlias ​​resolvió mi problema. No tengo idea de por qué no se menciona en la página createCriteria de la documentación de Grails. – Ben

Cuestiones relacionadas