Hibernate: Annotations vs XML

En varias ocasiones he visto sobre el tema de persistencia en java la discusión de si es mejor usar annotations o ficheros de configuración XML.

Mi primera opinión, sin pensar mucho más, es que era mejor los ficheros de configuración XML, sin lugar a dudas. ¿Por qué?. Pienso que los bean de java deben ser reutlizables de proyecto en proyecto, que la base de datos es un tema aparte cuyas tablas pueden cambiar de un proyecto a otro y no me gusta meter dependencias de jar raros en mis clases básicas del modelo de datos. Las annotations de persistencia necesitan esos jar para compilar. De alguna forma, pienso que estoy "casando" mis clase con una herramienta específica.

Sin embargo, ahora que me he metido a jugar un poco con hibernate más en serio y empiezo a comprender la filosofía de trabajo de estas herramientas de persistencia, empiezo a dudar si es mejor los ficheros XML.

Por un lado, estoy mal acostumbrado en los proyectos en los que trabajo. Alguien diseña la base de datos primero, o incluso nos la da el cliente ya hecha y tenemos que hacer código para tratar con esa base de datos. De proyecto en proyecto, aunque la temática es la misma, nos hacen cambios en las bases de datos. Por ello, nuestras aplicaciones pretenden tener su propio modelo de datos a base de java beans y tratan de aislarse lo más posible de los detalles de la base de datos. El patrón DAO se nos hace fundamental.

Pero veo que la forma de trabajo de Hibernate está pensada al revés. Tú te haces tu modelo de datos con java beans y te olvidas de la base de datos. Con annotations o con ficheros XML haces el mapeo de esos beans sobre la base de datos e Hibernate se encarga de crear todas las tablas. Y pensándolo de esta forma, en que lo principal son tus java beans y las tablas de base de datos son "secundarias", empiezo a ver ventajas en las annotations sobre los ficheos XML.

Si se hacen java beans y ficheros XML de mapeo separados, estamos hasta cierto punto violando el principio DRY (Don`t repeat yourself). Si tocamos los java beans, debemos acordarnos de tocar el XML correspondiente y al revés. Debemos tocar en dos sitios distintos si cambia el tipo de una columna, añadimos o borramos un atributo a un java bean, etc. Con annotations es más dificil el despiste. Si cambio un atributo, lo añado o lo borro, la annotation está justo al lado y es más difícil olvidarse de ella.

Además, si vamos a reutilizar nuestros beans en otros proyectos y vamos a seguir el mismo mecanismo de persistencia, dejando a Hibernate o la herramienta de turno crear las tablas de base de datos, no es tan malo llevarse los bean con sus annotations. De hecho, es más cómodo que llevarse los bean y además sus ficheros xml.

La única pega que le veo a esto es que las annotations en ocasiones se complican demasiado, quitando claridad a un código en principio simple (un java bean). Y como ejemplo, este trozo de código sacado de la documentación de Hibernate, donde sólo se empieza a declarar la clase Forest (si, fíjate al final, la última línea….)

@Entity
@BatchSize(size=5)
@org.hibernate.annotations.Entity(
        selectBeforeUpdate = true,
        dynamicInsert = true, dynamicUpdate = true,
        optimisticLock = OptimisticLockType.ALL,
        polymorphism = PolymorphismType.EXPLICIT)
@Where(clause="1=1")
@org.hibernate.annotations.Table(name="Forest", indexes = { @Index(name="idx", columnNames = { "name", "length" } ) } )
@Persister(impl=MyEntityPersister.class)
public class Forest { ... }

 

Otra vez Hibernate

 

Hace algún tiempo me puse a jugar con Hibernate y no me causó demasiada buena impresión. Me daba muchos problemas, las herramientas que bajaba parecian bastante descuidadas, no me funcionaba nada bien sin tener que pelearme con ello y un sin fin de descalabros. Pero estos días atrás me entró remordimiento de conciencia. De aquella, había empezado supongo que de mala manera, sin saber nada de hibernate, tratando de arrancar las herramientas de "ingeniería inversa", es decir, tratar de sacar de las tablas de base de datos ya creadas los bean de java y los xml de mapeo. Así que hace unos días me decidí a retomar el tema desde cero, empezando con la documentación de Hibernate y siguiéndola más o menos paso a paso.

Pues creo que me reafirmo en mi idea. La documentación, aunque están claros los conceptos que explica, deja bastante que desear en cuanto a cómo arrancar el ejemplo. Ahi van algunas pegas:

  • Si te bajas hibernate, no vienen ahí todos los jar necesarios. Aparte del conector con la base de datos, se echa en falta una implementación para slf4j-api. Hibernate trae la Api, pero no la implementación y no funciona el ejemplo sin una implementación. Sí, la documentación dice que es necesaria una implementación en el punto 3.5,  pero el ejemplo y el arranque del mismo está en el punto 1.2. No parece el orden adecuado eso de "tú arranca, que más adelante te diré qué está mal".
  • Si intentas la configuración con maven, en la documentación no pone el groupId a usar, sino una variable ${groupId} que no está definida en ningún sitio. Bueno, no cuesta mucho inventarse un valor y sacarlo, pero podrían haberlo puesto. Por cierto, tampoco pone la versión.
  • Si sigues con maven, no se baja el jar de javassist, sea lo que sea eso. El caso es que en el pom.xml debes poner la dependencia a mano y en la documentación no lo indica.
  • Además, por supuesto, falta la dependencia de la implementación de slf4j-log4j (o el logger que quieras). La podemos poner sin problemas, pero hay que tener cuidado, porque la versión que se ponga de dicha implementación debe coincidir con la versión de slf4j-api de la que depende hibernate y, que por supuesto, tampoco se ve directamente en ningún sitio.

En fin, que el ejemplo muy bien, pero ponerlo en marcha cuesta unos cuantos ensayo, error y googlear, añadiendo dependencias y jars, según nos van saliendo errores. No me extrañan nada comentarios como este de Nicolás.

Así que como siempre, copiando de la documentación y ampliándola precisamente en estas pequeñas pegas, ahí va mi "Hola mundo con hibernate", en el que espero quede más claro exactamente que jars necesitamos y cómo arrancar la aplicación de la documentación.

Y de paso, sigo leyendo la documentación dichosa, a ver si aprendo algo de Hibernate. Lo que he leido y probado hasta ahora me está gustando bastante.

Python con MySQL

 

Hay una tontería de la conexión de python con MySQL que me ha llamado la atención y aprovecho para comentar aquí. El tema es que según obtengamos el cursor de la conexión para hacer las consultas, podemos acceder a los resultados de una manera o de otra.

Si obtenemos el cursor de esta manera

conn = MySQLdb.connect (….)
cursor = conn.cursor()

una vez que hagamos una consulta y obtengamos una de las filas resultado, debemos acceder a cada uno de los campos usando un índice de un array

cursor.execute ("select * from tabla")
fila = cursor.fetchone()
# para acceder al primer campo
print fila[0]  

Sin embargo, al obtener el cursor podemos decir que queremos que las filas sean dictionaries, en vez de tuplas, de manera que podemos acceder a los campos usando el nombre del campo, en vez de un índice. Para ello, basta con obtener el cursor de esta manera

conn = MySQLdb.connect (…)
cursor = conn.cursor(MySQLdb.cursors.DictCursor)

y así podemos acceder a los campos a través de su nombre

cursor.execute("select * from tabla")
fila = cursor.fecthone()
# para acceder a uno de los campos
print fila["nombre_columna"]

Una tontería, pero estoy acostumbrado a java y a C++ y no a lenguajes tan flexibles.