Enums en Grails 1.1+

Supongamos que estoy modelando diseñando una aplicación. Encuentro que uno de los objetos del dominio, está limitado a un conjunto de valores que puede tomar. En terminos generales existen dos alternativas:

  • Si el conjunto de valores cambia en el tiempo, como por ejemplo el tipo de usuario (Administrador, Invitado, etc) asignado a cada usuario para gestionar sus permisos dentro de la aplicación, que en cualquier momento nos puede dar por agregar un nuevo tipo con otros provilegios: Una buena estrategia puede ser utilizar “lookup tables”, lo que en Grails corresponde a una clases de dominio que simplemente tienen su id y una propiedad adicional, por decir algo value, que es la que se encarga de almacenar cada uno de los posibles valores. De hecho hay quienes desnormalizan las “lookup tables” y meten todos los valores en una sola tabla (“domain/lookup table”), tal como lo comentan aqui.
  • Si el conjunto de valores es estatico, por ejemplo el genero (Masculino o Femenino) de una persona: Las “lookup tables” tambien podrían servir, pero quizá una enumeración sea más apropiada dado que precisamente para estos casos es que fueron pensadas: Conjunto (de tamaño razonable) de datos preestablecidos conocidos que no interesan ser cambiados a futuro. Una de las principales ventajas que nos brindan es que permiten una validación de Tipos.

En este post nos interesa abordar el segundo caso, cuando queremos usar enumeraciones. Asumo que se sabe implementar una enumeración en Groovy.

En GRAILS definimos una enumeración por ejemplo en src/groovy (de esta forma no será persistente):

enum Estado{
EVALUANDO_CICLO('EVALU', 'Evaluando ciclo'),
INVESTIGANDO_CAUSA_BENEFICIO('INVES', 'Investigando causa beneficio'),
IMPLANTANDO_SOLUCION_MEJORA('IMPLA', 'Implantando solucion mejora'),
VERIFICANDO_SOLUCION_MEJORA('VERIF', 'Verificando solucion mejora'),
CERRADA('CERRA', 'Cerrada');
final String id
final String value
Estado(String id, String value) { this.id = id;
this.value = value }
}

Notese que al ser groovy, los getter y setters han sido creados para id y para value. Luego en nuestra clase de dominio simplemente agregamos la enumeración como si se tratase de cualquier otra clase:

class Persona{
Estado estado = Estado.
EVALUANDO_CICLO
}

Con esto ya hemos logrado que cada vez que se haga persistente un objeto de la clase Persona, va a invocar al méotdo getId de su miembro tipo Estado y lo retornado es lo que se almacenará en la base de datos.

Por ejemplo si tuvieramos:

new Persona(estado:Estado.VERIFICANDO_SOLUCION_MEJORA).save()

obtendriamos en nuestra base de datos almacenado “VERIF“, y no todo el name() del enum (VERIFICANDO_SOLUCION_MEJORA), con el consiguente ahorro de recursos; esta es la gran ventaja de usar el método getId(). De hecho pudimos usar incluso algo más liviano como por ejemplo un entero, pero digamos que usando un pequeño String no es tan grave en recursos y da cierta legibilidad a los datos almacenados en la base de datos.  Como propiedad id podemos utilizar cualquier tipo de dato soportado por hibernate como Integer, String, Float, etc. Para mayor información sobre el getId() aqui (notese que es una funcionalidad de 1.1+).

Notese que GORM es lo suficientemente inteligente como para no tener que especificarle los posibles datos mediante un constraint tipo inList. Sinembargo, necesitamos que en la vista se vea la propiedad value y no la llamada a name(). Para esto debemos modificar la vista, en las partes donde se muestre el valor de la enum.

create.gsp y edit.gsp: <g:select name=”estado” from=”${InvariantManager$Estado?.values()}” value=”${solicitudNC_SInstance?.estado}” optionValue=’value’/>

show.gsp: <td valign=”top”>${solicitudNC_SInstance?.estado?.value?.encodeAsHTML()}</td>

list.gsp: <td>${fieldValue(bean: solicitudNC_SInstance, field: “estado.value“)}</td>

Como vemos, hemos logrado almacenar poca información en la base de datos (getId() = VERIF), utilizar enumeraciones legibles en código (name() = VERIFICANDO_SOLUCION_MEJORA) y presentando  en la vista un mensaje amigable al usuario (getValue() = Verificando solucion mejora), que más adelante podremos internacionalizar fácilemente tal como se explican en la documentación:

// create select with internationalized labels (this is useful for small static lists and the inList constraint)
// expected properties in messages.properties:
// book.category.M=Mystery
// book.category.T=Thriller
// book.category.F=Fantasy
<g:select name="book.category" from="${['M', 'T', 'F']}" valueMessagePrefix="book.category" />

Info adicional:

  • Internacionalización: aqui, aqui, aqui.
  • Un acercamiento similar, pero desconocen el uso del getId: aqui.

Etiquetas:

Una respuesta to “Enums en Grails 1.1+”

  1. nadiesoy Says:

    Que bien post! 😉

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s


A %d blogueros les gusta esto: