
Como el autor del framework Transfer, tengo un gran interés en la funcionalidad de ORM en ColdFusion, y por un largo tiempo por los frameworks de persistencia en general. Cuando escuche que ColdFusion 9 beta iba a incluir la integración con Hibernate, uno de los más importantes frameworks de ORM, estaba muy interesado en explorar las nuevas capacidades que este iba a ofrecer a una amplia variedad de desarrolladores de ColdFusion.
Rápidamente encontré que la integración entre Hibernate y ColdFusion había sido lograda excepcionalmente bien, ocultando muchas de las complejidades de implementar Hibernate (y ORM en general), sin embargo dándole al desarrollador una flexibilidad notable en estrategias de desarrollo, y también exponiendo muchas de las capas de Hibernate para aquellos que quieren tomar una ventaja directa de algunos de sus características más complejas y configurables.
En este articulo, proveeré una revisión de ORM en general así como también de la integración entre Hibernate y ColdFusion antes de cubrir como realizar operaciones de base de datos y manejar relaciones con ORM.
Aunque el término Object Relational Mapper suena complejo y espeluznante, en un nivel básico, el concepto es realmente sencillo y directo. El punto crucial del tema viene del hecho que en las aplicaciones, los objetos saben acerca de cada otro a través de referencias en memoria, mientras que en las bases de datos relacionales, las tablas de datos se refieren las unas a las otras a través de relaciones de claves primarias y claves foráneas. Por ejemplo, un objeto Musico puede saber acerca de una matriz de instrumentos que él puede tocar, pero en la base de datos una tabla Musico tendrá una clave primaria, a la cual se refiere una clave foránea para construir una relación entre un Musico y sus instrumentos.
La función de ORM, entonces es traducir objetos en datos relacionales y datos relacionales en objetos, sin que el desarrollador tenga que hacer nada del trabajo pesado. Mientras que muchos ORMs tienen muchas más características que van mas allá del corazón de este principio, en un nivel básico no es nada más complicado que eso.
La explicación de un ORM suena muy bien académicamente hablando. ¿Pero qué beneficios puedes esperar recibir como un desarrollador? Esencialmente, la mayor razón para usar ORM es para ahorrarle tiempo cuando desarrolle aplicaciones. Mientras que obviamente siempre tomara más tiempo dominar una nueva herramienta, creo que este punto es tan importante, que lo diré nuevamente: Usar un ORM te ahorrara mucho tiempo cuando desarrolles aplicaciones.
Esto incluye reducir el tiempo de implementación desde cuando empieza a desarrollar su aplicación, como ORM le ahorrara horas de tedioso trabajo pesado que es escribir sentencias de SQL para creer, leer, actualizar y borrar, y el código de ColdFusion que se usara en la aplicación. No solo eso, pero usar ORM reducirá el número de errores potenciales en su aplicación, debido al hecho que usted tiene un solo punto de configuración para todas sus necesidades de persistencia. Con ORM, tener una sentencia INSERT escrita correctamente, pero un error en una sentencia UPDATE tiende a ser una cosa del pasado.
El tiempo de mantenimiento también se reduce. Por ejemplo, si usted quiere agregar una propiedad extra a su objeto, normalmente tendría que hacer cambios a una gran cantidad de lugares, desde las sentencias UPDATE, SELECT, e INSERT hasta el código de ColdFusion. Todos estos cambios introducen la posibilidad de cometer errores de programación. Cuando usas ORM, los cambios usualmente se realizan en un solo lugar, y eso es todo lo que necesita hacer.
Para citar el sitio de Hibernate, “Hibernate es un servicio poderoso, de persistencia de objeto/relacional de alto rendimiento y de consultas.” Es también una de las soluciones de persistencia más populares de Java actualmente en uso.
Hibernate provee todas las herramientas para crear, leer, actualizar y borrar (CRUD=Create Read Update Delete) que usted necesita para introducir datos y recuperar datos desde y hacia una base de datos relacional a través de una sofisticada configuración de mapeo. Este también tiene todas las herramientas para consultas mejoradas, generar el esquema de su base de datos, cacheo, intercepción de eventos y mucho más.
En el largo plazo, este tecnología es definitivamente digna de aprender más acerca de cómo trabaja Hibernate para que así pueda usted empezar a entender que está haciendo exactamente ColdFusion tras bastidores y le ayudara a salir de algunas situaciones complicadas. Por ahora, sin embargo, usted puede empezar con la integración ORM sin conocer todos los detalles, porque mucho del trabajo complicado ha sido ya realizado por el equipo de desarrollo de ColdFusion.
La integración de ColdFusion e Hibernate
Antes de ColdFusion 9 beta, si usted quería usar Hibernate en una aplicación de ColdFusion, usted tenía que entender y saber de Java o Groovy. Usted también tenía que hacer configuración por usted mismo, y preocuparse acerca de las variables de entorno de Java, la configuración de Hibernate, el manejo de sesiones de Hibernate, el manejo de transacciones, y todos esos pequeños detalles que hacen de Hibernate una pieza de software increíblemente poderosa, pero también compleja de administrar.
Ahora con ColdFusion 9 beta, no hay necesidad para aprender Java o Groovy. Gracias a la integración entre Hibernate y ColdFusion 9 beta, muchos de estos aspectos son manejados o provistos para usted de formas que son ya claras para usted. Usando componentes de ColdFusion y un archivo Application.cfc para configurar y usar ORM, el desarrollador promedio de ColdFusion puede ahora tomar ventaja del poder y la flexibilidad de Hibernate.
El primer paso en configurar la integración con ORM se realiza a través del archivo Application.cfc de tu aplicación.
Para encender ORM, incluye esta línea de código:
this.ormenabled=true;
Con esto Hibernate está listo para ser usado.
Tomando ventaja de una nueva mejora en ColdFusion 9 beta, usted puede ajustar un origen de datos predeterminado para todas las llamadas de <cfquery> en el archivo Application.cfc, simplemente incluyendo la siguiente línea:
this.datasource=”orm”;
Esta línea de código le dice a la aplicación que use el origen de datos ORM, y también le dice a Hibernate a que origen de datos usted quiere que se conecte.
Nota: La integración de Hibernate solo puede funcionar con un solo origen de datos dentro de una determinada aplicación de ColdFusion. Dado el hecho que Hibernate puede solo manejar una base de datos a la vez, por ende esta restricción no es una sorpresa. Esto no le imposibilita de acceder otro origen de datos a través de <cfquery>, pero esta es una limitación de la cual usted debe conocer.
En términos de configuración, no hay nada más que usted necesita hacer. Hay, sin embargo, varios atributos opcionales que puede usar para controlar como Hibernate funciona. Estos atributos son provistos a través de this.ormsettings, el cual es una estructura (struct) de valores adicionales que se ajustan en Application.cfc. En este ejemplo, primero le digo a ORM que los CFCs que estoy usando están en la carpeta /com, de esta forma ORM no busca a través de toda mi carpeta web raíz, y así obtengo un inicio más rápido.
this.ormsettings.cfclocation=”com”;
También voy a determinar el dialecto que Hibernate usara, el cual le dice a ORM que tipo de bases de datos este manejara. Típicamente, usted no necesitaría hacer esto porque esto se configura automáticamente, pero para este ejemplo yo estoy usando SQL Server y hago que Hibernate cree la base de datos por mí. Como elegí que Hibernate creara mis tablas como InnoDB, para el soporte de transacciones y claves foráneas, en vez de la opción predeterminada, MyIsam, tengo que ajustar este valor.
this.ormsettings.dialect = "MicrosoftSQLServer";
También voy a usar los ajustes de dbcreate y logSQL, los cuales solo voy a ejecutar en mi servidor de desarrollo.
Como decidí que quería que Hibernate creara las tablas de mi base de datos por mí (permitiéndome enfocarme en crear los objetos para mi aplicación), tendré que decirle a Hibernate como quiero que haga esto. Si ajusto la opción dbcreate a update, entonces este creara la tabla que necesita si esta no existe, e intenta actualizarla si esta existe. Habiendo dicho esto, me gustaría empezar desde una base de datos en blanco con cada reinicio de mi aplicación, así yo sé exactamente el conjunto de datos que usare en cada iteración. Por esta razón, yo voy a ajustar esta propiedad a dropcreate, así Hibernate eliminara la tabla si esta existe, y entonces la recreara:
this.ormsetting.dbcreate=”dropcreate”;
Finalmente, le diré a Hibernate que guarde en la bitácora todo el SQL que ORM genere, para propósitos de depuración:
this.ormSetting.logSQL=true;
Desafortunadamente, esto no almacena en la bitácora el SQL en la vista de depuración como lo hace <cfquery>, pero en vez de esto manda toda la información de depuración a la consola. Esto no es un gran problema si usted está acostumbrado a iniciar ColdFusion a través de la línea de comandos, en vez de iniciar ColdFusion como un servicio de Windows, por ejemplo, pero si usted no lo hace, iniciar ColdFusion a través de ColdFusion Builder beta le dará acceso a la misma información.
Si usted quiere volver a cargar Hibernate, recrear tablas, o recargar la configuración de mapeos (la cual detallare más adelante), usted puede hacerlo usando el método ORMReload(), el cual volverá a cargar ORM sin volver a cargar toda la aplicación. Alternativamente, usted puede usar ApplicationStop() para detener la aplicación; en la siguiente petición la aplicación, y por ende de ORM, serán vueltos a cargar. He creado una pequeña utilidad para reiniciar mi aplicación en el archivo Application.cfc.
Application.cfc
<cfcomponent hint="Soy el Application CFC" output="false"> <cfscript>
this.name = "ORM Demo";
this.sessionManagement = true;
//turn on orm
this.ormenabled = true;
this.datasource = "orm";
//Si es un servidor de desarrollo
this.developmentServer = true;
//add some additional settings
this.ormsettings = { cfclocation = "com",dialect="MicrosoftSQLServer" };
if(this.developmentServer)
{
this.ormsettings.dbcreate = "dropcreate";
this.ormsettings.logSQL = true;
}
</cfscript>
<cffunction name="onRequestStart" access="public" hint="Request start processing" returnType="boolean" output="false">
<cfargument name="targetPage" type="string" hint="The page requested" required="true"/>
<cfif StructKeyExists(URL, "reload")>
<cfset ApplicationStop() />
<cflocation url="#arguments.targetPage#">
<cfreturn false />
</cfif>
<cfreturn true>
</cffunction>
</cfcomponent>
Hay muchas más opciones de configuración de ORM que están disponibles para ser usadas en Application.cfc que no he descrito, pero esto es suficiente para empezar a usar ORM. Si usted quiere aprender más, usted puede leer ColdFusion 9 Developers Guide – ORM Setting
Realizar operaciones básicas de crear, leer, actualizar y borrar con la integración de ColdFusion 9 beta y ORM es notablemente sencillo. Simplemente defina un CFC con las propiedades que quiere usar y almacenar en la base de datos, y deje que Hibernate haga el resto del trabajo por usted. Por ejemplo, el siguiente CFC representa un Musico, para el cual voy a almacenar un nombre y una edad:
<cfcomponent hint="Soy un musico" output="false" persistent="true">
<cfproperty name="musicoID" hint="El id para un musico" type="numeric" fieldtype="id" datatype="integer" generator="identity">
<cfproperty name="nombre" hint="El nombre del musico" type="string" length="255">
<cfproperty name="edad" hint="La edad del musico" type="numeric" datatype="integer">
<cffunction name="init" hint="Constructor" access="public" returntype="Musician" output="false">
<cfargument name="name" hint="the name of the musician" type="string" required="no" default="">
<cfscript>
setName(arguments.name);
return this;
</cfscript>
</cffunction>
</cfcomponent>
La primera cosa para notar acerca de este ejemplo es el atributo persistent en <cfcomponent>. Cuando persistent se ajusta a true, este le dice a ColdFusion que este CFC representa datos en la base de datos y que los datos pueden ser persistidos a través de la integración con ORM. Entonces tomo ventajas de la nueva funcionalidad implícita de setters y getters usando <cfproperty> para especificar que propiedades el objeto Musico necesita tener, el cual en este caso es un musicoid, el nombre del músico, y la edad del músico. Cuando ORM se inicia, este automáticamente creara una tabla de base de datos llamada “Musico”. Porque yo especifique fieldtype=”id”, ormdatatype=”integer”, y generator=”identity”, Hibernate ajustara una clave primaria numérica auto-incrementable para musicoid en la tabla. Las columnas “nombres” y “edad” también son creadas, de acuerdo a los criterios de las definiciones de <cfproperty>. Las columnas “nombre” y “edad” también se crean, emparejando las definiciones que declare usando <cfproperty>. En la propiedad nombre, ajuste la longitud a 255, usando el atributo length. En la propiedad edad, definí el tipo de datos a integer, usado el atributo datatype.

Como Hibernate, está creando la base de datos para mí, yo puedo tomar ventaja de varios atributos predefinidos que no necesito cambiar. Por ejemplo, no necesito especificar un nombre de tabla, porque el nombre de la tabla es definido con el nombre del componente, en este caso, “Musico”. Así que mientras parece que no he usado muchos atributos para mapear el CFC a la tabla de la base de datos, hay muchas más opciones disponibles. Para mapear una estructura de base de datos existente, usted necesitaría ser mas explicito y global tratándose de mapeos, y no confiarse en valores predeterminados. Desde este punto, las cosas se vuelven realmente fáciles. Para crear un nuevo músico usted puede usar el siguiente código:
<cfscript>
import com.*;
john = new Musico("John Doe");
john.setEdad(47);
EntitySave(john);
</cfscript>
Este código simplemente crea un nuevo objeto Musico, define algunas propiedades en este, y llama EntitySave(). Este método tomara el objeto que se le pasó y lo persistirá en la base de datos, sin que usted tenga que escribir ninguna sentencia de SQL. Esto creara la tabla para usted. (Imagen 1 e Imagen 2)

Para recuperar los datos de John y cambiar su edad, usted puede usar lo siguiente (vea Imagen 3)
<cfscript>
//El id de John es 1
john = EntityLoad("Musico", 1, true);
john.setEdad(22);
</cfscript>
El primer argumento para EntityLoad() es el nombre de entidad del CFC que quiere cargar, el cual por defecto es el mismo del CFC, aunque este puede ser sobrescrito. El segundo argumento es el id del Musico que quiere cargar. Para requerir un único resultado, usted tiene que especificar como true el tercer argumento, de otra manera EntityLoad() devolverá una matriz en vez de un solo valor.
Nota: EntityLoad() puede ser usado para retornar una matriz de CFCs, filtrados por criterio, pero no cubriré eso en este articulo.
Note que en este código no le dije a Hibernate explícitamente que actualice John. Hibernate mantiene un registro de que CFCs han sido cargados y si han cambiado desde su estado inicial. En este caso, este puede observar que la propiedad edad de John ha cambiado, y al final de la petición este actualizara la base de datos consecuentemente. Usted puede llamar a EntitySave() en John cuando está actualizando este objeto, pero la llamada simplemente es ignorada por Hibernate cuando el objeto ya esta persistido en la base de datos.

Nota: Por razones de rendimiento, Hibernate generalmente ejecutara en un archivo de lotes sus sentencias SQL al final de una petición HTTP. Consecuentemente, aunque si usted usa EntitySave() en medio del bloque de código, el código de inserción de SQL puede no ser ejecutado en la base de datos hasta el final de la petición. Hay métodos para forzar que el código de SQL sea ejecutado, lo cual se puede leer en ColdFusion 9 Developer Guide – Hibernate session management.
Finalmente, si usted decide que usted no necesita más a John, usted puede borrarlo:
<cfscript>
//El id de John es 1
john = EntityLoad("Musico", 1, true);
EntityDelete(john);
</cfscript>
John no está más persistido en la base de datos (mire Imagen 4)

Usted ahora tiene completa la funcionalidad de crear, leer, actualizar, y eliminar sin tener que escribir SQL o crear ninguna tabla. ¡Hibernate y ColdFusion 9 beta han hecho todo el trabajo pesado por usted!
Generalmente hablando, los CFCs tienden a no trabajar tan bien solos, sino mejor cuando hay grupos de ellos que saben el uno acerca del otro. Por ejemplo. ¿Qué haría un Musico sin un conjunto de instrumentos para tocar?
Hay una variedad de tipos de relaciones que usted puede mapear con la integración ORM. En este articulo, me enfocare en una relación muchos-a-muchos con un Instrumento, y permitiré que los Musicos compartan instrumentos dentro del grupo, así que múltiples Musicos pueden tener acceso al mismo Instrumento al mismo tiempo. Esto le debería dar la suficiente información para que usted pueda explorar todos los otros tipos de relaciones que la integración de ColdFusion con Hibernate soporta.
Primero, defino el componente Instrumento así como lo hice con el componente Musico.
Instrumento.cfc
<cfcomponent hint="Un instrumento" persistent="true" output="false">
<cfproperty name="instrumentoID" hint="id for the instrument" fieldtype="id" ormtype="integer" generator="identity">
<cfproperty name="nombre" hint="El nombre del instrumento" type="string" length="255"/>
<cfproperty name="sonido" hint="El sonido que produce" type="string" length="255"/>
<cffunction name="init" hint="Constructor" access="public" returntype="Instrumento" output="false">
<cfargument name="nombre" hint="El nombre del instrumento" type="string" required="no" default="">
<cfargument name="sonido" hint="El sonido que produce" type="string" required="false" default="">
<cfscript> this.setNombre(arguments.nombre); this.setSonido(arguments.sonido); return this; </cfscript> </cffunction> </cfcomponent>
También necesito agregar una nueva propiedad <cfproperty> al Musico para decirle acerca del conjunto de instrumentos al cual tendrá acceso. Cambio el código de Musico.cfc para que quede así:
Musico.cfc
<cfcomponent hint="Soy un musico" output="false" persistent="true">
<cfproperty name="musicoID" hint="El id para un musico" fieldtype="id" type="numeric" ormtype="integer" generator="identity">
<cfproperty name="nombre" hint="Nombre del musico" type="string" length="255">
<cfproperty name="edad" hint="Edad del musico" type="numeric" ormtype="integer">
<cfproperty name="transient" hint="propiedad transitoria" type="string" generated="never" persistent="false" />
<cfproperty name="instrumentos" hint="Conjunto de instrumentos" singularname="instrumento"
fieldtype="many-to-many" collectiontype="array" cfc="orm.com.Instrumento" linktable="musico_instrumento"
FKColumn="musicoID" inversejoincolumn="instrumentoID"
orderby="name">
<cffunction name="init" hint="Constructor" access="public" returntype="Musico" output="false">
<cfargument name="nombre" hint="el nombre del musico" type="string" required="no" default="">
<cfscript>
this.setNombre(arguments.nombre);
return this;
</cfscript>
</cffunction>
</cfcomponent>
He agregado una nueva etiqueta <cfproperty> llamada instrumentos para definir una collación de muchos-a-muchos. Definí el atributo fieldtype a “many-to-many”, y definí el atributo cfc a “com.Instrumento”, el cual es el CFC para los ítems en la collación. El atributo orderby establecerá que los Instrumentos serán ordenados por nombre dentro del conjunto de Instrumentos.
Nota: Al momento de esta publicación, se requiere incluir los atributos linktable, FKColumn e inversejoincolumn, para decirle a Hibernate cual es tabla que será vinculada y la clave foránea. Sin embargo, estos atributos pueden convertirse en opcionales y tener valores predefinidos.
El código de arriba crea la tabla de relaciones muchos-a-muchos cuando ORM se inicia, así como también un conjunto de métodos que pueden usarse en el objeto Musico para agregar o remover Instrumentos:
<cfscript>
import com.*;
joan = new Musico("Joan Doe");
joan.setEdad("51");
EntitySave(joan);
//preparamos algunos instrumentos antes
//la flauta es el instrumento 1
flauta = EntityLoad("Instrumento",1,true);
//demosle a Joan la flauta
joan.addInstrumento(flauta);
//el piano es el instrumento 2
piano = EntityLoad("Instrumento",2,true);
//demosle a Joan el piano
joan.addInstrumento(piano);
</cfscript>
En este caso, el método addInstrument() obtiene el nombre del atributo singularname definido en la configuración de muchos-a-muchos. Para mostrar todos los instrumentos de John que usted puede usar:
<cfoutput>
Los instrumentos de Joan: <br/>
<cfloop array=#joan.getInstrumentos()# index="instrumento">
Soy un instrumento #instrumento.getNombre()#, y produzco el sonido #instrumento.getSonido()# <br/>
</cfloop>
</cfoutput>
El código anterior produciría la salida mostrada en la Figura 5.
Las tablas Instrumento,Musico y musico_instrumento que se muestran en la Figura 6 fueron creadas automáticamente.

Después de que agregue el piano y la flauta de la tabla Instrumentos (vea Imagen 7) a John, la tabla músico_instrumento persiste las relaciones (vea Imagen 8)


La integración ColdFusion-Hibernate puede reducir considerablemente la cantidad de trabajo que usted como desarrollador necesita hacer para persistir datos cuando construye aplicaciones, los ejemplos aquí mostrados solo muestran la punta del iceberg. No se discutió en este artículo una gran variedad de funcionalidad altamente configurable de Hibernate que se ha incluido en ColdFusion, incluyendo las utilidades para hacer consultas, cacheo, manejo de eventos de persistencia, y varias otras herramientas para administrar datos de aplicaciones. Habiendo dicho esto, aun usando las características más básicas de ORM puede mejorar radicalmente cuán rápido y eficientemente usted desarrolla aplicaciones de ColdFusion.
Para aprender más acerca de la funcionalidad de ORM en ColdFusion visite los siguientes sitios:

This work is licensed under a
Creative Commons Attribution-Noncommercial-Share Alike 3.0 Unported License