You are on page 1of 198

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

HIBERNATE - Persistencia relacional para Java Idiomtico


Documentacin de Referencia de Hibernate
3.3.1 Traductor: Gonzalo Daz Copyright 2004 Red Hat Middleware, LLC. Prefacio 1. Introduccin a Hibernate 1.1. Prefacio 1.2. Parte 1 - La Primera Aplicacin Hibernate 1.2.1. La primera clase 1.2.2. El archivo de mapeo 1.2.3. Configuracin de Hibernate 1.2.4. Construyendo con Ant 1.2.5. Comienzo y ayudantes 1.2.6. Cargar y almacenar objetos 1.3. Parte 2 - Mapear asociaciones 1.3.1. Mapear la clase Person 1.3.2. Una asociacin unidireccional basada en un Set 1.3.3. Trabajar con la asociacin 1.3.4. Coleccin de valores 1.3.5. Asociaciones bidireccionales 1.3.6. Trabajar con vnculos bidireccionales 1.4. Parte 3 - La aplicacin de web "Event Manager" 1.4.1. Escribir el servlet bsico 1.4.2. Procesamiento y presentacin 1.4.3. Despliegue (deploy) y test 1.5. Sumario 2. Arquitectura 2.1. Generalidades 2.2. Estados de una instancia 2.3. Integracin con JMX 2.4. Soporte de JCA 2.5. Sesiones contextuales 3. Configuracin 3.1. Configuracin programtica 3.2. Obtener una SessionFactory 3.3. Conexiones JDBC 3.4. Propiedades optativas de configuracin 3.4.1. Dialectos de SQL 3.4.2. Captura (fetching) por Outer Join 3.4.3. Streams Binarios 3.4.4. Cach de 2do nivel y cach de consultas 3.4.5. Sustituciones en el lenguaje de consultas. 3.4.6. Estadsticas de Hibernate 3.5. Logueo (logging, bitcora) 3.6. Implementando una NamingStrategy 3.7. Archivo de configuracin XML 3.8. Integracin con los Servidores de Aplicacin J2EE 3.8.1. Configuracin de una estrategia transaccional 3.8.2. SessionFactory ligada a JNDI 3.8.3. Manejo del contexto actual de la sesin con JTA 3.8.4. Despliegue de JMX 4. Clases Persistentes 4.1. Un simple ejemplo de POJO

1 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

4.1.1. Implemente un constructor sin argumentos 4.1.2. Porvea una propiedad identificadora (optativo) 4.1.3. Prefiera clases que no sean finales (optativo) 4.1.4. Declare mtodos de acceso y "mutadores" (accessors, mutators) para los campos persistentes. 4.2. Implementar herencia 4.3. Implementar equals() y hashCode() 4.4. Modelos dinmicos 4.5. T-uplizadores 4.6. Extensiones 5. Mapeo O/R bsico 5.1. Declaracin del mapeo 5.1.1. El Doctype o "tipo de documento XML" 5.1.1.1. EntityResolver 5.1.2. hibernate-mapping 5.1.3. class 5.1.4. id 5.1.4.1. Generator 5.1.4.2. El algoritmo hi/lo 5.1.4.3. El argoritmo UUID 5.1.4.4. Columnas de identidad y secuencias 5.1.4.5. Identificadores asignados 5.1.4.6. Claves primarias assignadas por triggers 5.1.5. Generadores de identificador mejorados. 5.1.6. Optimizacin de los generadores de identificador 5.1.7. composite-id 5.1.8. discriminator 5.1.9. version (optativo) 5.1.10. timestamp (optativo) 5.1.11. property 5.1.12. many-to-one 5.1.13. one-to-one 5.1.14. natural-id 5.1.15. component, dynamic-component 5.1.16. properties 5.1.17. subclass 5.1.18. joined-subclass 5.1.19. union-subclass 5.1.20. join 5.1.21. key 5.1.22. elementos column y formula 5.1.23. import 5.1.24. any 5.2. Tipos de Hibernate 5.2.1. Entidades y "value types" 5.2.2. "Value types" bsicos 5.2.3. "Value types" hechos a medida 5.3. Mapear una misma clase ms de una vez 5.4. Identificadores de SQL entrecomillados 5.5. Alternativas de meta-datos 5.5.1. Usar marcadores de XDoclet 5.5.2. Usar anotaciones de JDK 5.0 5.6. Propiedades generadas 5.7. Objetos auxiliares de base de datos 6. Mapeo de Colecciones 6.1. Colecciones persistentes 6.2. Mapeo de colecciones 6.2.1. Claves forneas de las colecciones 6.2.2. Elementos de la coleccin 6.2.3. Colecciones indexadas 6.2.4. Colecciones de valores y asociaciones de-muchos-a-muchos 6.2.5. Asociaciones de-uno-a-muchos 6.3. Mapeos de coleccin avanzados 6.3.1. Colecciones ordenadas

2 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

6.3.2. Asociaciones bidireccionales 6.3.3. Asociaciones bidireccionales con colecciones indexadas 6.3.4. Asociaciones ternarias 6.3.5. Usar una <idbag> 6.4. Ejemplos de colecciones 7. Mapeo de asociaciones 7.1. Introduccin 7.2. Asociaciones unidireccionales 7.2.1. de-muchos-a-uno 7.2.2. de-uno-a-uno 7.2.3. de-uno-a-muchos 7.3. Asociaciones unidireccionales con tablas de unin 7.3.1. de-uno-a-muchos 7.3.2. de-muchos-a-uno 7.3.3. de-uno-a-uno 7.3.4. de-muchos-a-muchos 7.4. Asociaciones bidireccionales 7.4.1. de-uno-a-muchos / de-muchos-a-uno 7.4.2. de-uno-a-uno 7.5. Asociaciones bidireccionales con tablas de unin 7.5.1. de-uno-a-muchos / de-muchos-a-uno 7.5.2. de-uno-a-uno 7.5.3. de-muchos-a-muchos 7.6. Mapeos de asociacoones ms complejas 8. Mapeo de componentes 8.1. Objetos dependientes 8.2. Colecciones de objetos dependientes 8.3. Comonentes usados como ndices de un Map 8.4. Componentes usados como identificadores compuestos 8.5. Componentes dinmicos 9. Mapeo de herencia 9.1. Las tres estrategias 9.1.1. Una tabla por jerarqua de clases 9.1.2. Una tabla por subclase 9.1.3. Una tabla por subclase, usando un discriminador 9.1.4. Mezclar "una tabla por jerarqua de clases" con "una tabla por subclase" 9.1.5. Una tabla por cada clase concreta 9.1.6. Una tabla por cada clase concreta, usando polimorfismo implcito 9.1.7. Mezclar polimorfismo implcito con otras estrategias de mapeo de herencia 9.2. Limitaciones 10. Trabajar con objetos 10.1. Estados de un objeto de Hibernate 10.2. Hacer que los objetos se vuelvan persistentes 10.3. Cargar un objeto 10.4. Consultas 10.4.1. Ejecutar consultas 10.4.1.1. Iterar resultados 10.4.1.2. Consultas que devuelven T-uplas 10.4.1.3. Resultados escalares 10.4.1.4. Parmetros vinculados 10.4.1.5. Paginacin 10.4.1.6. Iteracin navegable 10.4.1.7. Externalizar consultas nombradas 10.4.2. Filtrar colecciones 10.4.3. Consultas "Criteria" 10.4.4. Consultas en SQL nativo 10.5. Modificar objetos persistentes 10.6. Modificar objetos desprnendidos 10.7. Deteccin automtica de estado 10.8. Borrar objetos persistentes 10.9. Replicar un objeto entre dos repositorios de datos distintos 10.10. "Flush" de la sesin 10.11. Persistencia transitiva

3 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

10.12. Usar metadatos 11. Transacciones y concurrencia 11.1. La sesin y el alcance (scope) de las transacciones 11.1.1. Unidad de trabajo 11.1.2. Conversaciones largas 11.1.3.Considerar la identidad de los objetos 11.1.4. Problemas comunes 11.2. Demarcacin de las transacciones de base de datos 11.2.1. Entornos no administrados 11.2.2. Usar JTA 11.2.3. Manejo de excepciones 11.2.4. Expiracin de transacciones 11.3. Control optimista de concurrencia 11.3.1. Chequeo de versin hecho por la aplicacin 11.3.2. Sesin extendida y versionado automtico 11.3.3. Objetos desprendidos y versionado automtico 11.3.4. Crear un mtodo a medida para el versionado automtico 11.4. "Lock" pesimista 11.5. Modos de liberacin de conecciones 12. Interceptores y eventos 12.1. Interceptores 12.2. Sistema de eventos 12.3. Seguridad declarativa de Hibernate 13. Procesamiento en lotes 13.1. Inserciones en lotes 13.2. Actualizaciones en lotes 13.3. La interfaz StatelessSession 13.4. Operaciones del tipo "Lenguaje de Modificacion de Datos" (DML-style) 14. HQL: El lenguaje de consultas de Hibernate 14.1. Relevancia de maysculas y minsculas 14.2. La clusula "from" 14.3. Asociaciones y "joins" 14.4. Formas de la sintaxis de los "joins" 14.5. Referirse a la propiedad identificadora 14.6. La clusula "select" 14.7. Funciones agregadas 14.8. Consultas polimrficas 14.9. La clusua "where" 14.10. Expresiones 14.11. La clusula "order by" 14.12. La clusula "group by" 14.13. Subconsultas 14.14. Ejemplos de HQL 14.15. Actualizaciones y borrados en masa 14.16. Consejos y trucos 14.17. Componentes 14.18. Sintaxis del "Constructor de Valor de Fila" (row value constructor) 15. Consultas "Criteria" 15.1. Crear una instancia de Criteria 15.2. Acotar el resultado 15.3. Ordenar el resultado 15.4. Asociaciones 15.5. Captura dinmica de asociaciones 15.6. Consultas "Example" 15.7. Proyecciones, agregado y agrupamiento 15.8. Consultas y subconsultas desprendidas 15.9. Consultas por identificador natural 16. SQL nativo 16.1. Usar un SQLQuery 16.1.1. Consultas escalares 16.1.2. Consultas con entidades 16.1.3. Manipular colecciones y asociaciones 16.1.4. Devolver mltiples entidades

4 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

16.1.4.1. Alias y referencias a propiedades 16.1.5. Devolver entidades no administradas 16.1.6. Manejar herencia 16.1.7. Parmetros 16.2. Consultas SQL nombradas 16.2.1. Usar return-property para especificar nombres de columna/alias explcitamente 16.2.2. Usar procedimientos almacenados (stored procedures) para efectuar consultas 16.2.2.1. Reglas y limitaciones en el uso de procedimientos almacenados 16.3. SQL a medida para crear, almacenar y borrar 16.4. SQL a medida para cargar 17. Filtrar datos 17.1. Filtros de Hibernate 18. Mapeo XML 18.1. Trabajar con datos XML 18.1.1. Especificar el mapeo XML y el mapeo de la clase al mismo tiempo 18.1.2. Especificar slo un mapeo XML 18.2. Metadatos del mapeo XML 18.3. Manipulacin de los datos XML 19. Mejorar la performance 19.1. Estrategias de captura (fetch) 19.1.1. Trabajar con asociaciones haraganas 19.1.2. Ajustar las estrategias de captura 19.1.3. Proxies de las asociaciones de un solo extremo 19.1.4. Inicializar colecciones y proxies 19.1.5. Usar la captura por lotes 19.1.6. Usar la captura mediante subselects 19.1.7. Usar la captura de propiedades haragana 19.2. El cach de 2do nivel 19.2.1. Mepeos de cach. 19.2.2. Estrategia de slo lectura 19.2.3. Estrategia de lecto/escritura 19.2.4. Estrategia de lecto/escritura no estricta 19.2.5. Estrategia transaccional 19.2.6. Compatibilidad entre el proveedor de cach y la estrategia de concurrencia 19.3. Admninistrar los cachs 19.4. El cach de consultas (query cache) 19.5. Comprender la performance de las colecciones 19.5.1. Taxonoma 19.5.2. Las lists, maps, idbags y sets son las colecciones ms eficientes de actualizar 19.5.3. Las bags y lists son las colecciones inversas ms eficientes 19.5.4. Borrado en una pasada 19.6. Monitorear la performance 19.6.1. Monitorear una SessionFactory 19.6.2. Mediciones 20. Gua de las herramientas (Toolset) 20.1. Generacin automtica del esquema de base de datos 20.1.1. Retocar el esquema de base de datos 20.1.2. Ejecutar la herramienta 20.1.3. Propiedades 20.1.4. Usar Ant 20.1.5. Actualizaciones incrementales del esquema de base de datos 20.1.6. Utilizar Ant para las actualizaciones incrementales del esquema de base de datos 20.1.7. Validacin del esquema de base de datos 20.1.8. Usar Ant para la validacin del esquema de base de datos 21. Ejemplo: Padre/Hijo 21.1. Nota sobre las colecciones 21.2. de-uno-a-muchos bidireccional 21.3. Ciclo de vida de las propagaciones en cascada 21.4. Propagaciones en cascada y unsaved-value 21.5. Conclusin 22. Ejemplo: La aplicacin Weblog 22.1. Clases persistentes 22.2. Mapeos de Hibernate

5 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

22.3. Cdigo Hibernate 23. Ejemplo: Mapeos varios 23.1. Empleador/Empleado 23.2. Autor/Obra 23.3. Cliente/Orden/Producto 23.4. Ejemplos miscelneos de asociacin 23.4.1. Asociacin de-uno-a-uno "con tipo" 23.4.2. Ejemplo de clave compuesta 23.4.3. de-muchos-a-muchos con atributo compartido de clave compuesta 23.4.4. Discriminacin basada en el contenido 23.4.5. Asociaciones en claves alternativas 24. Prcticas recomendadas

Prefacio
Trabajar con software orientado a objetos y bases de datos relacionales, puede ser embarazoso y demandar mucho tiempo, en los entornos corporativos actuales. Hibernate es una herramienta de mapeo objeto/relacional para ambientes Java. El trmino "mapeo objeto/relacional" (ORM por sus siglas en ingls) se refiere a esta tcnica de "mapear" la representacin de los datos desde un modelo de objetos hacia un modelo de datos relacional, con un esquema de base de datos basado en SQL. Hibernate no slo se hace cargo del mapeo de clases Java a las tablas de una base de datos (y de los tipos Java a los tipos de la base de datos), sino que tambin provee utilidades para consulta y captura de datos, y puede reducir considerablemente el tiempo que, de otra manera, habra que invertir con el manejo manual de datos mediante SQL y JDBC. La meta de Hibernate es aliviar al programador del 95% de las tareas ms comunes relacionadas con persistencia. Probablemente, Hibernate no sea la mejor solucin para aplicaciones data-cntricas que tengan casi toda su lgica de negocios en procedimientos almacenados (stored procedures) en la base de datos; es ms til con modelos orientados a objetos cuya lgica de negocio reside en la capa intermedia. Sin embargo, Hibernate puede ayudarlo a encapsular o eliminar cdigo SQL que sea especfico de un proveedor de BD, y ayudar en la tarea usual de traducir desde una representacin tabular a un grfico de objetos. Si usted es nuevo en Hibernate y en lo que respecta al Mapeo objeto/relacional, o incluso nuevo en Java, por favor siga los siguientes pasos: Lea el siguiente instructivo: Captulo 1, Introduccin a Hibernate, el cual es una especie de manual con instrucciones paso a paso. El cdigo fuente del instructivo est incluido en la distribucin descargable, en el directorio doc/reference/tutorial/ Lea Captulo 2, Arquitectura para entender en qu entornos Hibernate puede ser usado. chele un vistazo al directorio eg/ en la distribucin de Hibernate. Contiene una simple aplicacin autosuficiente. Copie su driver de JDBC al directorio lib/ y edite etc/hibernate.properties, especificando valores correctos para su base de datos. Desde la consola, situado en el directorio de distribucin, tipee ant eg (usando Ant), o desde Windows, tipee build eg. Use esta documentacin de referencia como su fuente primaria de informacin. Considere leer Java Persistence with Hibernate (http://www.manning.com/bauer2) si necesita ms ayuda con el diseo de aplicaciones o si prefiere un instructivo paso a paso. Tambin visite http://caveatemptor.hibernate.org y descargue la aplicacin de ejemplo para Persistencia de Java con Hibernate. Las preguntas frecuentes (FAQ, por sus siglas en ingls), son contestadas en el sitio de web de Hibernate. En el sitio de web de Hibernate hay vnculos a demostraciones de terceros, ejemplos e instructivos. El rea Comunitaria del sitio de web de Hibernate es un buen recurso acerca de patrones de diseo y varias soluciones de integracin (Tomcat, JBoss AS, Struts, EJB, etc). Si tiene preguntas, utilice el foro en el sitio de Hibernate. Tambin proveemos un sistema JIRA de seguimiento de problemas, para reportes de defectos (bugs) y pedidos de mejoras. Si a usted le interesa la programacin de Hibernate, nase a la lista de correo de programacin de Hibernate. Si le interesa traducir este documento, pngase en contacto con nosotros en la lista de correo de programacin.

6 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

A travs de JBoss Inc, hay disponible soporte para desarrollo comercial y de produccin, y entrenamiento para Hibernate. (vase http://www.hibernate.org/SupportTraining/). Hibernate es un componente vital del paquete de productos conocido como "Sistema Empresarial JBoss de Middleware" (JEMS, por sus siglas en ingls).

Captulo 1. Introduccin a Hibernate 1.1. Prefacio


Este captulo es una introduccin a Hibernate, con el tono de un instructivo, destinado a usuarios nuevos de Hibernate. Empezamos con una simple aplicacin que usa una base de datos residente en memoria. Construimos la aplicacin de a pasos pequeos, fciles de comprender. Este instructivo se basa en otro anterior, escrito por Michael Gloegl. Todo el cdigo est contenido en el directorio tutorials/web del cdigo fuente del proyecto.

Importante
Este instructivo sobreentiende que el usuario ya tiene conocimiento de Java y de SQL. Si cualquiera de ambos es nuevo para usted, o no se maneja bien ellos, le recomendamos que comience con una buena introduccin a estas tecnologas, antes de adentrarse en Hibernate. A la larga, le ahorrar tiempo y esfuerzo.

Nota
Hay otra aplicacin a modo de ejemplo/instructivo en el directorio del cdigo fuente /tutorials/eg. Dicho ejemplo se basa en lnea de comandos (consola), y como tal no depende de un contenedor de servlets para poder ser ejecutado. El montaje (setup) bsico es el mismo que para las instrucciones a continuacin.

1.2. Parte 1 - La primera aplicacin Hibernate


Supongamos que tenemos una pequea aplicacin de base de datos que puede almacenar eventos a los que queremos asistir, e informacin acerca del anfitrin (o anfitriones) de dichos eventos. Vamos a usar una base de datos residente en memoria, llamada HSQLDB, para evitar describir la instalacin y configuracin de cualquier base de datos en particular. Sintase en libertad de usar cualquier base de datos con la que est familiarizado. Lo primero que tenemos que hacer es montar nuestro entorno de desarrollo, y, especficamente, instalar todas las dependencias que Hibernate necesita, as como otras bibliotecas (libraries). Hibernate se construye usando Maven, el cual, entre otras cosas, provee manejo de dependencias. Ms an: provee un manejo transitivo de dependencias, lo cual simplemente significa que para usar Hibernate podemos definir nuestras dependencias dentro de l: Hibernate mismo define las dependencias que necesita, las cuales se convierten en "transitivas".
. <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4. ... <dependencies> <dependency> <groupId>${groupId}</groupId> <artifactId>hibernate-core</artifactId> </dependency> <!-- Como sta es una aplicacin de web, tambin necesitamos una dependencia a la API de se <dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> </dependency> </dependencies> </project>

7 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

Nota
Bsicamente, aqu estamos describiendo el archivo /tutorials/web/pom.xml. Vea el sitio de Maven para ms informacin.

Consejo
Aunque no es estrictamente necesario, muchos entornos visuales de progrmacin (IDEs) ya cuentan con integracin con Maven para leer estos archivos POM, y automticamente generar el proyecto por usted (lo cual puede ahorrar mucho tiempo y esfuerzo). Luego creamos una clase que representa el evento que queremos almacenar en la base de datos.

1.2.1. La primera clase


Nuestra primera clase persistente es un simple JavaBean con algunas propiedades.
package org.hibernate.tutorial.domain; import java.util.Date; public class Event { private Long id; private String title; private Date date; public Event() {} public Long getId() { return id; } private void setId(Long id) { this.id = id; } public Date getDate() { return date; } public void setDate(Date date) { this.date = date; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } }

Se puede ver que esta clase usa la convencin estndar de JavBeans para nombrar a sus mtodos "setter" y "getter" (escritura y lectura de propiedades, respectivamente). Este diseo es el recomendado - pero no es obligatorio. Hibernate puede aceder a los campos directamente; la ventaja de los mtodos de acceso es proveer mayor solidez a la hora de refinar ("refactoring") el cdigo. El constructor sin argumentos s es obligatorio, para poder instanciar el objeto mediante reflexin. La propiedad identificadora o id contiene un identificador nico para un evento en particular. Todas las clases de entidad persistentes (las hay menos importantes tambin) necesitarn dicho id, si queremos usar a pleno las capacides de Hibernate. De hecho, la mayora de las aplicaciones (especialmente aplicaciones de web), ya necesitan distinguir objetos por id, as que esta caracterstica debera considerarse una ventaja, ms que una limitacin. De todos modos, usualmente no manipulamos directamente la identidad de un objeto, as que el mtodo "setter" del id debera ser privado. Slo Hibernate asigna ids, cuando el objeto es grabado. Hibernate puede acceder a mtodos en cualquier nivel de acceso (protected, public, private, etc) directamente. La opcin de qu nivel de acceso utilizar es suya, segn el diseo de su aplicacin.

8 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

El constructor sin argumentos es obligatorio para todas las clases persistentes; Hibernate tiene que crear los objetos para usted utilizando Java Reflection. El constructor puede ser privado; sin embargo, para poder generar "proxies" en tiempo de ejecucin, y para la captura de datos sin la construccin de bytecode, se requiere al menos el nivel de acceso "package" o por defecto. Ponga este archivo de cdigo fuente Java en un directorio llamado src en el directorio de desarrollo, y dentro del paquete correspondiente. El directorio debera verse as:
. +lib <bibliotecas de Hibernate y de terceros> +src +events Event.java

En el paso siguiente, le vamos a informar a Hibernate acerca de esta clase persistente.

1.2.2. El archivo de mapeo


Hibernate necesita saber cmo cargar y almacenar objetos de la clase persistente. Aqu es donde entra en juego el archivo de mapeo. ste le dice a Hibernate a qu tabla en qu base de datos tiene que acceder, y qu columnas de dicha tabla tiene que utilizar. La estructura bsica del archivo de mapeo se ve as:
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping> [...] </hibernate-mapping>

Ntese que la DTD de Hibernate es bastante sofisticada. La puede usar para autocompletar elementos de mapeo y atributos de XML en su indetfaz grfica (IDE). Tambin puede abrir la el archivo de la DTD en su procesador de texto - es la forma ms fcil de tener una visin general de todos los elementos, y de ver los valores por defecto, junto con algunos comentatios. Sepa que Hibernate no buscar la DTD en la red, sino en el classpath. La DTD est incluida en el archivo, hibernate3.jar, as como en el directorio src/ de la distribucin de Hibernate. En los ejemplos sucesivos, omitiremos la declaracin de la DTD, por brevedad. Por supuesto, sta no es optativa. Entre las dos tags hibernate-mapping, incluya un elemento class. Todas las clases de entidad persistente (de nuevo: hay clases dependientes, como veremos luego, que no son entidades de primer nivel) necesitan dicho mapeo, a una tabla en la base de datos SQL.
<hibernate-mapping> <class name="events.Event" table="EVENTS"> </class> </hibernate-mapping>

Hasta el momento, le hemos dicho a Hibernate cmo persistir y cargar un objeto de la clase Event en la tabla EVENTS, cada instancia representando un registro de la tabla. Ahora continuamos con el mapeo del identificador nico a la clave primaria de la tabla. Por aadidura, como no queremos preocuparnos por manipular dicho identificador, configuramos una "estrategia de generacin de identificador" de Hibernate para que use una clave primaria "sustituta" (surrogate key).
<hibernate-mapping> <class name="events.Event" table="EVENTS"> <id name="id" column="EVENT_ID"> <generator class="native"/> </id> </class>

9 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

</hibernate-mapping>

El elemento id es la declaracuin de la propiedad indentificadora. El atributo name="id" declara el nombre de la propiedad Java - Hibernate usar los mtodos getter y setter para acceder a ella. El atributo "column" le dice a Hibernate qu columna de la tabla EVENTS usamos como clave primaria. El elemento anidado generator especifica la estrategia para la generacin de identificador. En este caso, usamos native, la cual elige la mejor estrategia dependiendo de la BD y dialecto configurados. Hibernate soporta tanto identificadores generados por la base de datos, como globalmente nicos, o asignados por la aplicacin (o generados por cualquier estrategia para la cual usted haya escrito una extensin). Finalmente, incluimos declaraciones para las propiedades persistentes en el archivo de mapeo. Por defecto, ninguna de las propiedades de la clase se considera persistente.
<hibernate-mapping> <class name="events.Event" table="EVENTS"> <id name="id" column="EVENT_ID"> <generator class="native"/> </id> <property name="date" type="timestamp" column="EVENT_DATE"/> <property name="title"/> </class> </hibernate-mapping>

Igual que con el elemento id, el atributo name del elemento property le dice a Hibernate qu mtodos getter y setter usar. As que, en este caso, Hibernate buscar getDate()/setDate(), as como getTitle()/setTitle(). Por qu el mapeo de la propiedad date incluye el atributo column, pero el title no? A falta del atributo column, Hibernate por defecto usa el nombre de la propiedad como nombre de columna. Esto funciona para title. Pero date es una palabra reservada en la mayora de las base de datoss, as que mejor la mapeamos con un nombre diferente. Otra cosa interesante, es que el mapeo title tambin carece del atributo type. Los tipos que usamos en los archivos de mapeo no son, como es de esperarse, tipos Java. Tampoco son tipos SQL. A estos tipos se los llama Tipos de mapeo de Hibernate, conversores que podemos traducir de tipos Java a SQL y viceversa. De nuevo, Hibernate tratar de determinar la conversin adecuada e incluso el tipo mismo, si el atributo type no se especifica en el mapeo. En algunos casos, esta deteccin automtica (que usa Java Reflection) puede no generar el valor por defecto que usted esperaba o necesita. se es el caso con la propiedad date. Hibernate no puede saber si la propiedad, que es del tipo java.util.Date, debera ser mapeada a una columna timestamp, o a una columna time. En este caso, mantengamos la informacin completa (de da y hora) mapeando la propiedad al conversor timestamp. Este achivo de mapeo debera ser grabado como Event.hbm.xml, justo en el mismo directorio que el archivo Java de la clase Event. El nombre de los archivos de mapeo puede ser arbitrario, pero los sufijos hbm.xml son una convencin en la comunidad de programadores de Hibernate. Ahora la estructura de directorios debera verse as:
. +lib <bibliotecase de Hibernate y de terceros> +src +events Event.java Event.hbm.xml

Continuamos con la configuracin principal de Hibernate

1.2.3. Configuracin de Hibernate


Ahora tenemos ubicados una clase persistente y su archivo de mapeo. Es el momento de configurar Hibernate mismo. Antes de hacerlo, necesitamos una base de datos. HSQLBD es una base de datos basada en Java; puede ser descargada del sitio de web de HSQL DB (http://hsqldb.org/). En ralidad, usted slo necesita hsqldb.jar de dicha descarga. Coloque este archivo en el directorio lib/ del directorio de desarrollo. Cree un directorio llamado data en la raz del directorio de desarrollo - es ah en donde HSQL DB almacenar sus archivos de datos. Ahora, haga arrancar la base de datos ejecutando: java -classpath ../lib/hsqldb.jar org.hsqldb.Server en este directorio de datos. Usted podr ver que arranca y est ligada a un socket TPC/IP. Ah es donde nuestra aplicacn se conectar luego. Si quiere comenzar con una base de datos nueva en el transcurso de este instructivo, cierre la base de datos HSQL DB pulsando CTRL + C en la ventana, borre todos los archivos en el

10 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

subdirectorio data/, y arranque HSQL DB nuevamente. Hibernate es la capa de su aplicacin que se conecta con esta base de datos, as que necesita informacin de conexin. Las conexiones se hacen mediante un pool de conexiones JDBC, el cual tambin tenemos que configurar. La distribucin de Hibernate contiene varias herramientas de cdigo abierto (open source) que generan pool de conexiones , pero para este instructivo usaremos el pool que ya viene incorporado en Hibernate. Dse cuenta de que, si quiere usar un pool de conexiones JDBC de mayor calidad (para aplicaciones ya instaladas en produccin) hecho por terceros, deber copiar las bibliotecas que hagan falta en el classpath, y usar propiedades de conexin diferentes. Para la configuracin de Hibernate, podemos usar un simple archvo hibernate.properties, un archivo hibernate.cfg.xml un tanto ms sofisticado, o incluso una configuracin totalmente programtica. La mayora prefiera el archivo de configuracin XML.
<?xml version='1.0' encoding='utf-8'?> <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"> <hibernate-configuration> <session-factory> <!-- datos de conexin de la BD --> <property name="connection.driver_class">org.hsqldb.jdbcDriver</property> <property name="connection.url">jdbc:hsqldb:hsql://localhost</property> <property name="connection.username">sa</property> <property name="connection.password"></property> <!-- pool de conexiones JDBC (usamos el que ya viene incorporado) -->

<property name="connection.pool_size">1</property> <!-- dialecto SQL --> <property name="dialect">org.hibernate.dialect.HSQLDialect</property> <!-- habilita el manejo automtio de contexto de sesin por parte de Hibernate --> <property name="current_session_context_class">thread</property> <!-- inhabilita el cach de 2do nivel --> <property name="cache.provider_class">org.hibernate.cache.NoCacheProvider</property> <!-- imprime todo el SQL ejecutado en la salida estndar <property name="show_sql">true</property> <!-- borra y recrea la BD en cada arranque --> <property name="hbm2ddl.auto">create</property> <mapping resource="events/Event.hbm.xml"/> </session-factory> </hibernate-configuration> -->

Fjese en que este archivo de configuracin XML usa una DTD distinta. Configuramos la SessionFactory de Hibernate una fabrica global responsable de una base de datos en particular. Si tiene varias base de datos, use varias configuraciones de <session-factory> por lo comn en otros tantos archivos de configuracin (para un arranque ms fcil). Los primeros 4 elementos property contienen la configuracin necesaria para la conexn JDBC. La propiedad "dialect" especifica la variante de SQL en particular que Hibernate genera. El manejo automtico de sesiones por contextos de persistencia ser muy til, como pronto veremos. La opcin hbm2ddl.auto activa la generacin automtica de esquemas directamente en la BD. Esto por supuesto puede ser desactivado (quitando esta opcin) o ser redirigido a un archivo, con la ayuda de la tarea de Ant SchemaExport. Fnalmente, agregamos el o los archivo de mapeo para las clases persistentes a la configuracin. Copie este archivo en el directorio de fuentes (src), de manera que quede en la raz del classpath. Hibernate busca automticamente un arhivo llamado hibernate.cfg.xml en la raz del classpath, al arrancar.

1.2.4. Construir con Ant

11 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

Ahora vamos a construir (build) esta aplicacin instructiva usando Ant. Deber tener Ant ya instalado - obtngalo de la Pgina de descarga de Ant. Aqu no vamos a discutir cmo instalar Ant. Por favor refirase al Manual de Ant. Despus de haber instalado Ant, podemos crear el archivo de construccin de Ant (build file), que se llamar build.xml, y estar situado directamente en el directorio de desarrollo. Un archivo de construccin Ant bsico se ve as:
<project name="hibernate-tutorial" default="compile"> <property name="sourcedir" value="${basedir}/src"/> <property name="targetdir" value="${basedir}/bin"/> <property name="librarydir" value="${basedir}/lib"/> <path id="libraries"> <fileset dir="${librarydir}"> <include name="*.jar"/> </fileset> </path> <target name="clean"> <delete dir="${targetdir}"/> <mkdir dir="${targetdir}"/> </target> <target name="compile" depends="clean, copy-resources"> <javac srcdir="${sourcedir}" destdir="${targetdir}" classpathref="libraries"/> </target> <target name="copy-resources"> <copy todir="${targetdir}"> <fileset dir="${sourcedir}"> <exclude name="**/*.java"/> </fileset> </copy> </target> </project>

Esto le dice a Ant que agregue todos los archivos del el directorio lib que terminen en .jar al classpath que usemos para la compilacin. Tambin copiar todos los archivos fuente no-Java al directorio de destino (target), por ejemplo, los archivos de configuracin y mapeo.. Si ejecuta Ant ahora, debera obtener la siguiente salida:
C:\hibernateTutorial\>ant Buildfile: build.xml copy-resources: [copy] Copying 2 files to C:\hibernateTutorial\bin compile: [javac] Compiling 1 source file to C:\hibernateTutorial\bin BUILD SUCCESSFUL Total time: 1 second

1.2.5. Arranque y ayudantes


Es hora de cargar y grabar algunos objetos Event,pero primero debemos completar la instalacin (setup) con algo de cdigo "infraestructural". Tenemos que hacer arrancar Hibernate. Dicho arranque incluye construir un objeto SessionFactory global, y almacenarlo en algn lugar de fcil acceso para el cdigo de la aplicacin. Una SessionFactory puede abrir nuevos objetos Session. Cada objeto Session representa una "unidad de trabajo" de un solo Thread. El cdigo de SessionFactory es thread-safe, y es instanciado slo una vez. Vamos a crear una clase de ayuda llamada HibernateUtil, que se encargar del arranque y har que el acceso a SessionFactory sea ms conveniente. Veamos cmo implementarla:
package util; import org.hibernate.*;

12 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

import org.hibernate.cfg.*; public class HibernateUtil { private static final SessionFactory sessionFactory; static { try { // Cree la SessionFactory para hibernate.cfg.xml sessionFactory = new Configuration().configure().buildSessionFactory(); } catch (Throwable ex) { // Asegrese de loguear la excepcin, dado que puede ser "tragada" System.err.println("Initial SessionFactory creation failed." + ex); throw new ExceptionInInitializerError(ex); } } public static SessionFactory getSessionFactory() { return sessionFactory; } }

Esta clase no slo produce la SessionFactory global, en un inicializador esttico (invocado una sola vez por la JVM cuando la clase se carga), sino que oculta el hecho de que se emplea un singleton esttico. Podra haber estado buscando la SessionFactory en el JNDI de un servidor de aplicaciones, , por ejemplo,. Si usted le da un nombre a la SessionFactory en su archivo de configuracin, Hibernate en realidad intentar vincularla a JNDI tras haber sido creada. Para omitir este cdigo completamente, usted tambin podra usar "despliegue JMX" y dejar que el un contenedor habilitado para JMX instancie y construya un HibernateService en la JNDI. Estas opciones avanzadas se discuten en la documentacin de referencia de Hibernate. Coloque HibernateUtil.java en el directorio de cdigo fuente, en un paquete al lado de events:
. +lib <Hibernate y las bibliotecas de terceros> +src +events Event.java Event.hbm.xml +util HibernateUtil.java hibernate.cfg.xml +data build.xml

Esto debera poder compilarse sin problemas. Finalmente, necesitamos configurar un sistema de logueo (bitcora, logging) - Hibernate usa commons logging y le deja a usted la opcin entre log4j y el logging especfico de Java. La mayora de los programadores prefiere Log4j. Copie log4j.properties de la distribucin de Hibernate (est en el directorio etc/) a su directorio src, al lado de hibernate.cfg.xml. Dele un vistazo a la configuracin de ejemplo, y cambie los valores si desea una salida ms locuaz. Por defecto, slo los mensajes de arranque de Hibernate se muestran en la salida estndar. La parte infraestructural del instructivo ha finalizado. Ahora estamos listos para efectuar verdadero trabajo con Hibernate.

1.2.6. Cargar y almacenar objetos


Finalmente podemos usar Hibernate para cargar y grabar objetos . Escribimos una clase EventManager con un mtodo main().
package events; import org.hibernate.Session; import java.util.Date; import util.HibernateUtil; public class EventManager { public static void main(String[] args) {

13 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

EventManager mgr = new EventManager(); if (args[0].equals("store")) { mgr.createAndStoreEvent("My Event", new Date()); } HibernateUtil.getSessionFactory().close(); } private void createAndStoreEvent(String title, Date theDate) { Session session = HibernateUtil.getSessionFactory().getCurrentSession(); session.beginTransaction(); Event theEvent = new Event(); theEvent.setTitle(title); theEvent.setDate(theDate); session.save(theEvent); session.getTransaction().commit(); } }

Creamos un objeto Event, y se los pasamos a Hibernate. Ahora Hibernate se encarga del SQL, y ejecuta INSERTs en la base de datos. Echmosle un vistazo a la sesin, y al cdigo de manejo de transacciones antes de ejecutarlo. Usa sesin (Session) es una unidad de trabajo. Por ahora mantendremos todo simple y asumiremos una correspondencia uno-a-uno entre una sesin de Hibernate y una transaccin de BD. Para "escudar" nuestro codigo respecto del sistema subyacente de transacciones (en este caso, slo JDBC, pero podra haber sido JTA), usamos la API para transacciones que est disponible en la clase Session. Qu hace sessionFactory.getCurrentSession()? Primero, a este mtodo se lo puede llamar desde dondequiera, y cuantas veces se desee, una vez que obtenemos una SessionFactory. (fcilmente, gracias a la HibernateUtil). El cdigo getCurrentSession() siempre devuelve la unidad "actual" de trabajo. Recuerda que configuramos una opcin con valor "thread" en hibernate.cfg.xml? Debido a esto, la unidad actual de trabajo est ligada al thread de Java que se est ejecutando en ese momento en su aplicacin. De todos modos, sta no es toda la historia: tambin hay que considerar el alcance (scope), cundo una unidad de trabajo empieza y cundo termina. Una sesin comienza cuando se la necesita por primera vez, cuando se hace la primera llamada a getCurrentSession(). Entonces, es ligada al thread actual por Hibernate. Cuando la transaccin termina, Hibernate desliga la sesin del thread, y la cierra por usted. Si usted llama getCurrentSession() de nuevo, obtiene una nueva sesin y comienza una nueva unidad de trabajo. El modo de programacin "ligado a threads" (thread-bound), es la forma ms difundida de usar Hibernate, dado que permite una distribucin en capas muy flexible: el cdigo de delimitacin de transacciones puede separarse del cdigo de acceso a datos, como veremos ms adelante. En relacin al alcance de la unidad de trabajo: Una sesin debera usarse para ejecutar una sola operacin de base de datos, o varias? El ejemplo precedente usa una sesin para una operacin. Esto es simple casualidad, el ejemplo no es lo suficientemente complejo como para demostrar ningn otro enfoque. El alcance de una sesin de Hibernate es flexible, pero nunca se debe designar una aplicacin de maneera que utilice una sesin para cada operacin de base de datos. As que, incluso si usted lo ve en algunos pocos de los ejemplos siguientes, considere la prctica de "una sesin por operacin" como algo a evitar (un "anti-pattern"). Una aplicacin real (de web) se analiza ms adelante en este instructivo. chele un vistazo al captulo Captulo 11, Transacciones y Concurrencia acerca del manejo de transacciones y su delimitacin. Tambin hemos salteado cualquier manejo de errores en el ejemplo precedente. Para ejecutar esta primera rutina, tenemos que agregar una "target" invocable al archivo de construccin de Ant.
<target name="run" depends="compile"> <java fork="true" classname="events.EventManager" classpathref="libraries"> <classpath path="${targetdir}"/> <arg value="${action}"/> </java> </target>

El valor del argumento "action" se asigna en la lnea de comandos cuando esta target se invoca.

14 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

C:\hibernateTutorial\>ant run -Daction=store

Despus de la compilacin, usted debera ver que que Hibernate arracna, y, dependiendo de su configuracin, un montn de salida de logueo. Al final encontrar la siguiente lnea:
[java] Hibernate: insert into EVENTS (EVENT_DATE, title, EVENT_ID) values (?, ?, ?)

se es el cdigo INSERT ejecutado por Hibernate. Los signos de interrogacin representan parmetros JDBC ligados. Para ver los valores de dichos parmetros, o para reducir la locuacidad del archivo de log, revise su archivo log4j.properties. Ahora, querramos tanbin listar los eventos almacenados, as que agregamos una opcin el el mtodo principal:
if (args[0].equals("store")) { mgr.createAndStoreEvent("My Event", new Date()); } else if (args[0].equals("list")) { List events = mgr.listEvents(); for (int i = 0; i < events.size(); i++) { Event theEvent = (Event) events.get(i); System.out.println("Event: " + theEvent.getTitle() + " Time: " + theEvent.getDate()); } }

Tambin agregamos un nuevo mtodo listEvents() method:


private List listEvents() { Session session = HibernateUtil.getSessionFactory().getCurrentSession(); session.beginTransaction(); List result = session.createQuery("from Event").list(); session.getTransaction().commit(); return result; }

Lo que hicimos aqu, es usar el lenguaje de consultas de Hibernate (HQL, por sus siglas en ingls) para cargar todos los objetos Event que existen en la base de datos. Hibernate generar el cdigo SQL que haga falta, lo enviar la base de datos, y poblar los objetos Event con los datos que sean devueltos. Se pueden crear consultas SQL mucho ms complejas con HQL, por supuesto. Ahora, para ejecutar y chequear todo esto, siga estos pasos: Ejecute ant run -Daction=store para almacenar algo en la base de datos y, por supuesto, para previamente generar el esquema de base de datos mediante hbm2ddl. Ahora inhabilite hbm2ddl (convirtiendo la propiedad en un comentario) en el archivo hibernate.cfg.xml. Por lo general, slo se la deja habilitada cuando se efecta un "unit testing continuo", pero en este caso, dejarla habilitada borrara todo lo que usted haya almacenado hasta ese momento. (el valor de hbm2ddl="create" se traduce como "haga un DROP de todas las tablas del esquema, y recree todas las tablas cuando la SessionFactory sea construida") Si usted ahora invocara Ant con -Daction=list, debera ver los eventos que haya almacenado hasta ese moento. Por supuesto, puede tambin invocar la accin store un par de veces ms. Nota: A esta altura, la mayora de los usuarios de Hibernate experimenta problemas, y aparecen seguido mensajes del tipo Table not found . De todos modos, si usted sigue los pasos que acabamos de describir cuidadosamente, no tendr este problema, ya que hbm2ddl crea el esquema de base de datos la primera vez, y las veces subsiguientes en que la aplicacin recomienza utilizan dicho esquema. Si usted en algn momento cambia algo del mapeo o del esquema, debe rehabilitar hbm2dll nuevamente para recrear la BD.

1.3. Parte 2 - Mapear asociaciones


Hemos mapeado una clase persistente a una tabla. Ahora, partiendo de esta base, agreguemos algunas asociaciones de

15 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

clase. Primero, agregaremos algunas personas a nuestra aplicacin, y almacenaremos una lista de eventos en los cuales participan.

1.3.1. Mapear la clase Person


El primer bosquejo de la clase Person es simple:
package events; public class Person { private private private private Long id; int age; String firstname; String lastname;

public Person() {} // mtodos "getter" y "setter" de acceso, y setter privado para 'id' }

Cree un nuevo archivo de mapeo llamado Person.hbm.xml (y no olvide la referencia a la DTD en la parte superior):
<hibernate-mapping> <class name="events.Person" table="PERSON"> <id name="id" column="PERSON_ID"> <generator class="native"/> </id> <property name="age"/> <property name="firstname"/> <property name="lastname"/> </class> </hibernate-mapping>

Por ltimo, agreguemos el nuevo archivo de mapeo a la configuracin de Hibernate.


<mapping resource="events/Event.hbm.xml"/> <mapping resource="events/Person.hbm.xml"/>

Y ahora crearemos una asociacin entre estas dos entidades, Obviamente, las personas pueden participar en eventos, y los eventos tienen participantes. Las cuestiones de diseo con las que tenemos que lidiar son: multiplicidad, direccionalidad, y comportamiento de las colecciones.

1.3.2. Una asociacin unidireccional basada en un Set


Agregaremos una coleccin de eventos a la clase Person. De este modo podremos navegar cmodamente los eventos para una determinada persona sin tener que ejecutar una consulta explcita, simplemente llamando aPerson.getEvents(). Usamos una coleccin de Java, un Set, porque esta coleccin no contendr elementos duplicados, y el orden no es relevante para nosotros. Necesitamos una asociacin unidireccional y de varios valores, que pueda ser implementada con un Set. Escribamos el cdigo para esto en las clases de Java, y luego mapemoslas.
public class Person { private Set events = new HashSet(); public Set getEvents() { return events; } public void setEvents(Set events) { this.events = events; }

16 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

Antes de mapear esta asociacin, piense en el otro lado (los eventos). Claramente, podemos simplemente mantener esta asociacin unidireccional. O si no, podramos crear otra coleccin en la clase Event, si deseamos navegar en forma bidireccional, es decir, anEvent.getParticipants(). Esto no es estrictamente necesario, desde un punto de vista funcional, siempre se puede ejecutar una consulta explcita para obtener los participamntes de un determinado evento. Esta es una opcin de diseo que le dejamos a usted; pero lo que sacamos en limpio de esta discusin, es la multiplicidad de la asociacin: hay "muchos valores" desde ambos lados. A esto se lo llama una asociacin "de-muchos-a-muchos" (many-to-many). Por esto, usamos el mapeo many-to-many de Hibernate.
<class name="events.Person" table="PERSON"> <id name="id" column="PERSON_ID"> <generator class="native"/> </id> <property name="age"/> <property name="firstname"/> <property name="lastname"/> <set name="events" table="PERSON_EVENT"> <key column="PERSON_ID"/> <many-to-many column="EVENT_ID" class="events.Event"/> </set> </class>

Hibernate soporta todo tipo de mapeos de coleccn, siendo el "set" el ms comn. Para una asociacin "many-to-many", o relacin entre entidades, se necesita una tabla de asociacin. Cada registro de esta tabla simboliza un vnculo entre una persona y un evento. El nombre de esta tabla se configura con el atributo table del elemento set. La columna indentificadora por el lado de las personas, se define con el elemento <key>, el nombre de la columna por el lado de los eventos, con el atributo column del <many-to-many>. Usted tambin debe decirle a Hibernate la clase de objetos de su coleccin. El esquema de base de datos para este esquema es, entonces:
_____________ __________________ | | | | _____________ | EVENTS | | PERSON_EVENT | | | |_____________| |__________________| | PERSON | | | | | |_____________| | *EVENT_ID | <--> | *EVENT_ID | | | | EVENT_DATE | | *PERSON_ID | <--> | *PERSON_ID | | TITLE | |__________________| | AGE | |_____________| | FIRSTNAME | | LASTNAME | |_____________|

1.3.3. Trabajar con asociaciones


Juntemos a alguna gente con sus eventos, en un nuevo mtodo de EventManager:
private void addPersonToEvent(Long personId, Long eventId) { Session session = HibernateUtil.getSessionFactory().getCurrentSession(); session.beginTransaction(); Person aPerson = (Person) session.load(Person.class, personId); Event anEvent = (Event) session.load(Event.class, eventId); aPerson.getEvents().add(anEvent); session.getTransaction().commit(); }

Despus de cargar una Person y un Event, simplemente modifique la coleccin usando los mtodos normales de las colecciones. Como puede usted ver, no hay llamados explcitos a update() o a save(), Hibernate detecta automticamente que la coleccin ha sido modificada y necesita ser actualizada. Esto se llama "dirty checking automtico", y usted puede experimentar con ello cmabiando la propiedad "date" en cualquiera de sus objetos. Siempre y cuando se mantengan en un estado persistente (es decir, ligados a una sesin de Hibernate, por haber sido cargados o

17 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

grabados en una unidad de trabajo), Hibernate monitorear cualquier cambio y ejecutar SQL entre bambalinas. El proceso de sincronizar el estado de lo que est en memoria con la base de datos, generalmente al final de la unidad de trabajo, se denomina "nivelar, desagotar" la sesin (en ingls, flush). En nuestro cdigo, la unidad de trabajo termina con un "commit" (o "rollback") de la transaccin de base de datos, tal como se define por la opcin de configuracin thread para la clase CurrentSessionContext. Se podra, por supuesto, cargar personas y eventos en distintas unidades de trabajo. O modificar un objeto fuera de una sesin, cuando no est en estado persistente (si lo estuvo anteriormente, este estado se llama "desprendido", en ingls detached). Incluso una coleccin se puede modificar estando en este estado desprendido.
private void addPersonToEvent(Long personId, Long eventId) { Session session = HibernateUtil.getSessionFactory().getCurrentSession(); session.beginTransaction(); Person aPerson = (Person) session .createQuery("select p from Person p left join fetch p.events where p.id = :pid") .setParameter("pid", personId) .uniqueResult(); // Eager fetch the collection so we can use it detached Event anEvent = (Event) session.load(Event.class, eventId); session.getTransaction().commit(); // fin de la primera unidad de trabajo aPerson.getEvents().add(anEvent); // aPerson (and its collection) is detached // comienzo de la segunda unidad de trabajo Session session2 = HibernateUtil.getSessionFactory().getCurrentSession(); session2.beginTransaction(); session2.update(aPerson); // reasociacin de aPerson, que estaba desprendida session2.getTransaction().commit(); }

El llamado a update convierte de nuevo en persistente un objeto que estaba desprendido. Se podra decir que lo liga a una nueva unidad de trabajo, de manera que cualquier modificacin que se le hubiera hecho mientras estaba desprendido pueda ser grabada en la base de datos. Esto incluye cualquier modificacin que se le hubiera hecho a la coleccin de ese objeto entidad. Bueno, esto no es muy til en la situacin actual, pero es un concepto importante, que usted puede aplicar al diseo de su propia aplicacin. Por ahora, simplemente complete este ejercicio agregando una nueva accin al mtodo main() de EventManager, e invquelo desde la lnea de comandos. Si necesita los identificadores de una persona y de un evento, el mtodo save() los devuelve (tal vez usted deba modificar alguno de los mtodos previos, para que devuelvan dicho identificador).
else if (args[0].equals("addpersontoevent")) { Long eventId = mgr.createAndStoreEvent("My Event", new Date()); Long personId = mgr.createAndStorePerson("Foo", "Bar"); mgr.addPersonToEvent(personId, eventId); System.out.println("Added person " + personId + " to event " + eventId); }

ste fue un ejemplo de una asociacin entre dos clases igualmente importantes, dos "entidades". Como se mencion anteriormente, hay otras clases y tipos "menos importantes" en un modelo tpico. Algunos, usted ya los ha visto, como los int o String. A esas clases las llamamos value types, y sus instancias dependen de una entidad en particular. Las instancias de estos tipos no tienen su propia identidad, ni se pueden compartir entre entidades (dos personas no pueden, por ejemplo, hacer referencia al mismo objeto firstname o primer nombre, incluso si son tocayos). Por supuesto, estos value types pueden ser encontrados no solamente en la JDK. De hecho, en una aplicacin Hibernate todas las clases JDK son consideradas "value types", pero usted puede escribir sus propias clases dependientes, para representar una direccin o una cantidad de dinero, por ejemplo. Tambin se puede disear una coleccin de "value types". Esto es conceptualmente bien distinto de una coleccin de referencias a otras entidades, pero en el cdigo Java ambas se ven casi igual.

1.3.4. Coleccin de valores

18 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

Agreguemos una coleccin de objetos "value type" a la entidad Person. Queremos almacenar direcciones de correo electrnico (email), de manera que el tipo que usaremos es String, y la coleccin, de nuevo un Set.
private Set emailAddresses = new HashSet(); public Set getEmailAddresses() { return emailAddresses; } public void setEmailAddresses(Set emailAddresses) { this.emailAddresses = emailAddresses; }

El mapeo de este Set:


<set name="emailAddresses" table="PERSON_EMAIL_ADDR"> <key column="PERSON_ID"/> <element type="string" column="EMAIL_ADDR"/> </set>

La diferencia, comparada con el mapeo anterior, es la parte element, la cual le dice a Hibernate que la coleccin no contiene referencias a otra entidad, sino a una coleccin de elementos de tipo string (al estar con minscula nos damos cuenta de que es un tipo/conversor de Hibernate). Une vez ms, el atributo table del set determina el nombre de la tabla para la coleccin. El elemento key define el nombre de columna para la clave fornea, El atributo column de "element" define en dnde estas cadenas van a ser almacenadas. Echmosle un vistazo al nuevo esquema de DB
_____________ __________________ | | | | _____________ | EVENTS | | PERSON_EVENT | | | ___________________ |_____________| |__________________| | PERSON | | | | | | | |_____________| | PERSON_EMAIL_ADDR | | *EVENT_ID | <--> | *EVENT_ID | | | |___________________| | EVENT_DATE | | *PERSON_ID | <--> | *PERSON_ID | <--> | *PERSON_ID | | TITLE | |__________________| | AGE | | *EMAIL_ADDR | |_____________| | FIRSTNAME | |___________________| | LASTNAME | |_____________|

Se puede ver que la clave primaria de la tabla de la coleccin es, en realidad, una clave compuesta, que usa ambas columnas. Esto tambin implica que no puede haber direcciones de email duplicadas para una misma persona, lo cual es precisamente la semntica de un conjunto o "Set" en Java. Ahora podemos intentar agregar elementos a esta coleccin, igual que como hicimos antes al vincular personas y eventos. El cdigo Java es el mismo:
private void addEmailToPerson(Long personId, String emailAddress) { Session session = HibernateUtil.getSessionFactory().getCurrentSession(); session.beginTransaction(); Person aPerson = (Person) session.load(Person.class, personId); // el getEmailAddresses() podra disparar una carga "haragana" de la coleccin aPerson.getEmailAddresses().add(emailAddress); session.getTransaction().commit(); }

Esta vez, no utilizamos una consulta con fetch para inicializar la coleccin. De ah que la invocacn de su mtodo "getter" disparar un SELECT adicional para inicializarla, de manera que podamos agregarle un elemento. Monitoree el log de SQL e intente optimizar esto con un "eager fetch" (captura ansiosa).

1.3.5. Asociaciones bidireccionales


Acto seguido, vamos a mapear una asociacin bidireccional, es decir, vamos a hacer que la asociacin funcione desde

19 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

ambos lados en Java. Desde luego, el esquema de base de datos no cambia, todava tenemos una multiplicidad de-muchosa-muchos (many-to-many). Una base de datos relacional es ms flexible que un lenguaje de programacin, no necesita cosas como una "direccin de navegacin", los datos pueden ser adquiridos de cualquier manera posible. Primero, agregue una coleccin de participantes al cdigo de la clase Event.
private Set participants = new HashSet(); public Set getParticipants() { return participants; } public void setParticipants(Set participants) { this.participants = participants; }

Ahora, mapee tambin este lado de la asociacin, en Event.hbm.xml.


<set name="participants" table="PERSON_EVENT" inverse="true"> <key column="EVENT_ID"/> <many-to-many column="PERSON_ID" class="events.Person"/> </set>

Como puede ver, stos son mapeos set normales en ambos documentos de mapeo. Fjese en que los nombres de columna en ambos documentos han sido alternados. La adicin ms importante es el atributo inverse="true" en el elemento set del mapeo de la coleccin de Event. Lo que esto significa, es que Hibernate debera rferirse al otro lado (el lado "Person"), cuando necesite obtener informacin sobre el vnculo entre los dos. Esto ser ms fcil de entender una vez que veamos cmo se crea el vnculo bidireccional entre las dos entidades.

1.3.6. Trabajar con vnculos bidireccionales


Primero que nada, tenga en cuenta que Hibernate no afecta la semntica normal de Java, Cmo habiamos creado un vnculo entre personas y eventos en el ejemplo unidireccional? Agregando una instancia de Event a la coleccin de referencias contenida en una instancia de Person. As que, obviamente, si queremos que este vnculo funcione tambin en sentido inverso, tenemos que hacer lo mismo del otro lado: agregar una referencia a Person a la coleccin en Event. Esto de "establecer el vnculo de los dos lados" es absolutamente necesario, y usted jams debe olvidarse de hacerlo. Muchos programadores trabajan "defensivamente", y crean mtodos facilitadores que asignan correctamente los vnculos a ambos lados. Por ejemplo, en la clase Person:
protected Set getEvents() { return events; } protected void setEvents(Set events) { this.events = events; } public void addToEvent(Event event) { this.getEvents().add(event); event.getParticipants().add(this); } public void removeFromEvent(Event event) { this.getEvents().remove(event); event.getParticipants().remove(this); }

Fjese en que los mtodos "get" y "et" de la coleccin ahora son "protected" - esto les permite a las clases en el mismo paquete, y a las subclases, acceder a los mtodos, pero les impide a todos los dems inmiscuirse con estas colecciones directamente (bueno... casi). Usted debera, probablemente, hacer lo mismo con las colecciones del otro lado. Y qu hay del atributo de mapeo inverse? Para usted (y para Java), un vnculo bidrecciolal es simplemente cuestin de asignar correctamente las referencias en ambos lados .Hibernate, sin embargo, no tiene informacin suficiente como para organizar adecuadamente sus llamados a comandos SQL INSERT y UPDATE. Marcar uno de los lados de la asociacin como inverse, bsicamente le dice a Hibernate que lo ignore, que lo considere como un espejo de lo que ocurre en el otro

20 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

lado. Eso es todo lo que se necesita para que Hibernate resuelva todos los problemas que derivan de transformar un modelo de navegacin bidireccional en un esquema de base de datos. Las reglas que usted denbe recordar son son simples: Toda asociacin bidireccional necesita que uno de sus lados sea "inverse". En una asociacin de-uno-a-muchos (one-to-many) tiene que ser el lado "many". En una asociacin de-muchos-a-muchos (many to many), elija cualquier lado, da lo mismo.

1.4. Parte 3 - La aplicacin de web "EventManager"


Convirtamos la siguiente discusin en una pequea aplicacin de web. Una aplicacin de web Hibernate utiliza sesiones y transacciones, lo mismo que la aplicacim autosuficiente que vimos anteriormente. Sin embargo, es conveniente usar algunos patrones de programacin ("patterns"). Escribamos un servlet EventManagerServlet que pueda listar los eventos alamacenados en la base de datos, y provea un formulario HTML para ingresar nuevos eventos.

1.4.1. Escribir el servlet bsico


Cree una nueva clase en su directorio de cdigo fuente, en el paquete events:
package events; // Imports public class EventManagerServlet extends HttpServlet { // Servlet code }

Este servlet maneja requests HTTP del tipo GET solamente, as que el mtodo que implementamos es doGet():
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { SimpleDateFormat dateFormatter = new SimpleDateFormat("dd.MM.yyyy"); try { // comienzo nuestra unidad de trabajo HibernateUtil.getSessionFactory().getCurrentSession().beginTransaction(); // procesamiento de la solicitud (request) y presentacin de la pgina... // fin de la unidad de trabajo HibernateUtil.getSessionFactory().getCurrentSession().getTransaction().commit(); } catch (Exception ex) { HibernateUtil.getSessionFactory().getCurrentSession().getTransaction().rollback(); throw new ServletException(ex); } }

El "pattern" o patrn de programacn que estamos aplicando aqu se llama session-per-request, (una sesin por cada "solicitud" o request HTTP). Cuando una nueva request apela al servlet, se abre una nueva sesin de Hibernate mediante el primer llamado a getCurrentSession() de la SessionFactory. Entonces, ss inicia una transaccin de base de datos (todo el cdigo de acceso a datos ocurre dentro de la transaccin, no importa si para lectura o escritura; en las aplicaciones no usamos auto-commit). Nunca cree una nueva sesin de Hibernate para cada operacin de base de datos. Use una sesin de Hibernate a lo largo de toda la request, es decir, que tenga un "alcance" de toda la sesin. Use getCurrentSession(), de manera que quede automticamente ligada al Thread actual. A continuacin, las acciones posibles de la request son procesadas, y es generada la respuesta HTML. Enseguida nos dedicaremos a esa parte. Finalmente, la "unidad de trabajo" finaliza, cuando el procesamiento y presentacin hayan sido completados. Si ocurri algn problema durante este procesamiento o presentacin, se lanzar una excepcin y la se ejecutar un "rollback" de la

21 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

transaccin. Esto cubre el "pattern" session-per-request. En lugar de escribir cdigo para demarcar la transaccin en cada request, usted debera crea un Servlet Filter. Refirase al sitio de web de Hibernate y a la Wiki para ms informacin acerca de este "pattern", llamado Open Session in View u OSIV, algo as como "apertura de una sesin por cada vista". Este patrn se necesitar en cuanto usted considere presentar sus "vistas" usando JSP en lugar de servlets.

1.4.2. Procesamiento y presentacin


Implementemos el procesamiento de la solicitud y la presentacin de la pgina.
// escribe el header encabezado HTML PrintWriter out = response.getWriter(); out.println("<html><head><title>Event Manager</title></head><body>"); // maneja las acciones if ( "store".equals(request.getParameter("action")) ) { String eventTitle = request.getParameter("eventTitle"); String eventDate = request.getParameter("eventDate"); if ( "".equals(eventTitle) || "".equals(eventDate) ) { out.println("<b><i>Please enter event title and date.</i></b>"); } else { createAndStoreEvent(eventTitle, dateFormatter.parse(eventDate)); out.println("<b><i>Added event.</i></b>"); } } // imprime la pgina printEventForm(out); listEvents(out, dateFormatter); // escribe el pie HTML out.println("</body></html>"); out.flush(); out.close();

Concedido, este tipo de escritura de cdigo, mezclando Java y HTML, sera inadmisible en aplicaciones ms complejas, tenga en cuenta que slo estamos ilustrando conceptos bsicos de Hibernate en este instructivo. El cdigo imprime un encabezado y un pie de pgina en HTML. Dentro de la pgina propiamente dicha, se imprime un formulario (form) para el ingreso de eventos. El primer mtodo es trivial, y slo produce HTML:
private void printEventForm(PrintWriter out) { out.println("<h2>Add new event:</h2>"); out.println("<form>"); out.println("Title: <input name='eventTitle' length='50'/><br/>"); out.println("Date (e.g. 24.12.2009): <input name='eventDate' length='10'/><br/>"); out.println("<input type='submit' name='action' value='store'/>"); out.println("</form>"); }

El mtodo listEvents() usa la sesin de Hibernate ligada al Thread actual para ejecutar una consulta:
private void listEvents(PrintWriter out, SimpleDateFormat dateFormatter) { List result = HibernateUtil.getSessionFactory().getCurrentSession().createCriteria(Event.class) if (result.size() > 0) { out.println("<h2>Events in database:</h2>"); out.println("<table border='1'>"); out.println("<tr>"); out.println("<th>Event title</th>"); out.println("<th>Event date</th>"); out.println("</tr>"); for (Iterator it = result.iterator(); it.hasNext();) { Event event = (Event) it.next(); out.println("<tr>"); out.println("<td>" + event.getTitle() + "</td>"); out.println("<td>" + dateFormatter.format(event.getDate()) + "</td>"); out.println("</tr>"); } out.println("</table>"); }

22 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

Finalmente, la accin store es despachada al mtodo createAndStoreEvent(), el cual usa la sesin del Thread actual.
protected void createAndStoreEvent(String title, Date theDate) { Event theEvent = new Event(); theEvent.setTitle(title); theEvent.setDate(theDate); HibernateUtil.getSessionFactory().getCurrentSession().save(theEvent); }

Eso es todo. El servlet est completo. Una request al servlet ser procesada en una nica sesin y transaccin. Tal como ocurri en el ejemplo anterior, Hibernate puede ligar estos objetos al Thread actual de ejecucin. Esto le da a usted la libertad de acceder a la SessionFactory de cualquier manera que guste. Normalmente, usted usara un diseo ms sofisticado, y movera el cdigo de acceso a datos (DAO, por sus siglas en ingls) a otra "capa". Refirase a la Wiki de Hibernate para ms ejemplos.

1.4.3. Despliegue (deploy) y test


Para desplegar (deploy) esta aplicacin, tiene que crear un archivo ".war". Agregue la siguiente target de Ant a su archivo build.xml:.
<target name="war" depends="compile"> <war destfile="hibernate-tutorial.war" webxml="web.xml"> <lib dir="${librarydir}"> <exclude name="jsdk*.jar"/> </lib> <classes dir="${targetdir}"/> </war> </target>

Esta target crea un archivo llamado hibernate-tutorial.war en su directorio de proyecto. Empaqueta todas las bibliotecas y el descriptor web.xml, el cual se espera que est en el directorio base de su proyecto.
<?xml version="1.0" encoding="UTF-8"?> <web-app version="2.4" xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4 <servlet> <servlet-name>Event Manager</servlet-name> <servlet-class>events.EventManagerServlet</servlet-class> </servlet> <servlet-mapping> <servlet-name>Event Manager</servlet-name> <url-pattern>/eventmanager</url-pattern> </servlet-mapping> </web-app>

Antes de compilar y desplegar, como sta es una aplicacin de web, note que se necesita una biblioteca adicional : jsdk.jar. Es el kit de herramientas o "developer kit" para los servlets de Java. Si an no tiene esta biblioteca, descrguela del sitio de web de Sun y colquela en su directorio de bibliotecas (lib). De todos modos, se la usa para compilar solamente, no se incluye en los paquetes WAR. Para construir (build) y desplegar (deploy), invoque el comando ant war situado en el directorio de su proyecto, y luego copie el archivo hibernate-tutorial.war en el directorio webapp de Tomcat. Si no tiene Tomcat instalado, descrguelo y siga las instrucciones. No es necesario que cambie nada en la configuracin de Tomcat para que este ejemplo ande. Una vez desplegada y con Tomcat andando, accceda a la aplicacin en http://localhost:8080/hibernate-tutorial /eventmanager. Asegrese de monitorear el log de Tomcar para comprobar si Hibernate se inicializa cuando ocurre la primera solicitud (request) a su servlet (tiene que ejecutarse el inicializado esttico en HibernateUtil), y tambin asegrese de obtener una mensaje detallado si ocurre algn error.

23 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

1.5. Sumario
Este instructivo cubri lo bsico para escribir una simple aplicacin Hibernate autosuficiente, y una pequea aplicacin de Web. Si ya va tomando confianza con Hibernate, contine hojeando la tabla de contenidos en la documentacin de referencia, buscando temas que le interesen. Los ms solicitados son el procesamiento de transacciones (Captulo 11, Transacciones y Concurrencia), la performance de las capturas de datos o "fetch performance" (Captulo 19, Mejorar la performance), el uso de las API (interfaces de programacin) (Captulo 10, Trabajar con objetos) y las caractersticas de las consultas (Seccin 10.4, Consultar). No olvide chequear el sitio de web de Hibernate en busca de ms instructivos especializados.

Captulo 2. Arquitectura 2.1. Generalidades


Una vista a vuelo de pjaro de la arquitectura de Hibernate

Este diagrama muestra a Hibernate usando datos de configuracin y base de datos para proveerle servicios de persistencia (y objetos persistentes) a la aplicacin. Nos gustara mostrar una vista ms detallada de la arquitectura en tiempo de ejecucin. Lamentablemente, Hibernate es tan flexible, que soporta muchas estrategias. Vamos a mostrar los dos extremos: la arquitectura "liviana" fuerza a la aplicacin a proveer sus propias conexiones JDBC y a gerenciar sus propias tranascciones. Esta arquitectura usa un subconjunto mnimo de las APIs de Hibernate.

24 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

La arquitectura "con todas las luces" abstrae la aplicacin, alejndola de las capas subyacentes de JDBC/JTA, y deja que Hibernate se encargue de los detalles.

He aqu algunas definiciones de los objetos en los diagramas: SessionFactory (org.hibernate.SessionFactory) Un cach thread-safe e inmutable de mapeos, compilados para una base de datos en particular. Una fbrica (factory) de sesiones, y cliente de ConnectionProvider. Puede contener un cach optativo (llamado "de 2do nivel") que es reusable entre transacciones, a nivel de proceso o de cluster. Session (org.hibernate.Session) Un objeto de thread simple y de corta visa, que representa una conversacin entre la aplicacin y el repositorio persistente. Envuelve a una fbrica de conexiones JDBC por transaccin. Contiene un cach obligatorio (llamado "de primer nivel") de objetos persistentes, que se usa al navegar el rbol de objetos, o cuando se buscan los objetos por identificador. Objetos y colecciones persistentes Objetos de un solo thread y corta vida, que contienen "estado" persistente y cumplen una funcin de negocio. Pueden ser JavaBeans comunes, o puros y simples objetos de Java (POJOs por sus siglas en ingls), la nica caracterstica notable que tienen, es que estn asociados con una sesin. En cuanto la sesin se cierra, sern desprendidos, y quedarn listos para ser usados en cualquier capa de la aplicacin (por ejemplo, directamente como objetos de transmisin de datos o "DTOs", desde y hacia la capa de presentacin).

25 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

Objetos y colecciones transitorios y desprendidos Instancias de clases persistenteses que, por el momento, no estn asociadas con una sesin. Pudieron haber sido instanciadas por la aplicacn, y an no haber sido asociadas con una sesin, o bien haber sido instanciadas por una sesin que en ese momento est cerrada. Transaccin (org.hibernate.Transaction) (Optativo) un objeto de un solo thread y corta vida, usado por la aplicacon para especificar unidades atmicas de trabajo. Abstrae a la aplicacin de la transaccin JDBC, JTA o CORBA subyacente. Una sesn puede extenderse a lo largo de varias transacciones en algunos casos. Pero, sea como sea, el cdigo para demarcar transacciones (ya sea utilizando APIs subyancentes o la interfaz Transaction) nunca es optativo! ConnectionProvider (org.hibernate.connection.ConnectionProvider) (Optativo) Una fbrica y repositorio (pool) de conexiones JDBC. Abstrae la aplicacin de la fuente de datos (Datasource) o del gerente de driver (DriverManager) subyacentes. No est expuesto directamente a la aplicacin, pero puede ser implementado o extendido por el programador. TransactionFactory (org.hibernate.TransactionFactory) (Optativo) Una fbrica de instancias de Transaction. No est expuesta directamente a la aplicacin, pero puede ser implementada o extendida por el programador. Interfaces de extensin Hibernate ofrece varias interfaces de extensin optativoes, se pueden implementar para personalizar el comportamiento de la capa de persistencia. Vea la documentacin de la API para ms detalles. En la arquitectura "liviana", la aplicacin se saltea las APIs de Transaction/TransactionFactory y/o ConnectionProvider APIs para dialogar con JTA o JDBC directamente.

2.2. Estados de una instancia


Una instancia de una clase persistente puede estar en uno de tres estados diferentes, los cuales se definen con respecto a un contexto de persistencia: la sesin. transitorio (transient) La instancia no est asociada con ningn "contexto de persistencia" (sesin), ni nunca lo ha estado. Carece de "identidad persistente", es decir, de clave primaria. persistente (persistent) La instancia est al momento asociada con un contexto de persistencia. Tiene identidad persistente (valor de clave primaria) y, tal vez, un valor correspondiente en la base de datos. Para un contexto de persistencia determinado, Hibernate garantiza que la identidad persistente equivale a la "identidad Java" (ubicacin en memoria del objeto). desprendida (detached) La instancia estuvo alguna vez asociada con un contexto de persistencia, pero dicho contexto est cerrado, o la instancia ha sido serializada a otro proceso. Tiene una identidad persistente y, tal vez, el correspondiente registro en la base de datos. Hibernate no ofrece ninguna garanta acerca de la relacin entre identida persistente e identidad Java.

2.3. Integracin con JMX


JMX es el estndar de J2EE para la administracin de componentes Java. Hibernate puede ser administrado via un servicio JMX estndar. Nosotros proveemos una implementacin de MBean en la distribucin: org.hibernate.jmx.HibernateService. Para un ejemplo sobre cmo desplegar Hibernate como un servicio JMX en el servidor de aplicaciones JBoss, por favor vea la gua del usuario de JBoss. En el servidor de applicaciones JBoss, tambin se obtienen los siguientes beneficios si se

26 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

despliega (deploy) usando JMX: Manejo de sesiones: El ciclo de vida de una sesin de Hibernate puede ser automticamente ligado al alcance (scope) de una transaccin JTA. Esto significa que usted ya no necesita abrir y cerrar manualmente las sesiones, de esto se encarga el interceptor de JBoss. Tampoco debe preocuparse ya por demarcar la transaccin en su cdigo (a menos que quiera escribir usted mismo una capa de persistencia porttil, use la API Transaction de Hibernate para eso). Puede llamar a HibernateContext para acceder a una sesin. Despliegue del Archivo de Hibernate (HAR por sus siglas en ingls): Normalmente se despliega el servicio JMX de Hibernate usando el "descriptor de despliegue" (deployment descriptor), en un archivo EAR o SAR, el cual soporta las opciones de configuracin de una SessionFactory de Hibernate. De todos modos, para esto an se debe nombrar a todos los archivos de mapeo en el descriptor de despliegue. En cambio, si decide usar el despliegue HAR, JBoss detecta automticamente todos los archivos de mapeo en su archivo HAR. Consulte la gua del usuario del servidor de aplicaciones JBoss para mayor informacin acerca de estas opciones. Otra caracterstica disponible en forma de servicio JMX son las estadsticas de Hibernate en tiempo de ejecucin. Vea la Seccin 3.4.6, Estadsticas de Hibernate

2.4. Soporte de JCA


Hibernate tambin puede ser configurado como un conector JCA. Por favor, vea el sitio de web para ms detalles, pero note que el soporte Hibernate de JCA se considera todava experimental.

2.5. Sesiones contextuales


La mayora de las aplicaciones que usan Hibernate necesitan alguna forma de sesin "contextual", donde una sesin determinada est en efecto a lo largo del "scope" o alacance de un contexto determinado. De todos modos, entre las distintas aplicaciones, la definicin de lo que constituye un "contexto" suele diferir, as como la definicin de qu constituye el contexto "actual". Las aplicaciones que usaban Hibernate antes de la versin a 3.0, tendan a utilizar o bien versiones "caseras" de sesin contextual (basadas en ThreadLocal) o bien utilizaban frameworks de terceras partes (como Spring o Pico), los cuales provean sesiones contextuales basadas en proxies e intercepcin. Empezando con la versin 3.0.1, Hibernate incorpor el mtodo SessionFactory.getCurrentSession(). Inicialmente, este mtodo asuma el uso de transacciones JTA, donde la transaccin JTA defina tando el alcance como el contexto de la sesin actual. El equipo de Hibernate mantiene que, dada la madurez de las numerosas implementaciones autosuficientes de JTA que existen hoy da, la mayora (si no todas) las aplicaciones deberan estar usando JTA para su manejo de transacciones (estn o no desplegadas en un contenedor J2EE). Basndose en eso, las sesiones contextuales JTA son todo lo que usted debera necesitar usar. Sin embargo, a partir de la versin 3.1, el proceso que ocurre por detrs de SessionFactory.getCurrentSession() es configurable. Con este fin, una nueva interfaz de extensin (org.hibernate.context.CurrentSessionContext) y un nuevo parmetro de configuracin (hibernate.current_session_context_class) han sido agregados, para permitir "enchufar" implementaciones nuevas para definir el alcance y contexto de las sesiones. Vea los Javadocs acerca de la interfaz org.hibernate.context.CurrentSessionContext, para una descripcin detallada del contrato que sta implica. Define un solo mtodo, currentSession(), por el cual la implementacin es responsable de rastrear la sesin contextual actual. Hibernate ya viene con 3 implementaciones incuidas de esta interfaz.
org.hibernate.context.JTASessionContext - las sesiones actuales son localizadas y su alcance definido por una transaccin JTA. El procesamiento aqu es exactamente el mismo que en el antiguo enfoque slo-JTA. Vea los Javadocs para ms detalles. org.hibernate.context.ThreadLocalSessionContext

- las sesiones actuales son localizadas por thread de

ejecucin. De nuevo, vea los Javadocs para ms detalles.


org.hibernate.context.ManagedSessionContext

- las sesiones actuales son localizadas por thread de ejecucin. Sin embargo, usted es responsable por ligar y desligar las instancias de sesin, mediante mtodos estticos en esta clase. Nunca abre, cierra o le aplica flush a una sesin.

Las dos primeras implementaciones proveen un modelo de programacin del tipo "una sesin - una transaccin de base de

27 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

datos", tambin llamado session-per-request. El comienzo y fin de una sesin de Hibernate est definido por la duracin de la transaccin de base de datos. Si usted usa demarcacin programtica de transacciones, en simple JSE sin JTA, se le aconseja que use la API de Transaction de Hibernate, para ocultar el sistema de transacciones subyacente. Si el cdigo se est ejecutando en un contenedor EJB que soporte CMT, los lmites de la transaccin son definidos declarativamente, y usted no necesita ninguna transaccin ni demarcacin de operaciones en el cdigo propiamente dicho. Refirase al Captulo 11, Transacciones y Concurrencia para ms informacin y ejemplos de cdigo. El parmetro de configuracin hibernate.current_session_context_class define cul implementacin de org.hibernate.context.CurrentSessionContext debe ser usada. Note que, por compatibilidad con versiones anteriores, si este parmetro de configuracin no se asigna, sino que se configura org.hibernate.transaction.TransactionManagerLookup en su lugar, Hibernate usar el org.hibernate.context.JTASessionContext. Tpicamente, el valor de este parmetro simplemente nombra la clase de implementacin a usar; para las tres implementaciones de fbrica existen los respectivos nombres cortos: "jta", "thread" y "managed".

Captulo 3. Configuracin
Como Hibernate est diseado para operar en varios entornos diferentes, hay un gran nmero de parmetros de configuracin. Afortunadamente, la mayora tiene valores por defecto razonables, e Hibernate es distribuido con un archivo hibernate.properties de ejemplo en el directorio etc/, que muestra varias de las opciones. Simplemente coloque este ejemplo en su classpath y modifquelo a medida.

3.1. Configuracin programtica


Una instancia de org.hibernate.cfg.Configuration representa un conjunto completo de mapeos desde los tipos Java de una aplicacin, hacia una base de datos SQL. org.hibernate.cfg.Configuration se usa para construir una org.hibernate.SessionFactory inmutable. Los mapeos son compilados a partir de los varios archivos de mapeo XML. Se puede ontener una instancia de org.hibernate.cfg.Configuration instancindola directamente, y especificando los archivos de mapeo XML. Si los archivos de mapeo estn en el classpath, utilice addResource():
Configuration cfg = new Configuration() .addResource("Item.hbm.xml") .addResource("Bid.hbm.xml");

Una alternativa (a veces preferible), es especificar la clase mapeada, y dejar que Hibernate encuentre el documento de mapeo l solo:
Configuration cfg = new Configuration() .addClass(org.hibernate.auction.Item.class) .addClass(org.hibernate.auction.Bid.class);

/auction/Bid.hbm.xml en el calsspath. Este

Entonces Hibernate buscar archivos de mapeo llamados /org/hibernate/auction/Item.hbm.xml y /org/hibernate enfoque elimina la necesidad de "hardcodear" los nombres de archivo.
org.hibernate.cfg.Configuration tambin permite

especificar propiedades de configuracin:

Configuration cfg = new Configuration() .addClass(org.hibernate.auction.Item.class) .addClass(org.hibernate.auction.Bid.class) .setProperty("hibernate.dialect", "org.hibernate.dialect.MySQLInnoDBDialect") .setProperty("hibernate.connection.datasource", "java:comp/env/jdbc/test") .setProperty("hibernate.order_updates", "true");

sta no es la nica manera de pasarle propiedades de configuracin a Hibernate. Entre las muchas otras opciones, estn stas: Pasarle una instancia de java.util.Properties a Configuration.setProperties(). Colocar un archivo llamado hibernate.properties en un directorio raz del classpath. Configurar propiedades "de sistema" (System) usando java -Dproperty=value.

28 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

Incluir elementos <property> en hibernate.cfg.xml (se discute ms adelante).


hibernate.properties es el enfoque

ms fcil, si lo que se busca es empezar rpido.

La idea de org.hibernate.cfg.Configuration es ser un objeto que viva durante el "tiempo de arranque" (startup), para ser descartado luego, una vez que la SessionFactory haya sido creada.

3.2. Obtener una SessionFactory


Una vez que todos los mapeos hayan sido revisados por org.hibernate.cfg.Configuration, la aplicacin debe obtener una fbrica o "SessionFactory" para las instancias de org.hibernate.Session. Esta fbrica ser compartida por todos los threads que accedan a la aplicacn.
SessionFactory sessions = cfg.buildSessionFactory();

Hibernate s le permite a la aplicacin instanciar ms de una org.hibernate.SessionFactory. Esto es til si se est usando ms de una base de datos.

3.3. Conexiones JDBC


Usualmente, usted querr que la org.hibernate.SessionFactory cree y administre el "fondo comn" (pool) de sesiones por usted. Si se adopta este enfoque, abrir una org.hibernate.Session es tan simple como escribir:
Session session = sessions.openSession(); // abre una nueva sesin

No bien se haga algo que requiera acceso a la base de datos, una nueva conexin JDBC ser obtenida del "pool". Para que esto funcione, necesitamos pasarle algunas propiedades de conexin JDBC a Hibernate. Todos los nombres y semntica de las propiedades Hibernate estn definidos en la clase org.hibernate.cfg.Environment. Vamos a describir los valores ms importantes para configurar la conexin JDBC. Hibernate obtendr las conexiones (y las administrar en un "pool") usando un java.sql.DriverManager si usted configura las siguientes propiedades: Table 3.1. Hibernate JDBC Properties Nombre de la propiedad Propsito

hibernate.connection.driver_class clase del driver JDBC hibernate.connection.url hibernate.connection.username hibernate.connection.password hibernate.connection.pool_size URL de JDBC usuario de la base de datos clave del usuario de la base de datos nmero mximo de conexiones en el "pool"

El algoritmo que ya viene incluido en Hibernate para el "pooling" de conexiones es, sin embargo, bastante rudimentario. Fue concebido ms que nada para ayudarlo a dar los primeros pasos, no para ser usado en un sistema de produccin, ni siquiera para un test de performance. Ustde debera usar un "pool" de algn tercero para asegurar mayor redimiento y estabilidad. Simplemente reemplace la propiedad hibernate.connection.pool_size con propiedades especficas de la herramienta de "pooling" de su eleccin. Esto desactivar el "pooling" interno de Hibernate. Por ejemplo, usted podra elegir C3P0. C3P0 es una biblioteca para pool de conexiones distribuida junto con Hibernate en el direactorio lib. Hibernate usar su para efectuar el "pooling" de conexiones, si usted les asigna valores a las propiedades que empiezan con hibernate.c3p0.*. Si prefiere usar Proxool, refirase a las propiedades empaquetadas en hibernate.properties, o al sitio de web de Hibernate para mayor informacin. He aqu un ejemplo de un hibernate.properties para C3P0:
hibernate.connection.driver_class = org.postgresql.Driver

org.hibernate.connection.C3P0ConnectionProvider

29 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

hibernate.connection.url = jdbc:postgresql://localhost/mydatabase hibernate.connection.username = myuser hibernate.connection.password = secret hibernate.c3p0.min_size=5 hibernate.c3p0.max_size=20 hibernate.c3p0.timeout=1800 hibernate.c3p0.max_statements=50 hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect

Para usar "pooling" dentro de un servidor de aplicaciones, se debera configurar Hibernate de manera tal, que siempre obtenga las conexiones desde una fuente de datos javax.sql.Datasource registrada usando JNDI. Se necesitarn por lo menos las siguientes propiedades: Table 3.2. Propiedades para fuente de datos de Hibernate Nombre de la propiedad Propsito

hibernate.connection.datasource nombre JNDI de la fuente de datos hibernate.jndi.url hibernate.jndi.class hibernate.connection.username hibernate.connection.password URL del proveedor de JNDI (optativo) clase del InitialContextFactory de JNDI (optativo) usuario de la base de datos (optativo) clave del usuario de base de datos (optativo)

He aqu un ejemplo de un archivo hibernate.properties para configurar la fuente de datos JNDI en un servidor de aplicaciones:
hibernate.connection.datasource = java:/comp/env/jdbc/test hibernate.transaction.factory_class = org.hibernate.transaction.JTATransactionFactory hibernate.transaction.manager_lookup_class = org.hibernate.transaction.JBossTransactionManagerLooku hibernate.dialect = org.hibernate.dialect.PostgreSQLDialect

Las conexiones JDBC que se obtengan de una fuente de datos JNDI participarn automticamente de las transacciones "manejadas por el contenedor" del servidor de aplicaciones. Tambin se pueden agregar propiedades de conexin arbitrarias, afijando "hibernate.connection" al nombre de la propiedad de conexin. Por ejemplo, usted puede especificar una propiedad de conexin charSet (juego de caracteres), usando "hibernate.connection.charSet". Usted tambin puede definir su propia estrategia de plugin para obtener conexiones JDBC, implementando la interfaz org.hibernate.connection.ConnectionProvider, y especificando su propia implementacin a medida en la propiedad hibernate.connection.provider_class.

3.4. Propiedades optativas de configuracin


Hay varias otras propiedades que controlan el comportamiento de Hibernate en tiempo de ejecucin. Todas son optativas, y tienen valores por defecto razonables. Advertencia: algunas de estas propiedades existen "a nivel de sistema" solamente. A las propiedades a nivel de sistema slo se les puede asignar valores via java -Dproperty=value o hibernate.properties. No se les puede asignar valores usando las tcnicas descritas anteriormente. Tabla 3.3. Porpiedades de Configuration de Hibernate Nombre de la propiedad Propsito

El nombre de clase de un org.hibernate.dialect.Dialect que le permita a Hibernate generar SQL optimizado para una BD relacional en particular. Tabla 3.4. Propiedades Hibernate de JDBC y Conexin hibernate.dialect Nombre de la propiedad hibernate.jdbc.fetch_size por ejemplo classname.completo.del.dialecto Propsito En laUn mayora de los casos, Hibernateel ser capaz de la implementacin valor distinto de 0 determina tamao de laelegir captura o "fetch" JDBC de (llama dialecto correcta, basndose en los metadatos devueltos por el driver JDBC. ). a Statement.setFetchSize()

30 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

Nombre de la propiedad

Propsito Un valor distinto de 0 habilita el uso de actualizacionesn en lotes (batch updates) de JDBC2 por parte de Hibernate.

hibernate.jdbc.batch_size valores posibles se recomienda entre 5 y 30 Asgnele true a esta propiedad, si su driver JDBC devuelve conteos de fila al ejecutar executeBatch() (normalmente, es seguro hacerlo). Entonces, Hibernate usar "batched DML" (lenguaje de creacin de datos en lotes) para datos a los que se les haya asignado automtiacmente nmero de versin. El valor por defecto es false. valores posibles true | false Selecciona un org.hibernate.jdbc.Batcher hecho a medida. La mayora de las aplicaciones no necesita configurar esta propiedad. hibernate.jdbc.factory_class por ejemplo classname.of.BatcherFactory Habilita el uso de resultados JDBC2 navegables (scrollable resultsets) por parte de Hibernate. Esta propiedad slo es necesaria cuando se emplean conexiones JDBC provistas por el usuario. De otro modo, Hibernate usa los metadatos de la conexin. valores posibles true | false Indica que se usarn streams al leer o escribir cdigo binario, o tipos serializables desde o hacia JDBC. *propiedad a nivel de sistema* hibernate.jdbc.use_streams_for_binary valores posibles true | false Habilita el uso del PreparedStatement.getGeneratedKeys() de JDBC3 para capturar claves generadas en forma nativa luego de insertar. Requiere que a Requires JDBC3+ driver y a JRE1.4+, le sea asignado "false" si el driver que usted est usando tiene problemas con los generadores de identificadores. Por hibernate.jdbc.use_get_generated_keys defecto, intenta determinar las capacidades del driver usando los metadatos de conexin. valores posibles true|false El nombre de clase de un
org.hibernate.connection.ConnectionProvider

hibernate.jdbc.batch_versioned_data

hibernate.jdbc.use_scrollable_resultset

hecho a medida que le

hibernate.connection.provider_class

provea conexiones JDBC a Hibernate. por ejemplo classname.of.ConnectionProvider Determina el nivel de aislamiento de las transacciones JDBC. Revise java.sql.Connection para averiguar qu valores tiene sentido asignar aqu, pero note que la mayora de las BD no soportan todos los niveles de aislamiento (isloation levels), y algunas definen niveles no estndar adicionales. por ejemplo 1, 2, 4, 8 Habilita la autocomisin (autocommit) para las conexiones JDBC en pool (no se recomienda).

hibernate.connection.isolation

hibernate.connection.autocommit valors posibles true | false

31 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

Nombre de la propiedad

Propsito Especifica cundo Hibernate debera liberar conexiones. Por defecto, una conexin JDBC es retenida hasta que la sesin es cerrada explcitamente o desconectada. Para fuentes de datos JTA en un servidor de aplicaciones, se debera usar after_statement para liberar conexiones agresivamente luego de cada llamado a JDBC. Para conexiones que no sean JTA, a menudo tiene sentido liberar las conexiones al final de cada transaccin, usando after_transaction. auto elegir after_statement para las estrategias JTA y CMT (manejadas por el contenedor), y after_transaction para las estrategias transaccionales JDBC.

hibernate.connection.release_mode

valores posibles auto (el valor por defecto) | on_close | after_transaction | after_statement Note que este valor slo afecta sesiones devueltas por SessionFactory.openSession. Para las que se hayan obtenido usando SessionFactory.getCurrentSession, lo que importa para determinar el modo de liberacin de conexiones, es la implementacin que se haya configurado de CurrentSessionContext. Vea la Seccin 2.5, Sesiones Contextuales

hibernate.connection. <nombreDeLaPropiedad> hibernate.jndi. <nombreDeLaPropiedad>

Le pasa el valor de propiedad JDBC <propertyName> a DriverManager.getConnection(). Le pasa la propiedad <nombreDeLaPropiedad> a la InitialContextFactory de JNDI.

Tabla 3.5. Propiedades del cach de Hibernate Nombre de la propiedad


hibernate.cache.provider_class

Propsito El nombre de clase de un CacheProvider hecha a medida. por ejemplo classname.of.CacheProvider Optimiza el cach de 2do nivel para minimizar escrituras, al costo de realizar lecturas ms frecuentemente. Esta configuracin es ms til con cachs en "cluster", y en Hibernate3 se habilita por defecto con cachs en cluster. valores posibles true|false Habilita el cach de consultas. Cada consulta (query) debe ser individualmente configurada como "cacheable".

hibernate.cache.use_minimal_puts

hibernate.cache.use_query_cache

valores posibles true|false Puede ser usado para inhabilitar completamente el cach de 2do nivel, el cual est habilitado por defecto para toda clase que especifique un hibernate.cache.use_second_level_cache mapeo <cache> valores posibles true|false El nombre de una interfaz QueryCache personalizada, que por defecto es StandardQueryCache, la cual ya viene de fbrica.
hibernate.cache.query_cache_factory

por ejemplo classname.of.QueryCache

32 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

Nombre de la propiedad
hibernate.cache.region_prefix

Propsito Un prefijo a usar con los nombres de regin de cach de 2do nivel. por ejemplo prefix Fuerza a Hibernate a almacenar datos en el cach de 2do nivel en un formato ms legible.

hibernate.cache.use_structured_entries

valores posibles true|false

Tabla 3.6. Propiedades para la configuracin de transaciones en Hibernate Nombre de la propiedad Propsito El nombre de clase de la TransactionFactory a usar con Hibernate (por defecto, JDBCTransactionFactory).
hibernate.transaction.factory_class

por ejemplo classname.of.TransactionFactory El nombre JNDI usado por JTATransactionFactory para obtener una UserTransaction JTA del servidor de aplicaciones. por ejemplo jndi/composite/name El nombre de clase de un TransactionManagerLookup. Obligatorio cuando se utiliza cach a nivel de la JVM, o se usa el generador hilo en un entorno JTA. por ejemplo classname.of.TransactionManagerLookup Si est habilitado, a la sesin le ser automtiamente hecho un "flush" antes de la fase de complecin de la transaccin. Es preferible usar el manejo de transacciones que ya viene hibernate.transaction.flush_before_completion incorporado, y el manejo automtico de contexto de sesiones; ver laSeccin 2.5, Sesiones contextuales. valores posibles true | false Si est habilitado, la sesin ser automticamente cerrada durante la fase de complecin de la transaccin. Es preferible usar el manejo de transacciones que ya viene incorporado, y el manejo automtico de contexto de sesiones; ver la Seccin 2.5, Sesiones contextuales. valores posibles true | false

jta.UserTransaction

hibernate.transaction.manager_lookup_class

hibernate.transaction.auto_close_session

Tabla 3.7. Propiedades Miscelneas Nombre de la propiedad Propsito

Provee una estrategia personalizada para determinar el alcance (scope) respecto de cul es la sesin "actual". Vase la Seccin 2.5, Sesiones Contextuales para ms informacin sobre cules son las 3.4.1. Dialectos de SQL hibernate.current_session_context_class opciones que ya vienen incorporadas. Siempre se debera configurar la propiedad hibernate.dialect al valor correcto. de la subclase de jta | thread | managed | la clase valores posibles org.hibernate.dialect.Dialect que corresponda a su BD. Si se especifica un dialecto, Hibernate usar valores por personalizada defecto adecuados para otras de las propiedades listadas anteriormente, ahorrndole el esfuerzo de especificarlas

33 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

manualmente. Tabla 3.8. Dialectos SQL de Hibernate (hibernate.dialect) Base de datos relacional DB2 DB2 AS/400 DB2 OS390 PostgreSQL MySQL MySQL with InnoDB MySQL with MyISAM Oracle (any version) Oracle 9i/10g Sybase Sybase Anywhere Microsoft SQL Server SAP DB Informix HypersonicSQL Ingres Progress Mckoi SQL Interbase Pointbase FrontBase Firebird Dialecto
org.hibernate.dialect.DB2Dialect org.hibernate.dialect.DB2400Dialect org.hibernate.dialect.DB2390Dialect org.hibernate.dialect.PostgreSQLDialect org.hibernate.dialect.MySQLDialect org.hibernate.dialect.MySQLInnoDBDialect org.hibernate.dialect.MySQLMyISAMDialect org.hibernate.dialect.OracleDialect org.hibernate.dialect.Oracle9Dialect org.hibernate.dialect.SybaseDialect org.hibernate.dialect.SybaseAnywhereDialect org.hibernate.dialect.SQLServerDialect org.hibernate.dialect.SAPDBDialect org.hibernate.dialect.InformixDialect org.hibernate.dialect.HSQLDialect org.hibernate.dialect.IngresDialect org.hibernate.dialect.ProgressDialect org.hibernate.dialect.MckoiDialect org.hibernate.dialect.InterbaseDialect org.hibernate.dialect.PointbaseDialect org.hibernate.dialect.FrontbaseDialect org.hibernate.dialect.FirebirdDialect

3.4.2. Captura (fetch) por Outer Join


Si su base de datos soporta outer joins del estilo ANSI, Oracle o Sybase, la captura con outer joins a menudo aumentar la performance, limitando la cantidad de viajes de ida y vuelta a la BD (probablemente a costa de un mayor trabajo efectuado por la base de datos misma). La captura por outer joins permite que todo un rbol (graph) de ojetos conectados por asociaciones de-uno-a-muchos, de-muchos-a-uno, de-muchos-a-muchos, y de-uno-a-uno sea capturado de una sola vez, con un solo comando SQL SELECT. La captura mediante outer joins puede ser inhabilitada globalmente asignndole el valor 0. a la propiedad de 1 o superior, se permiten las capturas (fetch) con outer joins para asociaciones que hayan sido mapeadas como de-una-a-una o de-muchas-a-una con fetch="join".
hibernate.max_fetch_depth. Al asignar un valor

Vea Seccin 19.1, Estrategias de captura (fetch) para ms informacin.

3.4.3. Streams binarios


Oracle limita el tamao de los arrays de tipo byte que pueden ser pasados desde y hacia el driver JDBC. Si usted desea usar instancias grandes de tipos binary o serializable, debera habilitar hibernate.jdbc.use_streams_for_binary. sta es una propiedad configurable a nivel de sistema solamente.

34 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

3.4.4. Cach de 2do nivel y cach de consultas.


Las propiedades con prefijo hibernate.cache le permiten usar un sistema de cach de 2do nivel con alcance (scope) de proceso o de cluster. Vea Seccin 19.2, El cach de 2do nivel para ms detalles.

3.4.5. Sustituciones en el lenguaje de consultas.


Se pueden definir nuevos smbolos para las consultas de Hibernate usando hibernate.query.substitutions. Por ejemplo:
hibernate.query.substitutions true=1, false=0

causr que los smbolos true y false sean traducidos como valores enteros literates en el SQL que se genere.
hibernate.query.substitutions toLowercase=LOWER

permitira renombrar la propiedad LOWER (pasar a minsculas) de SQL

3.4.6. Estadsticas de Hibernate


Si se habilita hibernate.generate_statistics, Hibernate expondr un buen nmero de mediciones que son tiles al ajustar (tuning) el rendimiento de un sistema en marcha, a travs de SessionFactory.getStatistics(). Hibernate incluso puede ser configurado para exponer dichas estadsticas via JMX. Lea el Javadoc de las interfaces en org.hibernate.stats para ms informacin.

3.5. Logueo (logging, bitcora)


Hibernate utiliza la librera llamada "Fachada simple de logueo para Java" (Simple Logging Facade for Java o SLF4J por sus siglas en ingls), para loguear varios eventos de sistema. SLF4J puede dirigir la salida de su actividad de logueo a varios "frameworks" de logueo: NOP, Simple, log4j 1.2, JDK 1.4, JCL o logback), dependiendo de la vinculacin elegida. Para configurar el logueo adecuadamente, necesitar slf4j-api.jar en su classpath, as como el archivo de jar de su preferencia (en el caso de log4j, slf4j-log4j12.jar). Vea la documentacin de SLF4J para ms detalles. Para usar log4j tambin necesitar colocar un archivo log4j.properties en su classpath. Un archivo de propiedades a modo de ejemplo viene distribuido con Hibernate en el directorio src/. Le recomendamos fuertemente que se familiarice con los mensajes de log de Hibernate. Se ha invertido mucho trabajo en lograr que el logueo en Hibernate sea lo ms detallado posible, sin volverlo ilegible. Es una herramienta esencial para la deteccin y resolucin de problemas. Las categoras ms interesantes son las siguientes: Table 3.9. Hibernate Log Categories Category (categora)
org.hibernate.SQL org.hibernate.type org.hibernate.tool.hbm2ddl

Funcin Loguea todo el "lenguaje de modificacin de datos" (DML) de SQL a medida que ste es ejecutado. Loguea todos los parmetros JDBC Loguea todos los comandos SQL de definicin de datos (DDL) que hayan sido ejecutados Loguea el estado de todas las entidades (con un mximo de 20) asociadas con una sesin al momento de aplicarle "flush". Loguea toda la actividad del cach de 2do nivel Loguea toda actividad relacionada con transacciones Loguea toda adquisicin de recursos JDBC Loguea todo AST de HQL y SQL durante la revisin (parsing) de las consultas

org.hibernate.pretty org.hibernate.cache org.hibernate.transaction org.hibernate.jdbc org.hibernate.hql.ast.AST

35 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

Category (categora)
org.hibernate.secure org.hibernate

Funcin Loguea todas las autorizaciones para requests JAAS Loguea todo (un montn de informacin, pero muy til a para detectar y solucionar problemas).

org.hibernate.SQL,

Al desarrollar aplicaciones con Hibernate, se debera trabajar casi siempre con debug habilitado para o, alternativamente, habilitar la propiedad hibernate.show_sql enabled.

3.6. Implementar una NamingStrategy


La interfaz org.hibernate.cfg.NamingStrategy permite especificar un estndar de nombrado o "NamingStrategy" para los objetos de base de datos y elementos del esquema. Usted puede proveer reglas para generar automticamente los identificadores a partir de identificadores Java, o para procesar los nombres de tabla y columna "lgicos" dados en el archivo de mapeo, y convertirlos en nombres de tabla y columna "fsicos". Esta caracterstica reduce la locuacidad de los documentos de mapeo, eliminando el "ruido" provocado por la repeticin de prefijos TBL_, por ejemplo. La estrategia que Hibernate usa por defecto es bastante parca. Se puede especificar una estrategia diferente, llamando a Configuration.setNamingStrategy() antes de agregar mapeos.
SessionFactory sf = new Configuration() .setNamingStrategy(ImprovedNamingStrategy.INSTANCE) .addFile("Item.hbm.xml") .addFile("Bid.hbm.xml") .buildSessionFactory(); org.hibernate.cfg.ImprovedNamingStrategy

es una estrategia que ya viene de incorporada, y puede ser un punto de

partida til para algunas aplicaciones.

3.7. Archivo de configuracin XML


Un enfoque alternativo de configuracin, es especificar la configuracin completa en un archivo llamado hibernate.cfg.xml. Este archivo puede usarse en reemplazo del archivo hibernate.properties, o, si ambos estn presentes, para suplantar propiedades de ste. Se espera que el archivo de configuracin XML est por defecto en la raz de su CLASSPATH. He aqu un ejemplo:
<?xml version='1.0' encoding='utf-8'?> <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"> <hibernate-configuration> <!-- una instancia de SessionFactory listada como /jndi/name --> <session-factory name="java:hibernate/SessionFactory"> <!-- propiedades --> <property name="connection.datasource">java:/comp/env/jdbc/MyDB</property> <property name="dialect">org.hibernate.dialect.MySQLDialect</property> <property name="show_sql">false</property> <property name="transaction.factory_class"> org.hibernate.transaction.JTATransactionFactory </property> <property name="jta.UserTransaction">java:comp/UserTransaction</property> <!-- archivos de mapeo --> <mapping resource="org/hibernate/auction/Item.hbm.xml"/> <mapping resource="org/hibernate/auction/Bid.hbm.xml"/> <!-- configuracin del cach -->

36 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

<class-cache class="org.hibernate.auction.Item" usage="read-write"/> <class-cache class="org.hibernate.auction.Bid" usage="read-only"/> <collection-cache collection="org.hibernate.auction.Item.bids" usage="read-write"/> </session-factory> </hibernate-configuration>

Como se puede ver, la ventaja de este enfoque es externalizar la configuracin de los nombres de los acrhivos de mapeo. hibernate.cfg.xml tambin es ms conveniente para ajustar los valores del cach. Note que usar hibernate.cfg.xml o hibernate.properties es indistinto, excepto por los beneficios mencionados de usar una sintaxis XML. Con la configuracin XML, hacer arrancar a Hibernate es tan simple como:
SessionFactory sf = new Configuration().configure().buildSessionFactory();

Se puede elegir un archivo distinto de configuracin, usando:


SessionFactory sf = new Configuration() .configure("catdb.cfg.xml") .buildSessionFactory();

3.8. Integracin con los Servidores de Aplicacin J2EE


Hibernate tiene los siguientes puntos de integracin con la infraestructura J2EE Fuentes de datos manejadas por el contenedor: Hibernate puede usar conexiones JDBC manejadas por el contenedor (container-mamaged), provistas a travs de JNDI. Usualmente, un TransactionManager compatible con JTA y un ResourceManager se hacen cargo del manejo de transacciones (CMT), especialmente transcciones distribuidas a lo largo de varias fuentes de datos. Por supuesto, usted tambin puede demarcar los lmites de sus transacciones programticamente (BMT) o usar la API de transacciones de Hibernate (Transaction) para mantener su cdigo portable. Enlace JNDI automtico: Hibernate puede ligar su SessionFactory a JNDI luego del arranque. Enlace de sesin JTA: La sesin de Hibernate puede ser automticamente ligada al alcance o "scope" de las transacciones JTA. Simplemente obtenga la SessionFactory de JNID (haciendo un "lookup"), y de ah obtenga la sesin actual. Deje que Hibernate se haga cargo de aplicarle "flush" y de cerrar la sesin cuando la transaccin JTA se haya terminado. La demarcacin de transacciones es o bien declarativa (CMT) o bien programtica (BMT/UserTransaction). Despliegue JMX: Si usted cuenta con un servidor de aplicaciones habilitado para JMX, (por ejemplo, JBoss), puede elegir desplegar Hibernate como un "Managed MBean" Esto le ahorra el cdgo de arranque de una lnea que construye la SessionFactory a partir de Configuration. El container har arrancar su HibernateService, e, idealmente, tambin se har cargo de las dependencias de servicios (la fuente de datos tiene que estar disponible antes de que Hibernate arranque, etc). Dependiendo del entorno, usted puede tener que asignar el valor "true" a la opcin de configuracin hibernate.connection.aggressive_release, si su servidor de aplicaciones produce excepciones de "contencin de conexiones" ("connection containment" exceptions).

3.8.1. Configuracin de una estrategia transaccional


La sesin de Hibernate es independiente de cualquier sistema de demarcacin de transacciones presente en la arquitectura de su sistema. Si usted deja que Hibernate use JDBC directamente a travs de un "pool" de conexiones, usted puede comenzar y terminar sus transacciones llamando a la API de JDBC. Si usted ejecuta su aplicacin en un servidor de aplicaciones J2EE, es posible que prefiera usar transaccioes manejadas por bean (bean-managed) e invocar la API de JTA y UserTransaction segn haga falta. Para mantener su cdigo portable entre estos dos entornos (y otros), le recomedamos emplear la API Transaction de Hibernate, la cual envuelve y oculta el sistema subyacente. Va a tener que especificar una clase "fbrica" de instancias de Transaction, configurando la propiedad de Hibernate hibernate.transaction.factory_class.

37 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

stas son las tres opciones estndar, que ya vienen incluidas "de fbrica":
org.hibernate.transaction.JDBCTransactionFactory

delega a las transacciones JDBC de la base de datos (es el valor por defecto)
org.hibernate.transaction.JTATransactionFactory

delega a la transaccin manejada por el contenedor (container-managed) si hay una tranasccin en proceso en este contexto (por ejemplo, un mtodo de un Session EJB), en caso contrario, crea una nueva transcin, y se utilizan transacciones manejadas por bean.
org.hibernate.transaction.CMTTransactionFactory

delega a transacciones JTA manejadas por el contenedor Usted tambin puede definir sus propias estrategias transaccionales (por un servicio de transacciones CORBA, por ejemplo). Algunas caractersticas de Hibernate (por ejemplo, cach de 2do nivel, sesiones contextuales con JTA, etc) requieren aceso al TransactionManager de JTA en un entorno administrado. En un servidor de aplicaciones, usted tiene que especificar cmo Hibernate obtendr una referencia al TransactionManager, dado que en J2EE no hay un mecanismo estndar y nico. Tabla 3.10. TransactionManagers de JTA Fbrica de transacciones
org.hibernate.transaction.JBossTransactionManagerLookup org.hibernate.transaction.WeblogicTransactionManagerLookup org.hibernate.transaction.WebSphereTransactionManagerLookup org.hibernate.transaction.WebSphereExtendedJTATransactionLookup org.hibernate.transaction.OrionTransactionManagerLookup org.hibernate.transaction.ResinTransactionManagerLookup org.hibernate.transaction.JOTMTransactionManagerLookup org.hibernate.transaction.JOnASTransactionManagerLookup org.hibernate.transaction.JRun4TransactionManagerLookup org.hibernate.transaction.BESTransactionManagerLookup

Servidor de aplicaciones JBoss Weblogic WebSphere WebSphere 6 Orion Resin JOTM JOnAS JRun4 Borland ES

3.8.2. SessionFactory ligada a JNDI


Una fbrica de sesiones (SessionFactory) ligada a JNDI puede simplificar la bsqueda y obtencin (lookup) de nuevas sesiones. Note que esto no se relaciona con las Datasource, tambin ligadas a JNDI, ambas simplemente comparten el mismo repositorio de registro (registry)! Si usted desea mantener la fbrica de sesiones ligada a un "espacio de nombre" o "namespace" JNDI, especifique un nombre (por ejemplo, java:hibernate/SessionFactory) usando la propiedad hibernate.session_factory_name. Si esta propiedad es omitida, la fbrica de sesiones no quedar ligada a JNDI. (Esto es especialmente til en entornos que por defecto tienen una JNDI de slo lectura, como por ejemplo Tomcat). Cuando de liga una fbrica de sesiones a JNDI, Hibernate emplear los valores de hibernate.jndi.url y hibernate.jndi.class para instanciar un contexto inicial. Si no son especificadas, se usa el InitialContext por defecto. Hibernate colocar la fbrica de sesiones (SessionFactory) automticamente en JNDI en cuanto se invoque cfg.buildSessionFactory(). Esto significa que este llamado estar presente, por lo menos, en algn cdigo de arranque (o clase utilitaria) de su aplicacin, a menos que usted usa el despliegue JMX, con HibernateService (lo cual se discute luego).

38 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

Si usted usa una fbrica de sesiones JNDI, un EJB o cualquier otra clase puede obtenerla usando el JNDI lookup. Le recomendamos que, en un entorno administrado, use JNDI para obtener sus fbricas de sesiones, y en cualquier otro entorno, un singleton esttico. Para escudar su aplicacin de estos detalles, tambin le recomendamos que oculte el cdigo que efectivamente realiza el "lookup" dentro de una clase utilitaria, (como por ejemplo, HibernateUtil.getSessionFactory()). Note que dicha clase es tambin una buena manera de hacer arrancar Hibernate (captulo 1).

3.8.3. Manejo del contexto actual de la sesin con JTA


La manera ms fcil de manejar sesiones y transacciones es el manejo automtico que Hibernate hace de la "sesin actual". Vea la discusin en Sesiones actuales. Usando el contexto de sesin "jta", si no hay ninguna sesin de Hibernate asociada con la transaccin JTA actual, se crear una y se la asociar con la transaccin la primera vez que sessionFactory.getCurrentSession() sea invocada. A las sesiones que hayan sido creadas de esta manera, les ser automticamente efectuado el "flush" antes de que la transaccin finalice, sern cerradas despus de que la transaccin finalice, y las conexiones JDBC sern agresivamente liberadas despus de cada comando. Esto permite que las sesiones sean manejadas por el ciclo de vida de la transaccin JTA al cual estn asociadas, manteniendo al cdigo libre de ese tipo de preocupaciones administrativas. Su cdigo puede utilizar o bien JTA programticamente a travs de UserTransaction, o (lo que ms recomendamos para producir cdigo portable) usar la API de Transaction de Hibernate para establecer los lmites de la transaccin. Si su aplicacin se est ejecutando en un contenedor de EJB, se prefiere utilizar demarcacin declarativa de transacciones con CMT (siglas en ingls de "transacciones manejadas por el contenedor").

3.8.4. Despliegue de JMX


La lnea cfg.buildSessionFactory() an tiene que ser ejecutada en algn lado para meter una fbrica de sesiones en JNDI. Esto se puede lograr o bien con un bloque inicializador esttico en una clase utilitaria (como el que est en HibernateUtil) o bien desplegando Hibernate como un "servicio administrado" (managed service), Hibernate es distribuido con org.hibernate.jmx.HibernateService para el despliegue en servidores de aplicaciones con capacidad JMX, como JBoss. El despliegue y configuracin son especficos de la marca del servidor. He aqu un jboss-service.xml de ejemplo para for JBoss 4.0.x:
<?xml version="1.0"?> <server> <mbean code="org.hibernate.jmx.HibernateService" name="jboss.jca:service=HibernateFactory,name=HibernateFactory"> <!-- Servicios requeridos --> <depends>jboss.jca:service=RARDeployer</depends> <depends>jboss.jca:service=LocalTxCM,name=HsqlDS</depends> <!-- Ligar el servicio Hibernate a JNDI --> <attribute name="JndiName">java:/hibernate/SessionFactory</attribute> <!-- fuente de datos --> <attribute name="Datasource">java:HsqlDS</attribute> <attribute name="Dialect">org.hibernate.dialect.HSQLDialect</attribute> <!-- integracin de transacciones --> <attribute name="TransactionStrategy">org.hibernate.transaction.JTATransactionFactory</attribut <attribute name="TransactionManagerLookupStrategy">org.hibernate.transaction.JBossTransactionMa <attribute name="FlushBeforeCompletionEnabled">true</attribute> <attribute name="AutoCloseSessionEnabled">true</attribute> <!-- opciones de captura --> <attribute name="MaximumFetchDepth">5</attribute> <!-- cach <attribute <attribute <attribute de 2do nivel --> name="SecondLevelCacheEnabled">true</attribute> name="CacheProviderClass">org.hibernate.cache.EhCacheProvider</attribute> name="QueryCacheEnabled">true</attribute>

<!-- Logueo --> <attribute name="ShowSqlEnabled">true</attribute> <!-- archivos de mapeo -->

39 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

<attribute name="MapResources">auction/Item.hbm.xml,auction/Category.hbm.xml</attribute> </mbean> </server>

Este archivo es desplegado en un directorio llamado META-INF, y empaquetado en un archivo JAR con la extensin .sar (service archive o "archivo de servicio). Sus EJB (usualmente session beans) pueden ser conservados en su propio archivo JAR, pero este archivo JAR de EJB se puede incluir en el archivo principal de servicio para obtener una nica desplegable "en caliente" (hot deployment). Consulte la documentacin del servidor de aplicaciones JBoss para ms informacin acerca del servicio JMX y el despliegue de EJB.

Captulo 4. Clases Persistentes


Las clases persistentes son clases de una aplicacin que implementen las entidades de un problema de negocios (por ejemplo, "Cliente" y "Orden" en una aplicacin de e-commerce). No todas las instancias de una clase persistente se considera que estn en un "estado persistente". Una instancia pude, en cambio, ser transitoria (transient) o desprendida (detached). Hibernate trabaja mejor si estas clases siguen un formato muy simple, conocido como el modelo de programacin de "objeto Java liso y llano" o POJO (Plain Old Java Object) por sus siglas en ingls. Sin embargo, ninguna de estas reglas es estrictamente obligatoria. Mas an, Hibernate3 presupone muy poco acerca de la naturaleza de sus objetos persistentes. Un modelo de dominio (domain model) se puede expresar de otras maneras: mediante rboles de instancias de Map, por ejemplo.

4.1. Un simple ejemplo de POJO


La mayora de las aplicaciones Java requieren una clase persistente que represente felinos:
package eg; import java.util.Set; import java.util.Date; public class Cat { private Long id; // identificador private private private private private Date birthdate; Color color; char sex; float weight; int litterId;

private Cat mother; private Set kittens = new HashSet(); private void setId(Long id) { this.id=id; } public Long getId() { return id; } void setBirthdate(Date date) { birthdate = date; } public Date getBirthdate() { return birthdate; } void setWeight(float weight) { this.weight = weight; } public float getWeight() { return weight; } public Color getColor() { return color; } void setColor(Color color) {

40 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

this.color = color; } void setSex(char sex) { this.sex=sex; } public char getSex() { return sex; } //litter=en ingls, camada void setLitterId(int id) { this.litterId = id; } public int getLitterId() { return litterId; } void setMother(Cat mother) { this.mother = mother; } public Cat getMother() { return mother; } //kittens=gatitos void setKittens(Set kittens) { this.kittens = kittens; } public Set getKittens() { return kittens; } // addKitten no es requerido por Hibernate public void addKitten(Cat kitten) { kitten.setMother(this); kitten.setLitterId( kittens.size() ); kittens.add(kitten); } }

Aqu hay 4 reglas principales a seguir:

4.1.1. Implemente un constructor sin argumentos


Cat tiene un constuctor sin argumentos. Todas las clases persistentes deben tener un constuctor por defecto (el cual puede no ser pblico) de manera qu Hibernate pueda instanciarlas usando Constructor.newInstance(). Recomendamos fuertemente un constructor por defecto, que tenga al menos visibilidad package para la generacin del "proxy" en Hibernate.

4.1.2. Provea una propiedad indentificadora (optativo)


una propiedad llamada id. Esta propiedad corresponde a la columna de clave primaria de la base de datos. La propiedad puede llamarse como sea, y su tipo puede ser cualquiera de los tipos de dato primitivos, cualquier tipo "envoltorio" (wrapper), java.lang.String, o java.util.Date. Si su base de datos anticuada tiene claves compuestas, usted puede usar inclusive una clase definida por el usuario con propiedades de los tipos mencionados (vea la seccin sobre claves compuestas ms adelante). La propiedad indentificadora es estrictamente optativa. La puede omitir e Hibernate an podr seguirle la pista al objeto, internamente. De todos modos, no le recomendamos que haga esto. De hecho, algunas de las funcoionalidades estn disponibles slo para aquellas clases que s tienen identificador. Recuperacin (reattachment) transitiva para objetos desprendidos (update o merge en cascada)-vea Seccin 10.11, Persistencia Transitiva
Session.saveOrUpdate() Session.merge() Cat tiene

Le recomendamos que declare propiedades indentificador nombradas de una manera consistente, en sus clases

41 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

persistentes. Mas an, le recomendamos que use un tipo anulable (es decir, no primitivo).

4.1.3. Prefiera clases que no sean finales (optativo)


Una caracterstica central de Hibernate, los representantes o proxies, depende de que la clase persistente no sea final, o de que sea la implementacin de una interfaz con todos sus mtodos pblicos. Se puede persistir clases finales que no implementen una interfaz con Hibernate, pero usted no ser capaz de usar proxies para la captura por asociaciones perezosas (lazy association fetching), lo cual limitar sus opciones de ajuste de performance. Tambin se debera evitar declarar mtodos public final en las clases no finales. Si se quiere usar clases con mtodos pblicos finales, se debe inhabilitar el "proxying" explcitamente, especificando lazy="false".

4.1.4. Declare mtodos de acceso y "mutadores" (accessors, mutators) para los campos persistentes.
Cat declara mtodos de acceso para todos sus campos persistentes. Muchos otras herramientas de ORM persisten directamente sus variables de instancia. Nosotros creemos que es mejor proveer un nivel de aislamiento entre el esquema relacional y la estructura interna de datos de la clase. Por defecto, Hibernate persiste propiedades del tipo JavaBean, y reconoce nombres de mtodo de la forma getAlgo, isAlgo y setAlgo. Si es necesario, usted puede revertir esto, y permitir el acceso directo, para propiedades especficas,

No se necesita que las propiedaes sean declaradas como pblicas. Hibernate puede persistir una propiedad con un par get/set que tenga acceso por defecto (package) o privado.

4.2. Implementar herencia


Una subclase tambin debe cumplir con la primera y la segunda regla. Hereda su identificador de la superclase Cat.
package eg; public class DomesticCat extends Cat { private String name; public String getName() { return name; } protected void setName(String name) { this.name=name; } }

4.3. Implementar equals() y hashCode()


Usted debe reemplazar (override) los mtodos equals() y hashCode() si: planea poner instacias de clases persistentes en un Set (lo cual es la manera recomendada de representar cualquier asociacin con un lado "muchos"), y planea usar recuperacin (reattachment) de instancias desprendidas Hibernate garantiza la equivalencia de la identidad persistente (el registro de base de datos) y la identidad de Java, slo dentro del alcance de una sesin en particular. As que, tan pronto como mezclamos instancias que hayan sido obtenidas de distintas sesiones, debemos implementar equals() y hashCode() si deseamos tener una semntca con sentido para los Sets. La manera ms obvia es implementar equals()/hashCode() comparando el valor identificador de ambos objetos. Si el valor es el mismo, ambos deben ser el mismo registro de la base de datos, siendo por lo tanto iguales (si ambos son agregados al Set., slo tendremos un elemento en el Set.). Desafortunadamente, no podemos utilizar ese enfoque con los identificadores generados! Hibernate slo asignar identificadores los objetos que hayan sido creados, y una instancia que haya sido recientemente creada an no tiene ningn identificador! Ms an, si una de estas instancias, sin grabar, est dentro de un Set., grabarla le va a asignar un identificador, y sus valores de equals() y hashCode() (que estaran

42 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

basados en el identificador) cambiaran, rompiendo el contrato del Set. Vea el sitio de web de Hibernate para una discusin completa de este problema. Note que esto no es un problema de Hibernate, sino parte de la semntica normal de Java en lo que respecta a la igualdad e identidad de los objetos. Nosotro recomendamos implementar equals() y hashCode() utilizando una igualdad "por clave de negocio". Esto quiere decir, que estos mtodos comparen solamente propiedades que formen la clave de negocio, una clave que identificara a nuestro objeto en el mundo real (una clave candidata natural).
public class Cat { ... public boolean equals(Object other) { if (this == other) return true; if ( !(other instanceof Cat) ) return false; final Cat cat = (Cat) other; if ( !cat.getLitterId().equals( getLitterId() ) ) return false; if ( !cat.getMother().equals( getMother() ) ) return false; return true; } public int hashCode() { int result; result = getMother().hashCode(); result = 29 * result + getLitterId(); return result; } }

Note que la clave de negocio no necesita ser tan slida como una clave primaria de la base de datos. (vea Seccin 11.1.3, Considerar la identidad de un objeto). Propiedades que sean nicas o inmutables, usualmente son buenas candidatas a "clave de negocio".

4.4. Modelos dinmicos


Advierta que las siguientes caractersticas se consideran experimentales, y pueden cambiar en el futuro cercano Las entidades persistentes no tienen que ser representadas, en tiempo de ejecucin, necesariamente, com clases POJO u objetos JavaBean. Hibernate tambin soporta modelos dinmicos (usando Maps de Maps en tiempo de ejecucin), y la representacin de entidades como rboles DOM4J. Con este enfoque, no se escriben clases, simplemente archivos de mapeo. Por defecto, Hibernate trabaja en el modo POJO normal. Se puede configurar un modo de representacin de entidad por defecto para una fbrica de sesiones en particular, usando la opcin de configuracin default_entity_mode (vea Tabla 3.3, Propiedades de Configuracin de Hibernate. Los ejemplos siguientes demuestran la representacin usando mapas. Primero, en el archicvo de mapeo, se debe declara un entity-name en lugar de (o adems de) el nombre de la clase:
<hibernate-mapping> <class entity-name="Customer"> <id name="id" type="long" column="ID"> <generator class="sequence"/> </id> <property name="name" column="NAME" type="string"/> <property name="address" column="ADDRESS" type="string"/> <many-to-one name="organization" column="ORGANIZATION_ID" class="Organization"/> <bag name="orders" inverse="true" lazy="false" cascade="all"> <key column="CUSTOMER_ID"/> <one-to-many class="Order"/> </bag>

43 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

</class>

</hibernate-mapping>

Note que, incluso si las asociaciones son declaradas usando nombres de clases de destino, el tipo de destino de una asociacin tambin puede ser una entidad dinmica en lugar de un POJO. Despus de configurar el modo de entidad por defecto a dynamic-map para esta SessionFactory, podemos trabajar con "mapas de mapas" en tiempo de ejecucin.
Session s = openSession(); Transaction tx = s.beginTransaction(); Session s = openSession(); // Crear un cliente Map david = new HashMap(); david.put("name", "David"); // Crear una organizacin Map foobar = new HashMap(); foobar.put("name", "Foobar Inc."); // Vincular a ambos david.put("organization", foobar); // Grabar a ambos s.save("Customer", david); s.save("Organization", foobar); tx.commit(); s.close();

La ventaja de un mapeo dinmico es acelerar el tiempo de entrega, para prototipos, sin la necesidad de implementar clases de entidades. De todos modos, se pierde el chequeo de tipos en tiempo de compilacin, y esto muy probablemente causar varias excepciones en tiempo de ejecucin. Gracias al mapeo de Hibernate, el esquema de base de datos puede ser fcilmente normalizado y saneado, permitiendo agregar una implementacin apropiada de modelo de dominio encima, ms adelante. Los modos de representacin de entidad tambin pueden ser configurados por sesin:
Session dynamicSession = pojoSession.getSession(EntityMode.MAP); // Crea un cliente Map david = new HashMap(); david.put("name", "David"); dynamicSession.save("Customer", david); ... dynamicSession.flush(); dynamicSession.close() ... // Contina con la sesin "POJO"

Dese cuenta por favor de que el llamado a getSession() usando un EntityMode determinado, es cosa de la API de Session API, no de SessionFactory. De esta manera, la nueva sesin comparte la misma conexin JDBC subyacente, y otra informacin de contexto. Esto vuelve innecesario invocar flush() y close() en la sesin secundaria, y le deja el manejo de transacciones y conexiones a unidad de trabajo primaria. Se puede encontrar ms informacin sobre las capacidades de representacin con XML en Captulo 18, Mapeo XML.

4.5. T-uplizadores
org.hibernate.tuple.Tuplizer, y sus sub-interfaces, son los encargados de manejar una representacin en particular de un fragmento de datos, dado el org.hibernate.EntityMode de dicha representacin. Si un determinado fragmento de

datos se concibe como una estructura de datos, entonces un t-uplizador es lo que sabe cmo crear dicha estructura. Por ejemplo, para el modo de entidad "POJO", el t-uplizador correspondiente sabe cmo crear el POJO mediante su constructor, y cmo acceder a las propiedades de POJO usando los mtodos de acceso. Hay dos t-uplizadores de alto nivel, representados por las interfaces org.hibernate.tuple.entity.EntityTuplizer y

44 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

org.hibernate.tuple.component.ComponentTuplizer.

Los EntityTuplizers see encargan de manejar los "contratos" recin descritos para las entidades, mientras que los ComponentTuplizers hacen lo propio para los componentes.

El usuario puede, asimismo, insertar sus propios t-uplizadores. Tal vez usted desee que par el modo de entidad "dynamic-map" se utilice una implementacin de java.util.Map que no sea java.util.HashMap, o tal vez usted necesita que se utilice una estrategia de generacin de proxies distinta de la que viene de fbrica. Las definiciones de t-uplizer van adjuntas a la entidad o mapeo de componentes que estn destinadas a manejar. Volviendo al ejemplo de la entidad "cliente" (customer).
<hibernate-mapping> <class entity-name="Customer"> <!-Reemplaza el t-uplizer de modo de entidad dynamic-map por el de entity-mode --> <tuplizer entity-mode="dynamic-map" class="CustomMapTuplizerImpl"/> <id name="id" type="long" column="ID"> <generator class="sequence"/> </id> <!-- otras propiedades--> ... </class> </hibernate-mapping>

public class CustomMapTuplizerImpl extends org.hibernate.tuple.entity.DynamicMapEntityTuplizer { // suplanta al mtodo buildInstantiator() para "enchufar" nuestro mapeo hecho a medida ... protected final Instantiator buildInstantiator(org.hibernate.mapping.PersistentClass mappingInf return new CustomMapInstantiator( mappingInfo ); } //suplanta a generateMap() para devolver nuestro map hecho a medida private static final class CustomMapInstantiator extends org.hibernate.tuple.DynamicMapInstanti protected final Map generateMap() { return new CustomMap(); } } }

4.6. Extensiones
A HACER: documentar el framework de extensiones de usuario y paquetes proxy.

Captulo 5. Mapeo O/R bsico 5.1. Declaracin del mapeo


Los mapeos objeto/relacionales generalmente se definen en un documento XML. El documento de mapeo ha sido diseado para ser legible y editable a mano. El lenguaje de mapeo es "Javacntrico", lo cual significa que los mapeos se construyen en torno a declaraciones de clases persistentes, no de tablas. Note que, aunque muchos usuarios de Hibernate eligen escribir el XML a mano, existe un buen nmero de herramientas para generar el documento de mapeo, como: XDoclet, Middlegen y AndroMDA. Comencemos con un mapeo de ejemplo:
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

45 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

<hibernate-mapping package="eg"> <class name="Cat" table="cats" discriminator-value="C"> <id name="id"> <generator class="native"/> </id> <discriminator column="subclass" type="character"/> <property name="weight"/> <property name="birthdate" type="date" not-null="true" update="false"/> <property name="color" type="eg.types.ColorUserType" not-null="true" update="false" <property name="sex" not-null="true" update="false"/> <property name="litterId" column="litterId" update="false"/> <many-to-one name="mother" column="mother_id" update="false"/> <set name="kittens" inverse="true" order-by="litter_id"> <key column="mother_id"/> <one-to-many class="Cat"/> </set> <subclass name="DomesticCat" discriminator-value="D"> <property name="name" type="string"/> </subclass> </class> <class name="Dog"> <!-- ac podra ir un mapeo para Perro --> </class> </hibernate-mapping>

(N.del T): "eg" son las siglas de "exempli gratia", una locucin latina que en ingls hace las veces de "por ejemplo". A lo largo de esta documentacin, "eg" se usa como el paquete por defecto para los ejemplos de cdigo. Ahora discutiremos el contenido del documente de mapeo. Slo describiremos los elementos y atributos del documento que son usados por Hibernate en tiempo de ejecucin. El documento de mapeo tambin contiene algunos atributos optativos adicionales, y elementos que afectan los esquemas de BD exportados por herramientas de exportacin de esquemas (por ejemplo, el atributo not-null).

5.1.1. El Doctype o "tipo de documento XML"


Todos los mapeos XML deberan declarar el doctype que se muestra. La DTD real puede ser encontrada en la URL mencionada, en el directorio hibernate-x.x.x/src/org/hibernate o en hibernate3.jar. Hibernate siempre buscar la DTD primero en el classpath. Si experimenta problemas al buscar la DTD debido a su conexin de Internet, compare su declaracin de DTD contra el contenido de su classpath.

5.1.1.1. EntityResolver
Como se mencion anteriormente, Hibernate primero intentar resolver la DTD en su classpath. La manera en que lo hace, es registrando una implementacin personalizada de org.xml.sax.EntityResolver con el SAXReader que usa para leer los archivos xml. Este EntityResolver perosnalizado reconoce dos espacios de nombre de systemId diferentes. un "espacio de nombre" (namespace) de Hibernate es reconocido siempre que el resolver encuentra un systemId qie comience con http://hibernate.sourceforge.net/; el resolver intenta resolver estas entidades mediante el classloader que haya cargado las clases de Hibernate. un espacia de nombre de usuario se reconoce siempre que el resolver encuentra un systemId que use un protocolo de URL classpath://; el resolver intentar resolver esas entidades a travs de (1) el classloader del contexto de thread actual, y (2), el classloader que haya cargado las clases de Hibernate. Un ejemplo de utilizacin de un espacio de nombre (namespace) hecho a medida:

46 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd" [ <!ENTITY types SYSTEM "classpath://your/domain/types.xml"> ]> <hibernate-mapping package="your.domain"> <class name="MyEntity"> <id name="id" type="my-custom-id-type"> ... </id> <class> &types; </hibernate-mapping>

En donde types.xml es un recurso en el paquete your.domain y contiene una definicin de tipo a medida typedef.

5.1.2. hibernate-mapping
Este elemento tiene varios atributos optativos. Los atributos schema y catalog especifican que las tablas a las que este mapeo se refiere pertenecen al esquema o catlogo indicado. Si se especifican, los nombres de tabla sern calificados con el esquema y/o catlogo dados. Si no estn presentes, los nombres de tabla no sern calificados. El atributo defaultcascade especifica qu estilo de propagacin en cascada debera asumirse para las propiedades y colecciones que no especifiquen un atributo cascade. El atributo auto-import nos permite, por defecto, usar un nombre de clase no calificado en el lenguaje de consultas.
<hibernate-mapping schema="schemaName" catalog="catalogName" default-cascade="cascade_style" default-access="field|property|ClassName" default-lazy="true|false" auto-import="true|false" package="package.name" />

(1) (2) (3) (4) (5) (6) (7)

(1)
schema (optativo): El nombre

de un esquema de BD

(2)
catalog

(optativo): El nombre de un catlogo de BD

(3)
default-cascade (optativo - por

defecto, none): El estilo por defecto de propagacin en cascada

(4) defecto, property): La estrategia que Hibernate debera usar para acceder a todas las propiedades. Puede ser una implementacn personalizada de PropertyAccessor. (5)
default-lazy (optativo - por defecto, true): El valor por defecto para los atributos lazy no especificados de clases y colecciones. default-access (optativo - por

(6)
auto-import

(optativo - por defecto true): Especifica si se puede usar nombres de clase no calificados (de clases en el mapeo) el en lenguaje de consultas.

(7)
package (optativo): Especifica un prefijo de paquete a ser asumido, para las clases no calificadas en el documento de mapeo.

47 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

Si usted tiene dos clases persistentes cuyo nombre (no calificado) es el mismo, debera configurar auto-import="false". Hibernate lanzar una excepcin si usted le intenta asignar dos clases al mismo nombre "imported". Note que el elemento hibernate-mapping le permite anidar los mapeos de varias clases persistentes, como se muestra anteriormente. Sin embargo, mapear slo una clase persistente (o jerarqua de clases) por archivo de mapeo es una costumbre ms establecida (y lo que algunas herramientas esperan). Por ejemplo, Cat.hbm.xml, Dog.hbm.xml, o, si se usa herencia, Animal.hbm.xml.

5.1.3. class
Se puede declarar una clase persistente usando el elemento class.
<class name="ClassName" table="tableName" discriminator-value="discriminator_value" mutable="true|false" schema="owner" catalog="catalog" proxy="ProxyInterface" dynamic-update="true|false" dynamic-insert="true|false" select-before-update="true|false" polymorphism="implicit|explicit" where="arbitrary sql where condition" persister="PersisterClass" batch-size="N" optimistic-lock="none|version|dirty|all" lazy="true|false" entity-name="EntityName" check="arbitrary sql check condition" rowid="rowid" subselect="SQL expression" abstract="true|false" node="element-name" /> (1) (2) (3) (4) (5) (6) (7) (8) (9) (10) (11) (12) (13) (14) (15) (16) (17) (18) (19) (20) (21)

(1)
name (optativo): El nombre

(totalmente calificado) de la clase (o interfaz) persistente de Java. Si este atributo est ausente, se asume que no se trata de una entidad POJO.

(2)
table (optativo

- por defecto el nombre no calificado de la clase): El nombre de su tabla en la base de datos

(3)
discriminator-value (optativo

- por defecto, el nombre de la clase): Un valor que distingue entre subclases individuales, usado para comportamiento polimrfico. null y not null tambin son valores aceptables.

(4)
mutable

(optativo, por defecto, true): Especifica si las instancias de esta clase son o no mutables.

(5)
schema (optativo): Suplanta

al nombre de esquema especificado por el elemento <hibernate-mapping> raz.

(6)
catalog

(optativo): Suplanta al nombre de catlogo especificado por el elemento <hibernate-mapping> raz.

(7)
proxy (optativo): Especifica

una interfaz a utilizar para los proxies de inicializacin perezosa. Se puede especificar

el nombre de la clase misma.

48 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

(8)
dynamic-update (optativo, por defecto false): Especifica que los comandos SQL UPDATE deberan ser generados en tiempo de ejecucin, y contener slo aqullas comlumnas cuyos valores hayan cambiado.

(9)
dynamic-insert (optativo, por defecto, false): Especifica que se deberan generar comandos SQL INSERT en tiempo de ejecucin, conteniendo slo las columnas cuyos valores son no nulos.

(10)
select-before-update (optativo, por defecto false): Especifica que Hibernate nunca debera ejecutar un UPDATE SQL a menos que est seguro de que en realidad se est modificando algn objeto. En algunos casos (en realidad, slo cuando un objeto transitorio ha sido asociado con una nueva sesin usando update()), esto significa que Hibernate ejecutar un comando SQLSELECT adicional, para determinar si un en realidad un UPDATE es

necesario. (11)
polymorphism (optativo,

por defecto, implicit): Determina si se usa polimorfismo explcito o implcito.

(12)
where (optativo)

especifica una condicin SQL WHERE arbitraria a ser usada cuando se seleccionen objetos de esta

clase. (13)
persister

(optativo): Especifica un ClassPersister hecho a medida.

(14)
batch-size

(optativo, por defecto, 1) especifica un "tamao de lote" para capturar instancias de esta clase por identificador.

(15)
optimistic-lock (optativo, por

defecto, version): Determina la estrategia de "locking" optimista.

(16)
lazy (optativo): La

captura haragana puede ser completamente inhabilitada espefificando lazy="false".

(17)
entity-name (optativo, por defecto, el nombre de la clase): Hibernate3 permite que una clase sea mapeada muchas veces (potencialmente, a distintas tablas), y permite mapeos de entidades qie estn representados por Maps a nivel de Java, En estos casos, se debera proveer un nombre arbitrario explcito para la entidad. Vea Seccin 4.4, Modelos dinmicos y Captulo 18, Mapeo XML for more information.

(18)
check (optativo): Una

expresin SQL arbitraria usada para generar una constraint tipo check multifila a usar durante la generacin automtica del esquema.

(19)
rowid (optativo): Hibernate

puede usar los vulgarmente llamados ROWIDs, en aquellas DB que lo soporten. Por ejemplo, en Oracle, Hibernate puede usar la columna adicional rowid para actualizar ms rapidamente, si usted configura esta opcin a rowid. Un ROWID es un detalle de implementacin, y representa la ubicacin fsica de una t-upla alamacenada.

(20)
subselect (optativo): Mapea una entidad inmutable y de slo-lectura a un subselect de la base de datos. Es til si se quiere tener una vista en lugar de una tabla, pero no se cuenta con una vista en la base de datos. Vea ms adelante para ms informacin.

(21)
abstract

(optativo): Usado para marcar superclases abstractas en jerarquas de <union-subclass>.

49 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

Es perfectamente aceptable que la clase persistente nombrada sea une interfaz. En ese caso, se debe declarar la clase implementadora usando el elemento <subclass>. Se puede persistir cualquier clase anidada (inner class) esttica. Se debera especificar el nombre de este tipo de clases usando la nomenclatura estndar, es decir com.Mi$ClaseInterna. Las clases inmutables (mutable="false") no pueden ser actualizadas o borradas por la aplicacin. Esto le permite a Hibernate realizar algunas optimizaciones menores. El atributo optativo proxy permite la inicializacin perezosa de instancias persistentes de la clase. Inicialmente, Hibernate devolver proxies CGLIB, que implementan la interfaz mencionada. El objeto persistente propiamente dicjo ser cargado cuando se invoque un mtodo del proxy. Vea "Inicializar colecciones y proxies" ms adelante. Polimorfismo implcito significa que cualquier consulta que nombre a una superclas o interfaz devolver instancias de la clase misma. Polimorfismo explcito significa que instancias de esta clase slo sern devueltas por consulta que nombren a esta clase, y que las consultas que nombren a esta clase devolvern slo instancias de subclases que hayan sido mapeados como <subclass> o <joined-subclass>. Para la mayora de los casos, el valor por defecto polymorphism="implicit", es lo ms apropiado. El polimorfismo explcito es til cuando hay dos clases diferentes mapeadas a la misma tabla (lo cual permite tener una clase "de peso ligero" que contenga un subconjunto de las columnas de la tabla). El atributo persister le permite personalizar la estrategia de persistencia usada para la clase. Por ejemplo, usted puede especificar su propia subclase de org.hibernate.persister.EntityPersister, o hasta puede proveer una implementacin completamente nueva de la interfaz org.hibernate.persister.ClassPersister que persista, por ejemplo, valindose de una llamada a un procedimiento almacenado de base de datos, o usando serializacin a archivos planos, o LDAP. Vea org.hibernate.test.CustomPersister para un ejemplo simple (de "persistencia" a una Hashtable). Note que las asignaciones de valores dynamic-update y dynamic-insert no son heredadas por la subclases, as que pueden ser especificadas en los elementos <subclass> o <joined-subclass>. Estos valores pueden incrementar la performance en algunos casos, pero reducirla en otros. selos con cuidado. El uso de select-before-update normalmente bajar la performance. Es muy til para evitar que un "update trigger" de la base de datos sea invocado innecesariamente si usted est revinculando todo un rbol de instancias desprendidas a una sesin. Si usted habilita dynamic-update, tendr las siguientes opciones de "locking" optimista
version verifica all

las columnas de versin/timestamp

verifica todas las columnas verifica las columnas que hayan cambiado, permitiendo algunas modificaciones concurrentes

dirty none

no usa "locking" optimista

Recomendamos muy fuertemente que se utilicen las columnas de versin/timestamp para locking optimista con Hibernate. sta es la estrategia ptima en lo que a performace se refiere, y es la nica estrategia que maneja correctamente las modificaciones que se hagan a instancias desprendidas (es decir, cuando se use Session.merge() ). Para un mapeo Hibernate, no hay diferencia entre una vista y una tabla de la base de datos. Como es de esperarse, esto es transparente a nivel de base de datos (note que algunas base de datos no soportan vistas correctamente, especialmente actualizaciones de stas). A veces usted quiere usar una vista, pero no puede crear una en la base de datos (por ejemplo, con un esquema heredado anticuado). En este caso, usted puede mapear una entidad inmutable y de slo-lectura a una expresin "subselect" de SQL.
<class name="Summary"> <subselect> select item.name, max(bid.amount), count(*) from item join bid on bid.item_id = item.id group by item.name </subselect> <synchronize table="item"/> <synchronize table="bid"/> <id name="name"/> ... </class>

50 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

Declara las tablas contra las cuales se ha de sincronizar esta entidad, asegurndose de que el auto-flush ocurra correctamente. y que las consultas efectuadas contra la entidad derivada no devuelvan datos vencidos. En el mapeo, <subselect> est disponible como atributo y como elemento anidado.

5.1.4. id
Las clases mapeadas deben declarar la columna de clave primaria de la tabla en la base de datos. La mayora de las clases tambin tendrn una propiedad del estilo JabaBeans conteniendo el didentificador nico de una instancia determinada. El elemento <id> define el mapeo de esa propiedad a la columna de clave primaria.
<id name="propertyName" type="typename" column="column_name" unsaved-value="null|any|none|undefined|id_value" access="field|property|ClassName"> node="element-name|@attribute-name|element/@attribute|." <generator class="generatorClass"/> </id> (1) (2) (3) (4) (5)

(1)
name (optativo): El nombre

de la propiedad indentificadora.

(2)
type (optativo): Un nombre

que indica el tipo de Hibernate

(3)
column (optativo, por defecto,

el nombre de la propiedad): El nombre de la columna de la clave primaria

(4)
unsaved-value (optativo, por defecto, un valor "adecuado"): Una propiedad identficadora que indica que una instancia ha sido recientemente instanciada (no grabada), distinguindola de las instancias desprendidas que fueron grabadas o cargadas en una sesin previa.

(5)
access (optativo, por defecto, property): La

estrategia que Hibernate debera usar para acceder al valor de la

propiedad.

Si falta el atributo name , se asume que la clase no posee propiedad indentificadora. El atributo unsaved-value casi nunca se usa en Hibernate3. Hay una declaracin alternativa de <composite-id>, para permitur el acceso a datos de formato anticuado, con clave compuesta. Desaconsejamos su uso en cualquier otro caso.

5.1.4.1. Generator
El elemento opcional hijo <generator> nombra a la clase de Java que se usa para generar los identificadores nicos de la clase persistente. Si hace falta algn parmetro para inicializar la instancia del generador, se pasa usando el elemento <param>.
<id name="id" type="long" column="cat_id"> <generator class="org.hibernate.id.TableHiLoGenerator"> <param name="table">uid_table</param> <param name="column">next_hi_value_column</param> </generator> </id>

Todos los generadores implementan la interfaz org.hibernate.id.IdentifierGenerator. Es una interfaz muy simple;

51 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

algunas aplicaciones podran elegir proveer su propia implementacin a medida. De todos modos, Hibernate provee una variedad de implementaciones que ya vienen incluidas. Los siguientes son los apodos mnemnicos para estos generadores ya incluidos:
increment

genera identificadores de tipo long, short o int que son nicos solamente cuando ningn otro proceso est insertando datos en la misma tabla. No usar en un cluster.
identity

soporta "columnas de identidad" (identity) en DB2, MySQL, MS SQL Server, Sybase e HypersonicSQL. El identificador que se devuelve es de tipo long, short o int.
sequence

usa una secuencia (sequence) en DB2, PostgreSQL, Oracle, SAP DB, McKoi o un generador en Interbase. El identificador que se devuelve es de tipo long, short o int
hilo

usa un algoritmo hi/lo para generar identificadores de los tipos long, short o int eficientemente, dada una tabla y una columna (por defecto, hibernate_unique_key y next_hi respectivamente) como fuente de los valores "hi". El algorithmo hi/lo genera identificadores que son nicos slo para una base de datos en particular.
seqhilo

usa un algoritmo hi/lo para generar identificadores de los tipos long, short o int eficientemente, dada una secuencia (sequence) nombrada de base de datos.
uuid

usa un algoritmo UUID de 128 bits para generar identificadores de tipo string, nicos para toda una red (se usa la direccin de IP). El UUID es codificado como una cadena de 32 dgitos hexadecimales.
guid

usa una cadena GUID generada por la base de datos, en MS SQL Server y MySQL.
native

elije identity, sequence o hilo, dependiendo de las capacidades de la base de datos subyancente.
assigned

deja que sea la aplicacin la que asigne el identificador al objeto antes de que save() sea llamado. sta es la estrategia por defecto si no se especifica un elemento <generator>.
select

obtiene una clave primaria asignada por un trigger de la base de datos, seleccionando la fila por alguna clave nica y obteniendo el valor de clave primaria.
foreign

usa el identificador de algn otro objeto asociado. Normalmente se usa en conjuncin con una asocoacin <one-to-one> por clave primaria.
sequence-identity

una generacin de secuencias especializada que utiliza una sequencia de base de datos para la generacin del valor en s, pero lo combina con el mtodo de JDBC3 getGeneratedKeys para devolver el valor final, como parte del comando INSERT. Esta estrategia slo es soportada, que sepamos, por los drivers de Oracle 10g diseados para JDK1.4. Note que los comentarios en estos comandos estn inhabilitados, debido a un error en los drivers de Oracle.

52 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

5.1.4.2. El algoritmo hi/lo


Los generadores hilo y seqhilo proveen dos implementaciones alternativas del algoritmo hi/lo, un enfoque muy comn para generar identificadores. La primera implementacin requiere una tabla de base de datos especial que almacene el siguiente valor "hi" disponible. La segunda, usa una secuencia al estilo de Oracle (si esto se soporta).
<id name="id" type="long" column="cat_id"> <generator class="hilo"> <param name="table">hi_value</param> <param name="column">next_value</param> <param name="max_lo">100</param> </generator> </id> <id name="id" type="long" column="cat_id"> <generator class="seqhilo"> <param name="sequence">hi_value</param> <param name="max_lo">100</param> </generator> </id>

Desafortunadamente, usted no puede usar hilo cuando le provee su propia conexin (Connection) a Hibernate. Cuando Hibernate use una fuente de datos de un servidor de aplicaciones para obtener conexiones inscriptas en JTA, usted deber configurar adecuadamente la hibernate.transaction.manager_lookup_class.

5.1.4.3. El algoritmo UUID


El UUID (siglas en ingls de "identificador universal nico) contiene: la direccin de IP, el tiempo de comienzo de la JVM (al cuarto de segundo), la hora del sistema, y un valor contador que es nico a lo ancho de la JVM. Desde el cdigo Java no se puede obtener la direccin MAC o direcciones de memoria, as que esto es lo mejor que se puede lograr, sin usar JNI.

5.1.4.4. Columnas de indentidad y secuencias


Con las BD que soportan columnas de identidad (DB2, MySQL, Sybase, MS SQL), se puede usar la generacin de claves identity. Con las que soportan secuencias (DB2, Oracle, PostgreSQL, Interbase, McKoi, SAP DB) se puede usar el valor sequence. Ambas estrategias requieren el uso de 2 comandos SQL para insertar un objeto nuevo.
<id name="id" type="long" column="person_id"> <generator class="sequence"> <param name="sequence">person_id_sequence</param> </generator> </id> <id name="id" type="long" column="person_id" unsaved-value="0"> <generator class="identity"/> </id>

La estrategia native produce un desarrollo ms porttil entre distintas plataformas (cross-platform), ya que elige entre identity, sequence e hilo, dependiendo de las capadidades de la DB subyacente.

5.1.4.5. Identificadores asignados


Si desea que sea la aplicacin la que asigne los identificadores (en lugar de que Hibernate los genere), usted puede usar el "generador" assigned. Este generador especial usa el valor de identificador ya asignado a la propiedad indentificadora del objeto. Este generador se usa cuando la clave primaria es una clave natural en lugar de una clave sustituta (surrogate key). ste es el comportamiento por defecto, si no se especifica el elemento <generator>.

53 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

Elegir el generador assigned, hace que Hibernate use unsaved-value="undefined", forzndolo a determinar si una instancia es transitoria o desprendida, a menos que haya una propiedad "version" o "timestamp", o usted defina Interceptor.isUnsaved().

5.1.4.6. Claves primarias asignadas por triggers


Para esquemas de DB anticuados/heredados solamente (Hibernate no genera DDL con triggers).
<id name="id" type="long" column="person_id"> <generator class="select"> <param name="key">socialSecurityNumber</param> </generator> </id>

(N del T): el nmero de seguridad social o SSN es un nmero nico asignado por el Estado a cada persona en EE.UU. En el ejemplo precedente, hay un valor de propiedad nico llamado socialSecurityNumber, definido por la clase, como clave natural, y una clave primaria en la tabla llamada person_id, cuyo valor es generado por un trigger que seleciona dicho nmero.

5.1.5. Generadores de identificador mejorados


A partir de la versin 3.2.3, hay 2 nuevos generadores que representan un replanteo de 2 aspectos diferentes de la generacin de identificadores. El primer aspecto, es la portabilida de base de datos, el segundo es la optimizacin (no tener que consultar a la base de datos cad vez que se requiera un valor de identificador nuevo). Estos dos nuevos generadores (a partir de la versin 3.3.x) han sido concebidos con el objetivo de reemplazar a algunos de los generadores nombrados anteriormente De todos modos, siguen incluyndose en los lanzamientos actuales, y se puede hacer referencia a ellos via FQN. El primero de estos nuevos generadores es el org.hibernate.id.enhanced.SequenceStyleGenerator, el cual ha sido concebido como reemplazo del generador sequence, y como un generador con una portabilidad superior a native (porque native (generalmente) elije entre identity y sequence, las cuales tienen en general semnticas distintas, lo cual puede causar sutiles problemas aplicaciones que consideren portabilidad). org.hibernate.id.enhanced.SequenceStyleGenerator, sin embargo, consigue la portabilidad de una manera diferente. Elije entre usar una tabla o una secuencia en la base de datos para almacenar sus valores incrementados, dependiendo de las capacidades del dialecto que est siendo usado. La diferencia entre esto y native, es que el almacenamiento basado en tablas y el basado en secuencias tienen exactamente la misma semntica (de hecho, las secuencias son exactamente lo que Hibernate trata de emular con sus generadores badados en tablas). Este generador tiene varios parmetros de configuracin:
sequence_name (optativo, por defecto, hibernate_sequence): El nombre initial_value (optativo, por defecto, 1): El valor

de la secuencia (o tabla) a ser usada.

inicial a ser devuelto por la tabla/secuencia. En trminos de la creacin de la secuencia, esto es anlogo a la clusula tpica "STARTS WITH".

increment_size (optativo, por defecto, 1): El incremento usdo en

llamadas ulteriores a la tabla/secuencia. En trminos de la creacin de la secuencia, esto es anlogo a la clusula tpica "INCREMENT BY".

force_table_use (optativo, por defecto, false): Deberamos forzar el uso de una tabla como estructura de respaldo, incluso si el dialecto soporta secuencias? value_column (optativo, por defecto, next_val): Slo relevante para estructuras de tabla! El nombre de la columna en la tabla usada para almacenar el valor. optimizer (optativo, por

defecto, none): Vea Seccin 5.1.6, Optimizacin de los generadores de identificador

El segundo de estos nuevos generadores es org.hibernate.id.enhanced.TableGenerator, el cual ha sido primariamente concebido en reemplazo del generador table, (aunque, en realidad, funciona mucho ms como un org.hibernate.id.MultipleHiLoPerTableGenerator). Secundariamente, ha sido concebido como una reimplementacin de org.hibernate.id.MultipleHiLoPerTableGenerator que utiliza la nocin de optimizadores "enchufables" (pluggable). En esencia, este generador define una tabla que es capaz de contener mltiples valores de

54 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

incremento distintos, usando mltiples registros con claves diferentes. Este generador tiene varios parmetros de configuracin:
table_name (optativo, por value_column_name

defecto, hibernate_sequences): El nombre de la tabla a usar.

(optativo, por defecto, next_val): El nombre de la columna en la tabla, que ser usada para

contener el valor.
segment_column_name (optativo, por defecto, sequence_name): El nombre de la columna en la tabla que set usada para contener la "clave de segmento". Este es el valor que identifica de manera distintiva qu valor de incremento usar. segment_value (optativo, por defecto, default): El valor de "clave de segmento" del cual queremos extraer valores de incremento para este generador. segment_value_length (optativo, por defecto, 255): Usado para la generacinde esquemas; el tamao del campo de esta "clave de segmento". initial_value (optativo, por defecto, 1): El valor

inicial a ser devuelto por la tabla. por el cual las llamdas subsiguientes a la tabla deberan diferir.

increment_size (optativo, por defecto, 1): El valor optimizer (optativo, por

defecto, ): Vea Seccin 5.1.6, Optimizacin de los generadores de identficadores

5.1.6. Optimizacin de los generadores de identficador


Para los identificadores que almacenan valores en la base de datos, es ineficiente acudir a la base de datos cada una de las veces en que se necesita generar un nuevo valor de identificador. En lugar de ello, lo ideal es agrupar un buen nmero de ellos en la memoria, y solamente acudir a la base de datos cuando se ese grupo de valores se haya agotado. sta es la funcin de los "optimizadores enchufables". Por el momento slo los dos generadoeres mejorados (Seccin 5.1.5, Generadores mejorados de identificadores ) soportan esta nocin.
none (ste es, generalmente, el valor por defecto si no se especific ningn optimizador): Esto indica que no se efecte ninguna optimizacin, y que se acuda a la base de datos para todos y cada uno de los pedidos. hilo: aplica un algoritmo hi/lo en torno a los valores devueltos por la base de datos. Se espera que los valores de base de datos para este optmizador sean secuenciales. Los valores devueltos desde la estructura de base de datos para este optmizador indican el "nmero de grupo"; el increment_size (tamao del incremento) se multiplica por el valor en memoria para definir un grupo "hi value". pooled: como fue discutido para hilo, estos optimizadores intentan minimizar el nmero de viajes a la base de datos. Aqu, sin embargo, simplemente almacenamos en valor inicial para el "prximo grupo" en la estructura de base de datos, ms que un valor secuencial en combinacin con un algoritmo de agrupamiento en memoria.Aqu, increment_size se refiere a los valores que vienen de la base de datos.

5.1.7. composite-id
<composite-id name="propertyName" class="ClassName" mapped="true|false" access="field|property|ClassName"> node="element-name|." <key-property name="propertyName" type="typename" column="column_name"/> <key-many-to-one name="propertyName class="ClassName" column="column_name"/> ...... </composite-id>

En una tabla con clave compuesta, se puede mapear varias de sus propiedades como identificadores. El elemento <composite-id> acepta mapeos de propiedades <key-property> y mapeos como elementos hijos.
<composite-id> <key-property name="medicareNumber"/>

55 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

<key-property name="dependent"/> </composite-id>

Su clase persistente debe reemplazar equals() y hashCode() para implementar igualdad entre identificadores compuestos. Tambin debe implementar Serializable. Desafortunadamente, este abordaje de los identificadores significa que el objeto persistente es su propio identificador. No hay otro "puntero" al objeto que no sea el objeto mismo. Se debe instanciar el objeto persistente mismo, y poblarle sus propiedades identificadores antes de poder cargarlo en estado persistente asociado con una clave primaria. A este enfoque lo llamamos "identificador compuesto incrustado (embedded)", y lo desaconsejamos para cualquier aplicacin seria. El segundo abordaje es lo que llamamos "identificador compuesto mapeado", en donde las propiedades identificador usadas dentro del <composite-id> son duplicadas tanto en la clase persistente como en una clase identificadora separada.
<composite-id class="MedicareId" mapped="true"> <key-property name="medicareNumber"/> <key-property name="dependent"/> </composite-id>

(N.del.T): "Medicare" es el nombre en ingls del seguro estatal de salud en EE.UU. y otros pases. En este ejemplo, tanto la clase del identificador compuesto, MedicareId, como la clase de la entidad misma tienen propiedades llamadas medicareNumber y dependent. La clase identificadora debe reemplazar equals() y hashCode() e implementar Serializable. La desventaja de este abordaje es obvia: duplicacin de cdigo. Los siguientes atributos son usados para especificar un identificador compuesto mapeado:
mapped

(optativo, por defecto, false): indica que se usa un identificador mapeado compuesto, y que los mapeos contenidos de propiedades se refieren tanto a la clase entidad como a la clase del identificador compuesto.

class (optativo, pero requerido para un identificador compuesto mapeado): La clase usada como identificador compuesto.

Vamos a describir una tercera manera, an ms conveniente de enfocar el tema de los modificadores compuestos, en donde el identificador compuesto es implementado como una clase componente en Seccin 8.4, Componentes como identificadores compuestos. Los atributos descritos a continuacin se aplican slo a este enfoque alternativo:
name (optativo, pero obligatorio para este abordaje): Una propiedad de tipo "componente" que contiene el identificador compuesto (ver captulo 9). access

(optativo, por defecto, property): La estrategia que Hibernate debera usar para acceder al valor de las propiedades.

class (optativo, por defecto, el tipo de propiedad determinado por reflexin): La clase componente usada como identificador compuesto (ver la seccin siguiente).

Este tercer abordaje, un compoennte identificador, es el que recomendamos para casi todas las aplicaciones.

5.1.8. discriminator (discriminador)


El elemento <discriminator> se requiere para la persistencia polimrfica que use la estrategia de mapeo de "una tabla por cada jerarqua de clases" y declara una columna como el "discriminador" de la tabla. La columna "discriminador" contiene un valor rtulo, que le dice a la capa de persistencia qu clase debe instanciar para cada registro en particular. Slo un nmero restringido de tipos puede ser usado: string, character, integer, byte, short, boolean, yes_no, true_false.
<discriminator column="discriminator_column" type="discriminator_type" force="true|false" insert="true|false" formula="arbitrary sql expression" />

(1) (2) (3) (4) (5)

56 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

(1)
column (optativo, por defecto, class)

el nombre de la columna del discriminador

(2)
type (optativo, por defecto, string) un nombre

que indica el tipo de Hibernate

(3)
force (optativo, por defecto, false) "fuerza" a Hibernate a especificar valores permitidos de discriminador cuando captura todas las instancias de la clase raz.

(4)
insert (optativo, por defecto, true) asgnele false si su columna de discriminador tambn forma parte de un identificador compuesto mapeado (le dice a Hibernate que no incluya a esta columna en el INSERT).

(5)
formula (optativo) una expresin SQL arbitraria que se ejecuta cuando un tipo tiene que ser evaluado. Permite discriminacin basada en contenido.

Los verdaderos valores de la columna del discriminador son especificados por el atributo discriminator-value de los elementos <class> y <subclass>. El atributo force solamente es til si la tabla contiene valores de discriminador "adicionales" que no estn mapeados a una clase persistente. ste no es casi nunca el caso. Usando el atributo formula, se puede declarar una expresin SQL arbitraria que puede ser usada para evaluar el tipo de una fila.
<discriminator formula="case when CLASS_TYPE in ('a', 'b', 'c') then 0 else 1 end" type="integer"/>

5.1.9. version (optativo)


El elemento <version> element es optativo e indica que la tabla contiene datos con versin. Esto es particularmente til si se planea usar transacciones largas (vase ms abajo).
<version column="version_column" name="propertyName" type="typename" access="field|property|ClassName" unsaved-value="null|negative|undefined" generated="never|always" insert="true|false" node="element-name|@attribute-name|element/@attribute|." />

(1) (2) (3) (4) (5) (6) (7)

(1)
column (optativo, por defecto,

el nombre de la propiedad): El nombre de la columna que contiene el nmero de

versin. (2)
name: El nombre

de una propiedad de la clase persistente.

(3)
type (optativo, por defecto, integer): El tipo del nmero de

versin.

(4) long , integer , short , timestamp o calendar . de la Los nmeros de versin pueden ser deproperty los tipos de Hibernate access (optativo, por defecto, ): La estrategia que Hibernate debera usar para obtener el valor propiedad.

57 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

Una propiedad de versin o timestamp nunca debera ser nula para una instancia desprendida, de manera que Hibernate pueda identificar cualquier instancia con una versin o timestamp nulos como transitoria, sin importar qu otras estrategias de unsaved-value se hayan usado. Declarar una propiedad versin o timestamp como anulable es un forma fcil de evitar problemas con la revinculacin transitiva en Hibernate, especialmente til para quienes usen identificadores asignados o claves compuestas!

5.1.10. timestamp (optativo)


El elemento optativo <timestamp> indica que la tabla contiene datos marcados con fecha y hora. Esto apunta a ser una alternativa a asignar nmeros de versin. Las timestamps son, por naturaleza, una implementacin menos segura de "locking" optimista. De todos modos, la aplicacin podra usar timestamps de otras formas.
<timestamp column="timestamp_column" name="propertyName" access="field|property|ClassName" unsaved-value="null|undefined" source="vm|db" generated="never|always" node="element-name|@attribute-name|element/@attribute|." />

(1) (2) (3) (4) (5) (6)

(1)
column (optativo, por defecto,

the property name): el nombre de una columna que contiene la timestamp.

(2)
name: El nombre

de una propiedad estilo JavaBeans del tipo Date o Timestamp de la clase persistente.

(3)
access (optativo, por defecto, property): La

estrategia que Hibernate debera usar para acceder al valor de la

propiedad. (4) por defecto, null): Una propiedad de versin, que indica que una instancia ha sido recientemente instanciada (no grabada, "transitoria"), distinguindola de una instancia desprendida, que haya sido cargada o grabada por una sesin previa (undefined especifica que debera usarse el valor de la propiedad indentificadora). (5)
source (optativo, por defecto, vm): De dnde debera Hibernate obtener el valor de la timestamp? De la base de datos, o de la JVM actual? Las timestamps originadas en la base de datos son costosas, porque Hibernate debe consultar la base de datos para determinar el "prximo" valor, pero sern ms seguras en entornos de cluster. Note tambin, que no se sabe si todos los dialectos soportan esta obtencin de timestamps de la base de datos, mientras que otros pueden ser inseguros de usar en "locking", dada su falta de precisin (Oracle 8, por ejemplo). unsaved-value (optativo,

(6)
generated

(optativo, por defecto, never): Especifica que esta propiedad timestamp en realidad es generada por la base de datos. Vea la discusin de propiedades generadas.

Note que <timestamp> equivale a <version type="timestamp">. Y <timestamp source="db"> equivale a <version
type="dbtimestamp">

5.1.11. property
El elemento <property> declara una propiedad pesistente de la clase, estilo JavaBeans.
<property name="propertyName" column="column_name" type="typename"

(1) (2) (3)

58 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

update="true|false" insert="true|false" formula="arbitrary SQL expression" access="field|property|ClassName" lazy="true|false" unique="true|false" not-null="true|false" optimistic-lock="true|false" generated="never|insert|always" node="element-name|@attribute-name|element/@attribute|." index="index_name" unique_key="unique_key_id" length="L" precision="P" scale="S" />

(4) (4) (5) (6) (7) (8) (9) (10) (11)

(1)
name: el nombre

de la propiedad, com una letra minscula inicial.

(2)
column (optativo, por defecto, the property name): el nombre de la columna de la tabla en la base de datos mapeada. Tambin puede especificarse con elemento(s) <column> anidados.

(3)
type (optativo): un nombre

que indica el tipo de Hibernate.

(4)
update, insert (optativo, por defecto, true) : indica que las columnas mapeadas deben ser incluidas en los comandos SQL UPDATE y/o INSERT. Asignarles false a las dos permite una propiedad puramente "derivada",

cuyo

valor es inicializado solamente por alguna otra propieadad que se mapea a la(s) misma(s) columna(s), o por un trigger, u otra aplicacin. (5)
formula (optativo): una expresin SQL que define el valor de una propiedad computada. Las propiedades computadas no tienen un mapeo de columna propio.

(6)
access (optativo, por defecto, property): La

estrategia que Hibernate debera usar para acceder al valor de esta

propiedad. (7)
lazy (optativo, por defecto, false): Especifica que esta propiedad debera ser obtenida de manera haragana, cuando se acceda por primera vez a la variable de instancia (requiere implementacin bytecode en tiempo de ejecucin).

(8)
unique (optativo): Habilita la generacin del lenguaje de definicin de datos (DDL) para una constraint nica para las columnas. Tambin permite que esto sea apuntado por una property-ref.

(9)
not-null (optativo): Habilita la generacin del lenguaje de definicin de datos (DDL) para una constraint de nulabilidad para las columnas.

(10)
optimistic-lock (optativo, por

defecto, true): Especifica si las actualizaciones al valor de esta propiedad requieren o no un "lock" optimista. En otras palabras, determina si pueden ocurrir incrementos de versin cuando la propiedad est "sucia".

(11)
generated

(optativo, por defecto, never): Especifica que el valor de esta propiedad es en realidad generado por la

59 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

base de datos. Vea la discusin de propiedades generadas.

typename puede ser: El nombre de un tipo bsico de Hibernate (por ejemplo integer, string, character, date, timestamp, float, binary, serializable, object, blob). El nombre de una clase de Java con un tipo bsico por defecto (por ejemplo int, float, char, java.lang.String, java.util.Date, java.lang.Integer, java.sql.Clob). El nombre de una clase de Java serializable. El nombre de un tipo de Java hecho a medida (por ejemplo, com.mipaquete.MiTipoPersonalizado). Si no se especifica un tipo, Hibernate usar reflexin en la propiedad nombrada, para adivinar el tipo Hibernate correcto. Hibernate intentar interpretar el nombre de la clase devuelta por el mtodo "getter" de la propiedad, usando las reglas 2, 3 y 4, en ese orden. De todos modos, esto no siempre es suficiente. En algunos casos, an se necesita el atributo type (por ejemplo, para distinguir entre Hibernate.DATE e Hibernate.TIMESTAMP, o para especificar un tipo hecho a medida). El atributo access le permite controlar cmo Hibernate acceder a la propiedad en tiempo de ejecucin. Por defecto, Hibernate invocar al par get/set. Si usted especifica access="field", Hibernate saltear el par get/set y acceder al campo directamente, usando reflexin. Usted puede especificar su propia estrategia de acceso, nombrando una clase que implemente la interfaz org.hibernate.property.PropertyAccessor. Las propiedades derivadas son una caracterstica especialmente poderosa. Estas propiedades son de slo lectura, por definicin. Son computadas en el momento en que se cargan. Se declara dicha computacin como un comando SQL, que se traduce en una subconsulta SELECT en el cdigo SQL que carga la instancia.
<property name="totalPrice" formula="( SELECT SUM (li.quantity*p.price) FROM LineItem li, Product p WHERE li.productId = p.productId AND li.customerId = customerId AND li.orderNumber = orderNumber )"/>

Note que usted se puede referir a la tabla misma de la entidad, evitando usar el alias para una columna en particular (en el ejemplo, customerId). Tambin note que puede usar elementos <formula> anidados si no le gusta especificar el valor como un atributo.

5.1.12. many-to-one
Una asociacin comn con otra clase persistente se declara usando un elemento many-to-one element. El modelo relacional es una asociacin de-muchos-a-uno: la clave fornea en una tabla se refiera a la(s) columna(s) clave de la tabla de destino.
<many-to-one name="propertyName" column="column_name" class="ClassName" cascade="cascade_style" fetch="join|select" update="true|false" insert="true|false" property-ref="propertyNameFromAssociatedClass" access="field|property|ClassName" unique="true|false" not-null="true|false" optimistic-lock="true|false" lazy="proxy|no-proxy|false" not-found="ignore|exception" entity-name="EntityName" formula="arbitrary SQL expression" node="element-name|@attribute-name|element/@attribute|." embed-xml="true|false" index="index_name"

(1) (2) (3) (4) (5) (6) (6) (7) (8) (9) (10) (11) (12) (13) (14) (15)

60 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

unique_key="unique_key_id" foreign-key="foreign_key_name" />

(1)
name: El nombre

de la propiedad.

(2)
column (optativo): El nombre <column> anidados.

de la columna de clave fornea. Tambin puede ser especificada por elementos

(3)
class (optativo, por defecto,

el tipo de la propiedad, determinado por reflexin): El nombre de la clase asociada

(4)
cascade (optativo): Especifica qu operaciones sern propagadas en cascada desde el objeto padre hacia los objetos asociados.

(5)
fetch (optativo, por defecto, select): Elije

entre la captura (fetching) por outer-join y la captura por seleccin

secuencial. (6)
update, insert (optativo, por defecto, true) especifica que las columnas mapeadas deben incluirse en el los comandos SQL UPDATE y/o INSERT. Asignarles false permite una propiedad puramente "derivada", cuyo valor es

inicializado desde alguna otra propiedad, o desde un trigger, u otra aplicacin. (7)
property-ref: (optativo) El nombre de una propiedad de una clase asociada que est ligada a esta clave fornea. Si no se especifica, se usa la clave primaria de la clase asociada.

(8)
access (optativo, por defecto, property): La

estrategia que Hibernate debera usar para acceder al valor de la

propiedad. (9)
unique (optativo): Habilita la generacin de lenguaje de definicin de datos (DDL) para la creacin de una constraint nica para la columna de clave fornea. Tambin permite que sta sea el blanco referido por una property-ref. Esto hace que la "multiplicidad" de la asociacin sea, efectivamente, de-uno-a-uno.

(10)
not-null (optativo): Habilita la generacin de lenguaje de definicin de datos (DDL) para la creacin de una constraint de nulabilidad para las columnas de la clave fornea.

(11)
optimistic-lock (optativo, por

defecto, true): Especifica si las actualizaciones de esta propiedad requieren o no la adquisicin de un "lock" optimista. En otras palabras, determina si debera ocurrir un incremento de versin cuando esta propiedad est "sucia".

(12)
lazy (optativo, por defecto, proxy): Las asociaciones de extremo nico estn "proxied" por defecto. lazy="noproxy" especifica que el valor de la propiedad debe ser capturado en forma haragana, cuando se acceda a la variable de instancia por primera vez (requiere instrumentacin bytecode en tiempo de ejecucin). lazy="false"

especifica que la asociacin siempre ser capturada de manera ansiosa ("eager" fetching). (13)
not-found

(optativo, por defecto, exception): Especifica cmo sern manejadas las claves forneas que se refieran a filas ausentes. ignore tratar dicha fila ausente como si fuera una asociacin nula.

61 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

(14)
entity-name

(optativo): El nombre de entidad de la clase asociada.

(15)
formula

(optativo): una expresin SQL que define el valor de una clave fornea computada.

Asignarle cualquier valor que tenga sentido al atributo cascade que no sea none propagar ciertas operaciones al objeto asociado. Los valores que tienen sentido son las operaciones bsicas de Hibernate, persist, merge, delete, save-update, evict, replicate, lock, refresh, as como los valores especiales delete-orphan y all, y combinaciones de nombres de operacion separados por comas, por ejemploc ascade="persist,merge,evict" o cascade="all,delete-orphan". Vea la Seccin 10.11, Persistencia transitiva para una explicacin completa. Note que las asociaciones a un solo valor (de-muchos-a-uno y de-uno-a-uno) no soportan el borrado de hurfanos. Una declaracin many-to-one tpica se ve tan simple como esto:
<many-to-one name="product" class="Product" column="PRODUCT_ID"/>

El atributo property-ref debe ser usado solamente para datos heredados/anticuados en donde la clave fornea apunte a una clave nica de la tabla asociada que no es la clave primaria. ste es un modelo relacional feo. Por ejemplo, suponga que la clase Product class tiene un nmero de serie nico, que no es la clave primaria. (El atributo unique controla en Hibernate la generacin de DDL con la herramienta SchemaExport).
<property name="serialNumber" unique="true" type="string" column="SERIAL_NUMBER"/>

Entonces, el mapeo para OrderItem podra usar:


<many-to-one name="product" property-ref="serialNumber" column="PRODUCT_SERIAL_NUMBER"/>

De todos modos, esto se desaconseja. Si la clave nica referida comprende mltiples propiedades de la entidad asociada, usted debera mapear las propiedades referidas dentro de un elemento llamado <properties>. Si la clave nica referida es la propiedad de un componente, se puede especificar un "path de propiedades":
<many-to-one name="owner" property-ref="identity.ssn" column="OWNER_SSN"/>

5.1.13. one-to-one
Una asociacin de-uno-a-uno a otra clase persistente se declara usando el elemento one-to-one.
<one-to-one name="propertyName" class="ClassName" cascade="cascade_style" constrained="true|false" fetch="join|select" property-ref="propertyNameFromAssociatedClass" access="field|property|ClassName" formula="any SQL expression" lazy="proxy|no-proxy|false" entity-name="EntityName" node="element-name|@attribute-name|element/@attribute|." embed-xml="true|false" foreign-key="foreign_key_name" />

(1) (2) (3) (4) (5) (6) (7) (8) (9) (10)

(1)
name: El nombre

de la propiedad.

62 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

(2)
class (optativo, por defecto,

el tipo de la propiedad, determinado por reflexin): El nombre de la clase asociada.

(3)
cascade (optativo) especifica qu operaciones deben ser propagadas en cascada desde el objeto padre hacia el objeto asociado.

(4)
constrained (optativo) especifica que una constraint de clave fornea a la clave primaria de la tabla mapeada apunta a la tabla de la clase asociada. Esta opcin afecta el orden en que save() y delete() son propagadas en cascada, y determina si la asociacin puede generar "proxies" (tambin es usada por la herramienta de exportacin de esquema de base de datos).

(5)
fetch (optativo, por defecto, select): Elige

entre captura por outer-join y captura por seleccin secuencial.

(6) El nombre de una propiedad de la clase asociada que est asociada a la clave primaria de esta clase. Si no se especifica, se usa la clave primaria de la clase asociada. (7)
access (optativo, por defecto, property): La property-ref: (optativo)

estrategia que Hibernate debe usar para acceder al valor de la

propiedad. (8)
formula (optativo): Casi todas las asociaciones de-uno-a-uno se mapean a la clave primaria de la entidad a la que pertenecen, En el raro caso de que no sea as, se puede especificar alguna otra columna o expresin con la cual asociarla usando una frmula SQL. (vea org.hibernate.test.onetooneformula por un ejemplo).

(9)
lazy (optativo, por defecto, proxy): Por defecto, las asociaciones de extremo nico usan proxies. lazy="noproxy" especififica que la propuedad debe ser capturada en forma haragana cuando se accede a la variable de instancia por primera vez (requiere instrumentacin bytecode de tiempo de ejecucin). lazy="false" especifica

que asociacin ser siempre capturada de forma "ansiosa" (eager fetching). Note que si se usa constrained="false", usar proxies es imposible e Hibernate siempre capturar en forma ansiosa! (10)
entity-name

(optativo): El nombre de entidad de la clase asociada.

Hay dos variantes de asociacin de-uno-a-uno: asociaciones por clave primaria. asociaciones por clave fornea nica. Las asociaciones por clave primaria no necesitan una columna extra en la tabla; si dos filas estn relacionadas por esta asociacin, entonces las dos filas en las respectivas tablas comparten el mismo valor de clave primaria. As que si usted quiere que dos objetos estn relacionados por la misma asociacin de clave primaria, tiene que asegurarse de que se les asigne el mismo valor de identificador! Para una asociacin por clave primaria, agrguele los siguientes mapeos a Employee y Person, respectivamente.
<one-to-one name="person" class="Person"/> <one-to-one name="employee" class="Employee" constrained="true"/>

Ahora, debemos asegurarnos de que las claves primarias de las filas relacionadas en las tablas PERSON y EMPLOYEE son iguales. Usamos una estrategia especial de Hibernate para asegurarnos de que las claves primarias de filas relacionadas sean iguales: un a estrategia de generacin de identificador llamada foreign:

63 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

<class name="person" table="PERSON"> <id name="id" column="PERSON_ID"> <generator class="foreign"> <param name="property">employee</param> </generator> </id> ... <one-to-one name="employee" class="Employee" constrained="true"/> </class>

Entonces, a una instancia recientemente creada de Person se le asigna el mismo valor de clave primaria que a la instancia de Employee referida por la propiedad employee. Alternativamente, una clave fornea que apunte a una constraint nica de Employee a Person, puede expresarse como:
<many-to-one name="person" class="Person" column="PERSON_ID" unique="true"/>

Y esta asociacin puede ser convertida en bidireccional agregando lo siguiente al mapeo de Person:
<one-to-one name="employee" class="Employee" property-ref="person"/>

5.1.14. natural-id
<natural-id mutable="true|false"/> <property ... /> <many-to-one ... /> ...... </natural-id>

Aunque recomendamos el uso de clave sustitutas como claves primarias, an se deberan identificar claves naturales para todas las entidades. Una clave natural es una propiedad o combinacin de propiedades que sea nica y no nula. Si tambin es inmutable, mejor todava. Mapee las propiedades de la clave natural dentro del elemento <natural-id>, e Hibernate generar las constraints necesarias de unicidad y nulabilidad, y su mapeo quedar ms auto-documentado. Recomentamos fuertemente que implemente equals() y hashCode() para comparar las propiedades de la clave natural de la entidad. Este mapeo no debera usarse con entidades para las cuales la clave primaria es la clave natural.
mutable (optativo,

por defecto, false): Por defecto, propiedades identificador naturales que asume son inmutables

(constantes).

5.1.15. component, dynamic-component


El elemento <component> mapea propiedades de un objeto hijo a columnas de la tabla de la clase padre. Los componenes a su vez pueden declarar sus propias propiedades, componentes o colecciones. Vea "Componentes" a continuacin.
<component name="propertyName" class="className" insert="true|false" update="true|false" access="field|property|ClassName" lazy="true|false" optimistic-lock="true|false" unique="true|false" node="element-name|." > <property ...../> <many-to-one .... /> ........ </component>

(1) (2) (3) (4) (5) (6) (7) (8)

64 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

(1)
name: El nombre

de la propiedad

(2)
class (optativo, por defecto,

el tipo de la propiedad, determinado por reflexin): El nombre de la clase

componente (hija). (3)


insert: Aparecen las columnas mapeadas en los SQL INSERTs?

(4)
update: Aparence

las columnas mapeadas en los SQL UPDATEs?

(5)
access (optativo, por defecto, property): La

estrategia que Hibernate debera usar para acceder al valor de la

propiedad. (6)
lazy (optativo, por defecto, false): Especifica que este componente debera ser capturado en forma haragana (lazy fetching) cuando se acceda a la variable de instancia por primera vez (requiere implementacin bytecode en tiempo de ejecucin).

(7)
optimistic-lock (optativo, por

defecto, true): Especifica si las actualizaciones de este componente requieren o no la adquisicin de un "lock" optimista. En otras palabras, determina si debera haber un incremento de versin cuando la propiedad est "sucia"

(8)
unique (optativo, por defecto, false): Especifica

que existe una constraint de unicidad sobre todas las columnas

mapeadas del componente.

Las propiedades <property> hijas mapean propiedades de la clase hija a columnas de la tabla. El elemento <component> acepta un subelemento <parent> que mapea una propiedad del componente como una referencia que apunta de vuelta a la entidad contenedora. El elemento <dynamic-component> permite que un Map sea mapeado como componente, en donde el nombre de la propiedad se refiere a claves del mapa, vase Seccin 8.5, Componentes dinmicos.

5.1.16. properties
El elemento <properties> permite la definicin de un agrupamiento lgico, con un nombre, de algunas propiedades de una clase. La utilidad ms importante de este tipo de construccin, es que permite que una combinacin de propiedades sea el blanco de un property-ref. Tambin es una manera conveniente de definir una constraint de unicidad.
<properties name="logicalName" insert="true|false" update="true|false" optimistic-lock="true|false" unique="true|false" > <property ...../> <many-to-one .... /> ........ </properties>

(1) (2) (3) (4) (5)

(1)
name: El nombre

lgico del agrupamiento ( no es un nombre de propiedad real).

65 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

(2)
insert: Aparecen las propiedades mapeadas en los comandos INSERT?

(3)
update: Aparecen las propiedades mapeadas en los comandos UPDATE?

(4)
optimistic-lock (optativo, por

defecto, true): Especifica si las actualizaciones de esta propiedad requieren o no la adquisicin de un "lock" optimista. En otras palabras, determina si debera ocurrir un incremento de versin cuando esta propiedad est "sucia".

(5)
unique (optativo, por defecto, false): Especifica

que existe un constraint de unicidad sobre todas las columnas

mapeadas del componente.

Por ejemplo, si tenemos el siguiente mapeo de <properties>:


<class name="Person"> <id name="personNumber"/> ... <properties name="name" unique="true" update="false"> <property name="firstName"/> <property name="initial"/> <property name="lastName"/> </properties> </class>

Y entonces podemos tener una asociacin de datos al estilo anticuado, que se refiera a esta clave nica de la tabla Person table, en lugar de a la clave primaria.
<many-to-one name="person" class="Person" property-ref="name"> <column name="firstName"/> <column name="initial"/> <column name="lastName"/> </many-to-one>

Pero no recomendamos esto, excepto en el contexto de un mapeo a datos anticuados/heredados.

5.1.17. subclass
Finalmente, la persistencia polimrfica requiere la declaracn de cada subclase de la clase persistente raz. Para la estrategia de mapeo una-tabla-por-clase, se usa la declaracin <subclass>.
<subclass name="ClassName" discriminator-value="discriminator_value" proxy="ProxyInterface" lazy="true|false" dynamic-update="true|false" dynamic-insert="true|false" entity-name="EntityName" node="element-name" extends="SuperclassName"> <property .... /> ..... </subclass>

(1) (2) (3) (4)

(1) Cada subclase debera declara sus propias propiedades persistentes y subclases. Se asume que las propiedades <version> name: El nombre (enteramente calificado) de la subclase. e <id> sern heredadas de la clase raz. Cada subclase en la jerarqua debe definir un valor nico de discriminator-

66 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

value. Si no

es especificado ninguno, se usa el nomre enteramente calificado de la clase de Java.

Para informacin sobre el mapeo de herencias, vea Captulo 9, Mapeo de Herencia.

5.1.18. joined-subclass
Alternativamente, cada subclase puede ser mapeada a su propia tabla (la estrategia de mapeo "una-table-por-subclase"). El estado heredado se captura haciendo un "join" con la tabla de la superclase. Usamos el elemento <joined-subclass>.
<joined-subclass name="ClassName" table="tablename" proxy="ProxyInterface" lazy="true|false" dynamic-update="true|false" dynamic-insert="true|false" schema="schema" catalog="catalog" extends="SuperclassName" persister="ClassName" subselect="SQL expression" entity-name="EntityName" node="element-name"> <key .... > <property .... /> ..... </joined-subclass>

(1) (2) (3) (4)

(1)
name: El nombre

enteramente calificado de la subclase.

(2)
table: El nombre

de la tabla de la subclase.

(3)
proxy

(optativo): Especifica una clase o interfaz a usar para la inicilizacin haragana de proxies.

(4)
lazy

(optativo, por defecto, true): Asignar lazy="false" inhabilita el uso de captura haragana (lazy fetching).

Para esta estrategia de mapeo no se requiere ninguna columna discriminadora. Sin embargo, cada subclase debe declarar una columna de tabla que contenga al identificador de objeto, usando el elemento <key>. El mapeo del comienzo del captulo sera rescrito as:
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="eg"> <class name="Cat" table="CATS"> <id name="id" column="uid" type="long"> <generator class="hilo"/> </id> <property name="birthdate" type="date"/> <property name="color" not-null="true"/> <property name="sex" not-null="true"/> <property name="weight"/> <many-to-one name="mate"/> <set name="kittens"> <key column="MOTHER"/> <one-to-many class="Cat"/> </set> <joined-subclass name="DomesticCat" table="DOMESTIC_CATS"> <key column="CAT"/>

67 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

<property name="name" type="string"/> </joined-subclass> </class> <class name="eg.Dog"> <!-- ac podra ir el mapeo de Dog --> </class> </hibernate-mapping>

Para informacin sobre los mapeos de herencias, vea Captulo 9, Mapeo de Herencia.

5.1.19. union-subclass
Una tercera opcin es mapear a tablas slo las clases concretas de la jerarqua de herencias. (la estrategia de "una-tablapor-clase-concreta"), en la cual una tabla define todo el estado persustente de la clase, incluido el estado persistente. En Hibernate, no es absolutamente necesario mapear dichas jerarquas de herencia. Se puede, simplemente, mapear cada clase con una declaracn separada de <class>. De todos modos, si desea usar asociaciones polimrficas (por ejemplo, una asociacin a la superclase de su jeraqua), es necesario usar un mapeo con <union-subclass>.
<union-subclass name="ClassName" table="tablename" proxy="ProxyInterface" lazy="true|false" dynamic-update="true|false" dynamic-insert="true|false" schema="schema" catalog="catalog" extends="SuperclassName" abstract="true|false" persister="ClassName" subselect="SQL expression" entity-name="EntityName" node="element-name"> <property .... /> ..... </union-subclass>

(1) (2) (3) (4)

(1)
name: El nombre,

enteramente calificado, de la subclase.

(2)
table: El nombre

de la tabla de la subclase.

(3)
proxy (optativo): Especifica

una clase o interfaz a usar para la inicilizacin haragana de proxies.

(4)
lazy (optativo, por defecto, true): Especificar lazy="false" inhabilita

el uso de captura haragana (lazy

fetching).

Para esta estrategia de mapeo no se requiere una columna discriminadora. Para informacin sobre los mapeos de herencias, vea Captulo 9, Mapeo de Herencia.

5.1.20. join
Usando el elemento <join>, es posible mapear propiedades de una clase a varias tablas, cuando hay una relacion de-uno-a-uno entre dichas tablas.
<join

68 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

table="tablename" schema="owner" catalog="catalog" fetch="join|select" inverse="true|false" optional="true|false"> <key ... /> <property ... /> ... </join>

(1) (2) (3) (4) (5) (6)

(1)
table: El nombre

de la tabla asociada.

(2)
schema (optativo): Suplanta <hibernate-mapping>.

al nombre del esquema de base de datos especificado en el elemento raz

(3)
catalog (optativo): Suplanta <hibernate-mapping>.

al nombre del catlogo de base de datos especificado en el elemento raz

(4) le asigna el valor pr defecto join, Hibernate usar un INNER JOIN para capturar una asociacin definida por una clase en su superclase, y utilizar un OUTER JOIN para una asociacin definida por una subclase. Si se le asigna el valor select, entonces Hibernate usar una asociacin secuencial definida en una subclase, la cual slo ser emitida cuando ocurra que una fila represente una instancia de la subclase. Los INNER JOINS an sern usados para capturar asociaciones definidas por la clase y sus superclases. (5)
inverse fetch (optativo, por defecto, join): Si se

(optativo, por defecto, false): Si se habilita, Hibernate no intentar insertar o acualizar las propiedades definidas por esta asociacin.

(6)
optional

(optativo, por defecto, false): Si se habilita, Hibernate insertar una nueva fila slo si las propiedades definidas por esta asociacin son no nulas, y siempre usar un OUTER JOIN para capturar las propiedades.

Por ejemplo, la informacin de la direccin de una perosna puede ser mapeada en una tabla separada, al tiempo que se preserva la semntica para todas las propiedades.
<class name="Person" table="PERSON"> <id name="id" column="PERSON_ID">...</id> <join table="ADDRESS"> <key column="ADDRESS_ID"/> <property name="address"/> <property name="zip"/> <property name="country"/> </join> ...

Esta caracterstica es a menudo slo til para modelos de datos anticuados. Recomendamos que haya menos tablas que clases, y un modelo de dominio bien detallado. N.del T.: se les suele llamar "detallados" (en ingls "fine-grained") a los modelos con clases que contiengan otras clases como miembro, por ejemplo, una clase Direccin dentro de una clase Persona, en lugar de incluir los campos de la direccn (calle, nmero, etc) directamente en Persona. Aunque los campos de Direccin probablemente se terminen persistiendo en la misma tabla que los de Persona, se considera que una representacin jerrquica que use las clases Persona y Direccin es ms "detallada" que la simple tabla PERSONA subyacente

69 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

De todos modos, "join-table" es til para alternar entre distintas estrategias de mapeo en una misma jerarqua, como se explica ms adelante.

5.1.21. key
Hemos visto surgir el elemento <key> varias veces ya. Aparece cada vez que el mapeo de un elemento padre define una asociacin a una nueva tabla, que haga referencia a la clave primaria de la tabla original.
<key column="columnname" on-delete="noaction|cascade" property-ref="propertyName" not-null="true|false" update="true|false" unique="true|false" /> (1) (2) (3) (4) (5) (6)

(1)
column (optativo): El nombre <column> anidados.

de la columna de clave fornea. Esto tambin puede ser especficado por elementos

(2)
on-delete

(optativo, por defecto, noaction): Especifica si la constraint de clave fornea tiene habilidtado el borrado en cascada a niver de la base de datos.

(3)
property-ref (optativo): Especifica que la clave fornea se refiere a columnas que no son la clave primaria de la tabla original. (provisto para datos anticuados/heredados solamente).

(4)
not-null (optativo): Especifica que las columnas de la clave fornea no son anulables (lo cual se sobreentiende cuando la clave fornea es tambin parte de la clave primaria)

(5)
update (optativo): Especifica que la clave fornea nunca debera ser actualizada (lo cual se sobreentiende cuando la clave fornea es tambin parte de la clave primaria)

(6)
unique (optativo): Especifica que la clave fornea debera tener una constraint de unicidad (lo cual se sobreentiende cuando la clave fornea es tambin la clave primaria).

Recomendamos que, para sistemas en los cuales la performance de delete sea importante, toda las claves sean definidas con on-delete="cascade", e Hibernate generar una constraint ON CASCADE DELETE a nivel de la base de datos, en lugar de varios comandos DELETE individuales. Tenga presente que esta caracterstica saltea la estrategia usual de locking optimista para datos versionados. Los atributos not-null y update son tiles cuando se mapea una asociacin de-uno-a-muchos unidireccional. Si la mapea a una clave fornea no anulable, hay que declarar la columa clave usando <key not-null="true">.

5.1.22. elementos column y formula


Cualquier elemento de mapeo que acepte un atributo column aceptar, alternativamente, un subelemento <column>. De la misma manera, el elemento <formula> es una alternativa al atributo formula.
<column name="column_name" length="N" precision="N" scale="N" not-null="true|false"

70 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

unique="true|false" unique-key="multicolumn_unique_key_name" index="index_name" sql-type="sql_type_name" check="SQL expression" default="SQL expression"/> <formula>SQL expression</formula>

Los atributos column y formula pueden incluso ser combinados dentro de la mismo mapeo de propiedad o asociacin, para expresar, por ejemplo, codiciones de asociacin exticas.
<many-to-one name="homeAddress" class="Address" insert="false" update="false"> <column name="person_id" not-null="true" length="10"/> <formula>'MAILING'</formula> </many-to-one>

5.1.23. import
Supongamos que su aplicacin tiene dos clases persistenes con el mismo nombre, y usted no quiere especificar un nombre de clase enteramente calificado (con el paquete) en las consutas de Hibernate. Las clases pueden ser "importadas" explcitamente en lugar de tener que confiar en el auto-import="true". Usted puede incluso importar clases e interfaces que no estn mapeadas explcitamente.
<import class="java.lang.Object" rename="Universe"/> <import class="ClassName" rename="ShortName" /> (1) (2)

(1)
class: The

fully qualified class name of of any Java class.

(2)
rename (optativo,

por defecto, the unqualified class name): A name that may be used in the query language.

5.1.24. any
Hay un tipo ms de mapeo de propiedad: El elemento de mapeo <any> define una asociacin polimrfica a clases de mltiples tablas. Este tipo de mapeo siempre requiere ms de una columna. La primera columna contiene el tipo de la entidad asociada. Es imposible especificar una constraint de clave fornea para este tipo de asociaciones. Esto se debera usar slo en casos muy especiales (por ejemplo, logs de auditora, datos de sesin de usuario, etc). El atributo meta-type le permite a la aplicacin especificar un tipo hecho a medida, que mapear valores de columna en la base de datos a clases persistentes, las cuales tendrn propiedades indentificadoras del tipo identificado por id-type. Se debe especificar el mapeo desde los valores valores del meta-tipo a los nombres de las clases.
<any name="being" id-type="long" meta-type="string"> <meta-value value="TBL_ANIMAL" class="Animal"/> <meta-value value="TBL_HUMAN" class="Human"/> <meta-value value="TBL_ALIEN" class="Alien"/> <column name="table_name"/> <column name="id"/> </any> <any name="propertyName" id-type="idtypename" meta-type="metatypename" cascade="cascade_style" access="field|property|ClassName" (1) (2) (3) (4) (5)

71 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

optimistic-lock="true|false" > <meta-value ... /> <meta-value ... /> ..... <column .... /> <column .... /> ..... </any>

(6)

(1)
name: el nombre

de la propiedad.

(2)
id-type: el tipo del identificador.

(3)
meta-type

(optativo, por defecto, string): Cualquier tipo que sea permisible para mapear un discriminador.

(4)
cascade

(optativo, por defecto none): el estilo de propagacin en cascada

(5)
access (optativo, por defecto, property): La

estrategia que Hibernate debera usar para acceder al valor de la

propiedad. (6)
optimistic-lock (optativo, por

defecto, true): Especifica si las actualizaciones de esta propiedad requieren o no la adquisicin de un "lock" optimista. En otras palabras, determina si debera ocurrir un incremento de versin cuando esta propiedad est "sucia".

5.2. Tipos de Hibernate


5.2.1. Entidades y "value types"
Para comprender el comportamiento de varios objetos (a nivel del lenguaje Java) con respecto al servicio de persistencia, necesitamos clasificarlos en 2 grupos: Una entidad (en ingls, "entity") existe independientemente de que cualquier otro objeto tenga o no referencias a ella. Contraste esto con el modelo de Java normal, en donde un objeto sufre "garbage colection" en cuanto dejan de referirse a l. Las entidades deben ser grabadas y borradas explcitamente (excepto cuando los borrados o grabaciones en cascada se transmiten de padre a hijos). ste es un tipo distinto de manejo de objetos de datos (ODMG, por sus siglas en ingls), que consiste en la persistencia de objetos basada en la capacidad de acceder a ellos, lo cual corresponde ms ntimamente con cmo los objetos de una aplicacin son usados en sistemas grandes. Las entidades soportan referencias compartidas y circulares, y pueden ser versionadas. El estado persistente de una entidad consiste en referencias a otras entidades, y a instancias de lo que en Hibernate se denomina "value types" (tipos "valor"), Los "value types" son los tipos primitivos, las colecciones (el componente coleccin en s, no lo que est dentro de ellas), y ciertos objetos inmutables. Los "value types" no pueden ser grabados ni versionados independientemente, sino que son persistidos junto con la entidad que los contiene. No tienen "identidad" independiente, y por lo tanto no pueden ser compartidos entre dos o ms entidades, ni entre colecciones. Hasta ahora hemos usado el trmino "clase persistente" para referirnos a entidades. Lo seguiremos haciendo, pero, estrictamente hablando, sin embargo, un "componente" (en ingls, component) tambin es una clase, definida por el usuario, que es persistente. La diferencia es que estos "componentes" tienen la semntica de un "value type", no la de una entidad. Un "value type" puede ser, entonces, un tipo primitivo de la JDK, o una String, o un tipo definido por el usuario. Una clase definida por el usuario puede ser, a criterio del programador de la aplicacin, un "value type" o una entidad. En un modelo de dominio, ser una entidad en general implica que varios otros objetos compartirn referencias a ella, mientras que los "value types" simplemente forman parte de una nica clase, va composicin o agrupacin (en ingls, "composition" y "aggregation").

72 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

Retomaremos estos conceptos todo a lo largo de la documentacin. El desafo es mapear el sistema de tipos de Java (junto con la definicin del desarrollador de las entidades y "value types") a un sistema del tipo SQL/BD. El puente entre ambos sistemas es provisto por Hibernate. Para las entidades proveemos <class>, <subclass> y as sucesivamente. Para los "value types" usamos <property>, <component>, etc., normalmente con un atributo type. El valor de este atributo es uno de los tipos para mapeo de Hibernate. Hibernate trae varios mapeos (para los tipos estndar de la JDK) ya incluidos. Pero usted puede escribir sus propios tipos para mapeo e implementar sus propias estrategias de conversin, como veremos ms adelante. Todos los tipos que vienen ya incluidos en Hibernate, excepto las colecciones, soportan la semntica de nulo.

5.2.2. "Value types" bsicos


Los tipos de mapeo bsicos ya incluidos pueden ser someramente clasificados en:
integer, long, short, float, double, character, byte, boolean, yes_no, true_false

Mapeos de los respectivos tipos primitivos o "clases envoltorio" a valores de columna SQL (que dependen de la marca de la BD): boolean, yes_no y true_false son todas codificaciones alternativas de un boolean o un java.lang.Boolean de Java.
string

Un mapeo de tipo de java.lang.String a VARCHAR (o el VARCHAR2 de Oracle).


date, time, timestamp

Mapeos de tipo de java.util.Date y sus subclases a tipos SQL DATE, TIME y TIMESTAMP (o equivalentes).
calendar, calendar_date

Mapeos de tipo de java.util.Calendar a tipos SQL TIMESTAMP y DATE (o equivalente).


big_decimal, big_integer

Mapeos de tipo de java.math.BigDecimal y java.math.BigInteger a NUMERIC (e el NUMBER de Oracle).


locale, timezone, currency

Mapeos de tipo de java.util.Locale, java.util.TimeZone y java.util.Currency a VARCHAR (o el VARCHAR2 de Oracle). Las instancias de Locale y Currency son mapeadas a sus cdigos ISO. Las instancias de TimeZone son mapeadas a su ID.
class

Un mapeo de tipo java.lang.Class a VARCHAR (o la VARCHAR2 de Oracle). Una Class es mapeada con su nombre enteramente calificado.
binary

Mapea arrays de bytes a un tipo SQL binario apropiado.


text

Mapea cadenas largas de Java los tipos CLOB o TEXT de SQL.


serializable

Mapea tipos serializables de Java a un tipo SQL binario apropiado. Tambin se puede indicar el tipo de Hibernate serializable con el nombre de una clase o interfaz serializable de Java, que no sea por defecto un tipo bsico.
clob, blob

Mapeos de tipo para las clases JDBC java.sql.Clob y java.sql.Blob. Estos tipos pueden ser inconvenientes para algunas aplicaciones, dado que los objetos clob y blob no pueden ser reusados fuera de una transaccin. (Ms

73 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

an, el soporte de drivers es espordico e inconsistente).


imm_date, imm_time, imm_timestamp, imm_calendar, imm_calendar_date, imm_serializable, imm_binary

Mapeos de tipo para lo que normalmente se considera "tipos mutables de Java", en los que Hibernate adopta ciertas optimizaciones que son slo apropiadas para tipos inmutables de Java, y la aplicacin trata al objeto como inmutable. Por ejemplo: para una instancia mapeada como imm_timestamp, no se debera invocar Date.setTime(). Para cambiar el valor de la propiedad (y hacer que ese valor cambiado sea persistido), la aplicacin tiene que asignarle un nuevo objeto (no idntico) a la propiedad.
clob.

Los identificadores nicos de las entidades y colecciones pueden ser de cualquier tipo bsico excepto binary, blob y (Los identiicadores compuestos tambin estn permitidos, ver ms adelante).

Los "value types" bsicos tienen constantes Type definidas en org.hibernate.Hibernate. Por ejemplo, Hibernate.STRING representa el tipo string.

5.2.3. "Value types" hechos a medida


Para los programadores, es relativamente fcil crear sus propios "value types". Por ejemplo, usted podra querer persistir propiedades del tipo java.lang.BigInteger a columnas VARCHAR. Hibernate no trae un tipo ya incluido para esto. Pero los tipos a medida no solamente sirven para mapear una propiedad de Java (o un elemento coleccin) a una sola columna de una tabla. Por ejemplo, usted puede tener una propiedad Java con mtodos getNombre()/setNombre() de tipo java.lang.String que sea persistida varias columnas, como PRIMER_NOMBRE, INICIAL_DEL_SEGUNDO, APELLIDO. Para crear un tipo a medida, implemente org.hibernate.UserType o org.hibernate.CompositeUserType y declare propiedades usando el nombre enteramente calificado del tipo. Revise org.hibernate.test.DoubleStringType para comprobar el tipo de cosas que es posible hacer.
<property name="twoStrings" type="org.hibernate.test.DoubleStringType"> <column name="first_string"/> <column name="second_string"/> </property>

Note el uso de los elementos <column> para mapear una sola propiedad a mltiples columnas. Las interfaces CompositeUserType, EnhancedUserType, UserCollectionType, y UserVersionType poveen soporte para usuarios ms especializados. Incluso se le pueden proveer parmetros a un UserType en el archivo de mapeo. Para lograr esto, su UserType debe implementar la interfaz org.hibernate.usertype.ParameterizedType. Para proveerle parmetros a su tipo a medida, usted puede usar el elemento <type> en sus archivos de mapeo.
<property name="priority"> <type name="com.mycompany.usertypes.DefaultValueIntegerType"> <param name="default">0</param> </type> </property>

Ahora el UserType puede aceptar valrores para el parmetro llamado default con el objeto Properties que le fue pasado. Si se usa un objeto UserType muy a menudo, sera til definirle un nombre corto. Esto se puede hacer usando el elemento <typedef>. Los "typedefs" le asignan un nombre a un tipo a medida, y pueden contener tambin una lista de parmetros por defecto si el tipo es parametrizado.
<typedef class="com.mycompany.usertypes.DefaultValueIntegerType" name="default_zero"> <param name="default">0</param> </typedef> <property name="priority" type="default_zero"/>

74 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

Tambin es posible sustituir (override) los parmetros provistos en un typedef, caso por caso, usando parmetros de tipo en el mapeo de propiedades. Aunque la rica variedad de tipos ya incluidos en Hibernate hace que slo en contadas ocasiones realmente se necesite usar un tipo a medida, se considera aconsejable crear tipos a medida para clases (no entidades) que ocurran frecuentemente en su aplicacin. Por ejemplo, una clase MonetaryAmount (suma de dinero) sera una buena candidata para un CompositeUserType, incluso si pudiere ser fcilmente mapeada como componente. Uno de los motivos para esto es abstraccin. Con un tipo a medida como ste, sus documentos de mapeo sern a prueba de posibles cambios en la forma en que los valores monetarios se representaren en el futuro.

5.3. Mapear una misma clase ms de una vez


Es posible proveer ms de un mapeo para una clase persistente en particular. En tal caso, se debe proveer un nombre de entidad para desambigar entre instancias de las dos entidades mapeadas. (Por defecto, el nombre de la entidad es igual al nombre de la clase). Hibernate permite especificar el nombre de entidad al trabajar con objetos persistentes, al escribir consultas, o al mapear asociaciones a dicha entidad.
<class name="Contract" table="Contracts" entity-name="CurrentContract"> ... <set name="history" inverse="true" order-by="effectiveEndDate desc"> <key column="currentContractId"/> <one-to-many entity-name="HistoricalContract"/> </set> </class> <class name="Contract" table="ContractHistory" entity-name="HistoricalContract"> ... <many-to-one name="currentContract" column="currentContractId" entity-name="CurrentContract"/> </class>

Note cmo ahora las asociaciones son especificadas usando entity-name en lugar de class.

5.4. Identificadores de SQL entrecomillados


Se puede forzar a Hibernate a encerrar el identificador entre comillas, en el SQL generado, encerrando el nombre de tabla o de columna en signos de acento grave (`), en ingls, "backticks". Hibernate usar el entrecomillado adecuado para el dialecto SQL correspondiente (lo cual es usualmente comillas, pero para SQL Server son corchetes, y para MySQL, estos "backticks").
<class name="LineItem" table="`Line Item`"> <id name="id" column="`Item Id`"/><generator class="assigned"/></id> <property name="itemNumber" column="`Item #`"/> ... </class>

5.5. Alternativas de metadatos


XML no es para ualquiera, as que hay algunas otras alternativas para definir los metadatos del mapeo O/R en Hibernate.

5.5.1. Usar marcadores de XDoclet


Muchos usuarios e Hibernate prefieren incrustar la informacin de mapeo directamente en su cdigo fuente, usando las tags @hibernate.tags de XDoclet. No cubriremos esta estrategia aqu, dado que es estrictamente parte de XDoclet. De todos modos, incluimos el siguiente ejemplo de la clase Cat con mapeo XDoclet.
package eg; import java.util.Set; import java.util.Date; /** * @hibernate.class

75 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

* table="CATS" */ public class Cat { private Long id; // identifier private Date birthdate; private Cat mother; private Set kittens private Color color; private char sex; private float weight; /* * @hibernate.id * generator-class="native" * column="CAT_ID" */ public Long getId() { return id; } private void setId(Long id) { this.id=id; } /** * @hibernate.many-to-one * column="PARENT_ID" */ public Cat getMother() { return mother; } void setMother(Cat mother) { this.mother = mother; } /** * @hibernate.property * column="BIRTH_DATE" */ public Date getBirthdate() { return birthdate; } void setBirthdate(Date date) { birthdate = date; } /** * @hibernate.property * column="WEIGHT" */ public float getWeight() { return weight; } void setWeight(float weight) { this.weight = weight; } /** * @hibernate.property * column="COLOR" * not-null="true" */ public Color getColor() { return color; } void setColor(Color color) { this.color = color; } /** * @hibernate.set * inverse="true" * order-by="BIRTH_DATE" * @hibernate.collection-key * column="PARENT_ID" * @hibernate.collection-one-to-many */ public Set getKittens() { return kittens; } void setKittens(Set kittens) { this.kittens = kittens; }

76 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

// addKitten not needed by Hibernate public void addKitten(Cat kitten) { kittens.add(kitten); } /** * @hibernate.property * column="SEX" * not-null="true" * update="false" */ public char getSex() { return sex; } void setSex(char sex) { this.sex=sex; } }

Vea el sitio de web de Hibernate para ms ejemplos de XDoclet con Hibernate.

5.5.2. Usar anotaciones de JDK 5.0


La JDK 5.0 introdujo anotaciones al estilo XDoclet a nivel del lenguaje. Son de tipo comprobado (type-safe) y se verifican en tiempo de compilacin. Este mecanismo es ms poderoso que las anotaciones XDoclet, y mejor soportado por las herramientas grficas (IDE) como IntelluJ IDEA, muchas de las cuales proveen autocomplecin y resaltado de sintaxis para anotaciones de JDK 5.0. La nueva revisin de los EJB, (JSR-220), usa anotaciones como su principal mecanismo de metadatos para los Entity Beans. Hibernate3 implementa el EntityManager JSR-220 (la API de persistencia), hay soporte disponible para el mapeo de metadatos en el paquete de Annotataciones de Hibernate (Hibernate Annotations), como una descarga separada. Los metadatos que se soportan son tanto Hibernate3 como EJB3 (JSR-220). El siguiente es un ejemplo de un POJO anotado como Entity Bean EJB.
@Entity(access = AccessType.FIELD) public class Customer implements Serializable { @Id; Long id; String firstName; String lastName; Date birthday; @Transient Integer age; @Embedded private Address homeAddress; @OneToMany(cascade=CascadeType.ALL) @JoinColumn(name="CUSTOMER_ID") Set<Order> orders; // mtodos Getter/setter, y de negocio ... }

Note que el soporte para anotaciones JDK 5.0 (y JSR-220) todava es un trabajo en curso, incompleto. Por favor remtase al mdulo de Anotaciones de Hobernate para ms detales.

5.6. Propiedades generadas


Las propiedades generadas son propiedades cuyos valores son generados por la base de datos. En general, las aplicaciones Hibernate tienen que refrescar los objetos que contengan cualquier propiedad para la cual la base de datos est generando valores. Sin embargo, al marcar propiedades como "generadas" se deja que la aplicacin delegue esta responsabilidad en Hibernate. Esencialmente, cada vez que Hibernate emita un INSERT o UPDATE para una entidad que tenga propiedades generadas definidas, inmediatamente generar un SELECT para capturar los valores generados. Por aadidura, las propiedades marcadas como generadas debe ser no insertables y e inmodifocables. Slo las versiones, las timestamps, y las propiedades simples pueden ser marcadas como generadas.

77 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

never (el valor por defecto) insert - declara

significa que el valor de la propiedad dada nunca es generada por la base de datos.

que el valor de la propiedad dada es generado al ocurrir un INSERT, pero no es regenerado en los UPDATEs subsiguientes. Cosas como "fecha de creacin" entraran en esta categora. Note que, aunque las propiedades version y timestamp pueden ser marcadas como generadas, esta opcin no est disponible para ellas.
always - declara

que el valor de esta propiedad es generado tanto al insertar como al modificar.

5.7. Objetos auxiliares de base de datos


Permite la ejecucin de comandos CREATE y DROP arbitrarios para objetos de base de datos, en conjuncin con las herramientas de evolucin de esquema de base de datos con las que cuenta Hibernate, para poveer la capacidad de definir un esquema totalmente dentro de los archivos de mapeo de Hibernate. Aunque fue designada especficamente para eliminar (DROP) cosas como triggers o procedimientos almacenados, en realidad cualquier comando SQL que pueda ser ejecutado mediante un java.sql.Statement.execute() es vlido aqu: ALTERs, INSERTs, etc). Esencialmente, hay dos maneras de definir objetos de base de datos auxiliares: La primera es listar explcitamente los comandos CREATE y DROP en el archivo de mapeo:
<hibernate-mapping> ... <database-object> <create>CREATE TRIGGER my_trigger ...</create> <drop>DROP TRIGGER my_trigger</drop> </database-object> </hibernate-mapping>

La segunda es proveer una clase a medida, la cual sepa cmo construir los comandos CREATE y DROP. Esta clase a medida debe implementar la interfaz org.hibernate.mapping.AuxiliaryDatabaseObject.
<hibernate-mapping> ... <database-object> <definition class="MyTriggerDefinition"/> </database-object> </hibernate-mapping>

Adicionalmente, a estos objetos de base de datos se les puede definir un alcance, de manera que se apliquen slo cuando se usen ciertos dialectos determninados.
<hibernate-mapping> ... <database-object> <definition class="MyTriggerDefinition"/> <dialect-scope name="org.hibernate.dialect.Oracle9Dialect"/> <dialect-scope name="org.hibernate.dialect.OracleDialect"/> </database-object> </hibernate-mapping>

Captulo 6. Mapeo de colecciones 6.1. Colecciones persistentes


Hibernate requiere que los campos con valor de coleccin sean declarados como el tipo de una interfaz, por ejemplo:
public class Product { private String serialNumber; private Set parts = new HashSet(); public Set getParts() { return parts; } void setParts(Set parts) { this.parts = parts; }

78 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

public String getSerialNumber() { return serialNumber; } void setSerialNumber(String sn) { serialNumber = sn; } }

La interfaz puede ser, efectivamente, un java.util.Set, java.util.Collection, java.util.List, java.util.Map, java.util.SortedSet, java.util.SortedMap o cualquier otra cosa que implemente la interfaz org.hibernate.usertype.UserCollectionType.) Dese cuenta de cmo inicializamos la variable de instancia con una instancia de HashSet. sta es la mejor manera de inicializar propiedades con valor de coleccin, o instancias recientemente inicializadas (no persistentes). Cuando una clase se vuelve persistente (al llamar persist(), por ejemplo) Hibernate en realidad reemplazar el HashSet con una implementacin de Set propia de Hibernate mismo. Est atento a errores como stos:
Cat cat = new DomesticCat(); Cat kitten = new DomesticCat(); .... Set kittens = new HashSet(); //kittens=gatitos kittens.add(kitten); cat.setKittens(kittens); session.persist(cat); kittens = cat.getKittens(); // Correcto, porque la coleccin kittens es un Set (HashSet) cat.getKittens(); // Error!

Las colecciones persistentes que son inyectadas por Hibernate se comportan como: HashMap, HashSet, TreeMap, TreeSet or ArrayList, dependiendo del tipo de interfaz. Las instancias de coleccioones tienen el comportamiento usual de los "value tupes". Son automticamente persistidas cuando son referidas por un objeto persistente, y aumticamente borradas cuando son "des-referidas". Si una coleccin se pasa de un objeto persistente a otro, sus elementos pueden ser movidos de una tabla a otra. Dos entidades no pueden compartir una referencia a la misma instancia de una coleccin. Dado el modelo relacional subyacente, las propiedades con valor de coleccin no soportan la semntica de nulo. Hibernate no distingue entre una coleccin nula y una coleccin vaca. No vale la pena preocuparse mucho por nada de esto. Use las colecciones persistentes del mismo modo en que usara las colecciones comunes de Java. Slo asegrese de comprender la semntica de las asociaciones bidireccionales (la cual se discute ms adelante).

6.2. Mapeo de colecciones


Consejo
Hay una gran variedad de mapeos que puede ser generada para colecciones, abarcando muchos modelos relacionales de uso comn. Le sugerimos que experimente con la herramienta de generacin de esquemas de DB para tener una idea de cmo las declaraciones de mapeo se traducen en tablas de una base de datos. El elemento de mapeo de Hibernate que se use para mapear una coleccin depende del tipo de interfaz. Por ejemplo, un elemento <set> se usa para mapear propiedades del tipo Set.
<class name="Product"> <id name="serialNumber" column="productSerialNumber"/> <set name="parts"> <key column="productSerialNumber" not-null="true"/> <one-to-many class="Part"/> </set> </class>

Adems de <set>, tambin estn los elementos de mapeo <list>, <map>, <bag>, <array> y <primitive-array> . El elemento <map> es representativo:
<map name="propertyName" table="table_name" schema="schema_name" lazy="true|extra|false"

(1) (2) (3) (4)

79 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

inverse="true|false"

(5)

cascade="all|none|save-update|delete|all-delete-orphan|delet(6)e-orphan" sort="unsorted|natural|comparatorClass" (7) order-by="column_name asc|desc" (8) where="arbitrary sql where condition" (9) fetch="join|select|subselect" (10) batch-size="N" access="field|property|ClassName" optimistic-lock="true|false" mutable="true|false" node="element-name|." embed-xml="true|false" > <key .... /> <map-key .... /> <element .... /> </map> (11) (12) (13) (14)

(1)
name el nombre

de la propiedad coleccin

(2)
table (optativo, por defecto, el nombre

de la propiedad) el nombre de la tabla de la coleccin (no se usa en

asociaciones de-muchos-a-muchos). (3)


schema (optativo)

el nombre de un esquema de base de datos que suplanta al esquema declarado en el elemento

raz. (4)
lazy (optativo, por defecto, true) puede usarse para inhabilitar la "captura haragana" (lazy fetching) y especificar que la asociacin es siempre capturada en forma "ansiosa" (eager fetching), o para especificar que la asociacin es "sper-haragana", en donde la mayora de las operaciones evitan inicializar la coleccin (prescrito para colecciones muy grandes).

(5)
inverse

(optativo, por defecto, false) marca esta coleccin como el extremo "inverso" de una asociacin bidireccional.

(6)
cascade

(optativo, por defecto, none) les permite a las operaciones propagarse en cascada a las entidades hijas.

(7)
sort (optativo)

especifica una coleccin ordenada con un orden natural, o una clase "comparator" dada.

(8)
order-by (optativo, a partir de JDK1.4 solamente) especifica una columna o columnas de tabla que define el orden de iteracin del Map, Set o bag, junto con un asc o desc opcional (ascendente/descendente).

(9)
where (optativo)

especifica una condicin SQL WHERE arbitraria, a ser usada ciando se capture o borre la coleccin (til cuando la coleccin slo debe contener un subconjunto de los datos disponibles).

(10)
fetch (optativo, por defecto, select)

Elije entre la captura por outer-join, select secuencial, y subselect

secuencial. (11) (optativo, porcolecciones defecto, 1) especifica el "tamao de lote" al capturar instancias de esta coleccin en 6.2.1. batch-size Claves forneas de las forma haragana.

80 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

Las instancias de colecciones se distinguen en la BD por la clave fornea que posee a la coleccin. Esta clave fornea se denomina columna (o columnas) clave de la coleccin en la tabla de la coleccin. La columna clave de la coleccin es mapeada por el elemento <key>. Puede haber constraints de nulabilidad en la columna de la clave fornea. Para la mayora de las colecciones, esto est implcito. Para las asociaciones de-uno-a-muchos unidireccionales, la columna de la clave primaria es anulable por defecto, as que a veces es necesario especificar not-null="true".
<key column="productSerialNumber" not-null="true"/>

la constraint de clave fornea puede usar ON DELETE CASCADE.


<key column="productSerialNumber" on-delete="cascade"/>

Vea el captulo correspondiente para una definicin completa del elemento <key>.

6.2.2. Elementos de las colecciones


Las colecciones pueden contener casi cualquier otro tipo de Hibernate, incluyendo todos los tipos bsicos, los tipos a medida, componentes, y, por supuesto, referencias a otras entidades. Esta es una distincin importante: un objeto en una coleccin puede ser manipulado con la semntica de "valor" (que todo su ciclo de vida dependa del dueo de la coleccin), o puede ser una referencia a otra entidad, con su propio ciclo de vida. En este ltimo caso, slo el "vnculo" entre ambos objetos es lo que se considera como estado almacenado por la coleccin. Al tipo contenido se lo refiere como al tipo del elemento de la coleccin. Los elementos de la coleccin son mapeados por <element> o <composite-element>, o, en el caso de referencias a entidades, con <one-to-many> o <many-to-many>. Los primeros dos, mapean elementos con la semntica de valor. Los otros dos, se usan para mapear asociaciones de entidades.

6.2.3. Colecciones indexadas


Todos los mapeos de coleccin, excepto los los que tengan semntica de set o de bag, necesitan una columna ndice en la tabla de la coleccin (una columna que mapea a un ndice de una array), o un ndice de List, o una clave de un Map. El ndice de un Map puede ser de cualqueira de los tipos bsico, mapeado con <map-key>, puede ser una entidad mapeada con <map-key-many-to-many>, o puede ser un tipo compuesto, mapeado con <composite-map-key>. El ndice de un array o lista es siempre del tipo integer y se mapea usando el elemento <list-index> element. La columna mapeada contiene enteros secuenciales (comenzando por cero, por defecto).
<list-index column="column_name" base="0|1|..."/>

(1)

(1)
column_name (obligatorio): El nombre

de la columna que contiene el valor del ndice de la coleccin.

(1)
base

(optativo, por defecto, 0): El valor de columna ndice correspondiente al primer elemento de la lista o array.

<map-key column="column_name" formula="any SQL expression" type="type_name" node="@attribute-name" length="N"/>

(1) (2) (3)

(1)
column (optativo): El nombre

de la columna que contiene los valores de ndice de la coleccin.

(2)

<map-key-many-to-many formula (optativo): Una frmula column="column_name"

SQL usada para evaluar la clave del mapa


(1)

81 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

formula="any SQL expression" class="ClassName" />

(2)(3)

(1)
column (optativo): El nombre

de la columna de clave fornea para los valores de ndice de la coleccin.

(2)
formula (optativo): Una

frmula SQL usada para evaluar la clave fornea de la clave del mapa.

(3)
class (obligatorio): La

clase de entidad usada como clave primaria del mapa.

Si su tabla no tiene una columna ndice, pero usted an desea usar una List como el tipo de propiedad, usted debera mapear la propiedad como una <bag> de Hibernate. Una bag (bolsa) no retiene su orden cuando es obtenida de la base de datos, pero puede ser opcionalmente ordenada.

6.2.4. Colecciones de valores y asociaciones de-muchos-a-muchos


Cualquier coleccin de valores o asociacin de-muchos-a-muchos requiere una tabla de coleccin dedicada, con una columna o columnas de clave fornea, una columna o columnas para el elemento de la coleccin, y, posiblemente, una columna o columnas ndice. Para una coleccin de valores, usamos la tag <element>.
<element column="column_name" formula="any SQL expression" type="typename" length="L" precision="P" scale="S" not-null="true|false" unique="true|false" node="element-name" />

(1) (2) (3)

(1)
column (optativo): El nombre

de la columna que contiene los valores de elementos de la coleccin.

(2)
formula (optativo): Una

frmula SQL usada para evaluar el elemento.

(3)
type (obligatorio): El tipo de

elemento de coleccin

Una asociacin de-muchos-a-muchos (many-to-many) se especifica usando el elemento <many-to-many>.


<many-to-many column="column_name" formula="any SQL expression" class="ClassName" fetch="select|join" unique="true|false" not-found="ignore|exception" entity-name="EntityName" property-ref="propertyNameFromAssociatedClass" node="element-name" embed-xml="true|false" />

(1) (2) (3) (4) (5) (6) (7) (8)

82 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

(1)
column (optativo): el nombre

de columna del elemento clave fornea.

(2)
formula

(optativo): una frmula SQL usada para evaluar el valor del elemento clave fornea

(3)
class (obligatorio): el nombre

de la clase asociada.

(4)
fetch (optativo, por defecto, join): permite capturas para esta asociacin mediante un outer-join o un select secuencial. ste es un caso especial: para una captura total y "ansiosa" (usando un solo SELECT) de una entidad y sus relaciones de-muchos-a-muchos con otras entidades, se debera habilitar la captura (fetch) de tipo join no solamente en la coleccin misma, sino tambin en este atributo del elemento anidado <many-to-many>.

(5)
unique (optativo): habilita la generacin de lenguaje de definicin de datos (DDL) para una constraint de unicidad en la columna de clave fornea. Esto vuelve efectivamente "de-uno-a-muchos" la multiplicidad de la asociacin.

(6)
not-found (optativo, por defecto, exception): Especifica cmo se fornea. ignore tratar la fila faltante como una asociacin nula

actuar cuando le falten filas a la clave

(7)
entity-name

(optativo): el nombre de entidad de la clase asociada, como una alternativa a class.

(8)
property-ref: (optativo) el nombre de una propiedad, en la clase asociada que est ligada a esta clave fornea. Si no se especifica, se usa la clave primaria de la clase asociada.

A continuacin, algunos ejemplos. Primero, un conjunto de strings.


<set name="names" table="person_names"> <key column="person_id"/> <element column="person_name" type="string"/> </set>

Una bag conteniendo enteros, con un orden de iteracin determinado por el atributo order-by:
<bag name="sizes" table="item_sizes" order-by="size asc"> <key column="item_id"/> <element column="size" type="integer"/> </bag>

Un array de entidades (en este caso, una asociacin de-uno-a-muchos):


<array name="addresses" table="PersonAddress" cascade="persist"> <key column="personId"/> <list-index column="sortOrder"/> <many-to-many column="addressId" class="Address"/> </array>

Un mapa de ndices string a fechas:


<map name="holidays" table="holidays" schema="dbo" order-by="hol_name asc"> <key column="id"/> <map-key column="hol_name" type="string"/> <element column="hol_date" type="date"/> </map>

Una lista de componentes (se discute ms adelante):

83 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

<list name="carComponents" table="CarComponents"> <key column="carId"/> <list-index column="sortOrder"/> <composite-element class="CarComponent"> <property name="price"/> <property name="type"/> <property name="serialNumber" column="serialNum"/> </composite-element> </list>

6.2.5. Asociaciones de-uno-a-muchos


Una asociacin de-uno-a-muchos vincula las tablas de dos clases a travs de una clave fornea, sin la intervencin de una "tabla de coleccin". Este mapeo pierde algo de la semntica de las colecciones normales de Java, porque: Una instancia de la clase-entidad contenida, no puede pertenecer a ms de una instancia de la coleccin. Una instancia de la clase-entidad contenida, no puede aparecer en ms de un valor de ndice de la coleccin. Una asociacin de Product a Part (producto a parte) requiere la existencia de una clave fornea, y posiblemente una columna ndice en la tabla Part. Una tag <one-to-many> indica que sta es una asociacin de-uno-a-muchos.
<one-to-many class="ClassName" not-found="ignore|exception" entity-name="EntityName" node="element-name" embed-xml="true|false" />

(1) (2) (3)

(1)
class (obligatorio): El nombre

de la clase asociada.

(2)
not-found

(optativo, por defecto, exception): especifica cmo se manejarn los identificadores en cach que estn refirindose a columnas perdidas. ignore tratar la fila ausente como una asociacin nula.

(3)
entity-name

(optativo): El nombre de la entidad asociada, como alternativa a class.

Note que el elemento <one-to-many> no necesita declarar ninguna columna. Tampoco es necesatio especificar un nombre de tabla en ningn lado. Nota muy importante: Si la columna de clave fornea de una asociacin <one-to-many> se declara NOT NULL, se debe declarar el mapeo de <key> not-null="true" o usar una asociacin bidireccional con el mapeo de la coleccin marcado como inverse="true". Vea la discusn sobre asociaciones bidireccionales ms adelante en este captulo. Este ejemplo muestra un mapa de entidades Part por nombre (donde el nombre de la parte, partName, es una propiedad persistente de Part). Note el uso de un ndice basado en una frmula.
<map name="parts" cascade="all"> <key column="productId" not-null="true"/> <map-key formula="partName"/> <one-to-many class="Part"/> </map>

6.3. Mapeos de coleccin avanzados:


6.3.1. Colecciones ordenadas.
Hibernate soporta colecciones que implementen java.util.SortedMap y java.util.SortedSet. Se debe especificar un comparador en el archivo de mapeo.

84 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

<set name="aliases" table="person_aliases" sort="natural"> <key column="person"/> <element column="name" type="string"/> </set> <map name="holidays" sort="my.custom.HolidayComparator"> <key column="year_id"/> <map-key column="hol_name" type="string"/> <element column="hol_date" type="date"/> </map>

Valores permitidos del atributo sort son unsorted, natural y el nombre de una clase que implemente java.util.Comparator. Las colecciones ordenadas en realidad se comportan como un java.util.TreeSet o java.util.TreeMap. Si quiere que la base de datos misma ordene los elementos de la coleccin, use el atributo order-by del mapeo de los mapeos de set, bag o map. Esta solucin slo se encuentra disponible bajo la JDK 1.4 o superior (se implementa usando LinkedHashSet o LinkedHashMap). Esto efecta el ordenamiento en la consulta SQL, no en memoria.
<set name="aliases" table="person_aliases" order-by="lower(name) asc"> <key column="person"/> <element column="name" type="string"/> </set> <map name="holidays" order-by="hol_date, hol_name"> <key column="year_id"/> <map-key column="hol_name" type="string"/> <element column="hol_date type="date"/> </map>

Note que el valor del atributo order-by es un ordenamiento SQL, no HQL! Las asociaciones pueden incluso ser ordenadas por algn criterio arbitrario en tiempo de ejecucin, usandp un filtro (filter()) de coleccin.
sortedUsers = s.createFilter( group.getUsers(), "order by this.name" ).list();

6.3.2. Asociaciones bidireccionales


Una asociacin bidireccional (bidirectional association) permite navegar desde ambos "extremos" de la asociacin. Se soportan dos tipos de asociacin bidireccional: one-to-many (de-uno-a-muchos) un set o una bag en un extremo, un valor simple en en otro extremo. many-to-many (de-muchos-a-muchos) un set o una bag con valores en ambos extremos Se puede especificar una asociacin bidireccional de-muchos-a-muchos simplemente mapeando dos asociaciones a la misma tabla de la base de datos, y declarando uno de los extremos como inverse (cul, es a eleccin, pero no puede ser una coleccin indexada). He aqu un ejemplo de una asociacin bidireccional de-muchos-a-muchos; cada categora puede tener muchos items y cada tem puede tener muchas categoras:
<class name="Category"> <id name="id" column="CATEGORY_ID"/> ... <bag name="items" table="CATEGORY_ITEM"> <key column="CATEGORY_ID"/> <many-to-many class="Item" column="ITEM_ID"/> </bag> </class> <class name="Item">

85 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

<id name="id" column="ITEM_ID"/> ... <!-- lado inverso --> <bag name="categories" table="CATEGORY_ITEM" inverse="true"> <key column="ITEM_ID"/> <many-to-many class="Category" column="CATEGORY_ID"/> </bag> </class>

Los cambios que se le hacen slo al extremo inverso de la asociacin, no son persistidos. Esto significa que Hibernate tiene dos representaciones en memoria por cada asociacin bidireccional.: un vnculo de A a B, y otro vnculo de B a A. Esto es ms fcil de entender si se piensa en el modelo de objetos Java y cmo se crea una relacin de-muchos-a-muchos en Java.
category.getItems().add(item); item.getCategories().add(category); session.persist(item); session.persist(category); // La categora ahora "sabe" acerca de la relacin // El tem ahora "sabe" acerca de la relacin // La relacin no ser grabada! // La relacin s ser grabada

El lado no-inverso se usa para grabar en la base de datos la representacin en memoria. Se puede definir una asociacin bidireccional de-muchos-a-muchos mapeando un a asocacin de-uno-a-muchos a la(s) misma(s) columna(s) de la tabla que una asociacin de-muchos-a-uno, y poniendo inverse="true" en el el extremo 'muchos'.
<class name="Parent"> <id name="id" column="parent_id"/> .... <set name="children" inverse="true"> <key column="parent_id"/> <one-to-many class="Child"/> </set> </class> <class name="Child"> <id name="id" column="child_id"/> .... <many-to-one name="parent" class="Parent" column="parent_id" not-null="true"/> </class>

Mapear uno de los extremos de la asociacin con inverse="true" no afecta las propagaciones en cascada. Son conceptos ortogonales!

6.3.3. Asociaciones bidireccionales con colecciones indexadas.


Una asociacin bidireccional en donde un extremo est representado como una <list> o un <map>necesita algunas consideraciones especiales. Si existe una propiedad de la clase hija que mapee a la columna de ndice, no hay problema, podemos continuar usando inverse="true" en el mapeo de la coleccin.
<class name="Parent"> <id name="id" column="parent_id"/> .... <map name="children" inverse="true"> <key column="parent_id"/> <map-key column="name" type="string"/> <one-to-many class="Child"/> </map> </class> <class name="Child"> <id name="id" column="child_id"/> .... <property name="name" not-null="true"/> <many-to-one name="parent" class="Parent" column="parent_id" not-null="true"/> </class>

86 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

Pero si tal propiedad no existe en la clase hoja, no podemos concebir la asociacin como verdaderamete bidireccional (hay informacin disponible en un extremo que no lo est en el otro extremo). En este caso, no podemos mapear la coleccin con inverse="true". En lugar de eso, podemos usar el siguiente mapeo.
<class name="Parent"> <id name="id" column="parent_id"/> .... <map name="children"> <key column="parent_id" not-null="true"/> <map-key column="name" type="string"/> <one-to-many class="Child"/> </map> </class> <class name="Child"> <id name="id" column="child_id"/> .... <many-to-one name="parent" class="Parent" column="parent_id" insert="false" update="false" not</class>

Note que en este mapeo, el extremo con la coleccin es el responsable de las actualizaciones de la clave fornea. A HACER: esto resulta realmente en la ejecucin de UPDATES innecesarios?

6.3.4. Asociaciones ternarias


Hay tres abordajes posibles para mapear asociaciones ternarias. Uno es usar un Map con la asociacin como ndice:
<map name="contracts"> <key column="employer_id" not-null="true"/> <map-key-many-to-many column="employee_id" class="Employee"/> <one-to-many class="Contract"/> </map> <map name="connections"> <key column="incoming_node_id"/> <map-key-many-to-many column="outgoing_node_id" class="Node"/> <many-to-many column="connection_id" class="Connection"/> </map>

Un segundo abordaje es simplemente remodelar la asociacin como una clase de entidad. ste es el enfoque que se usa ms comnmente. Una ltima alternativa, es usar elementos compuestos, lo cual se discute ms adelante.

6.3.5. Usar una <idbag>


Si usted est totalmente convencido de que las claves compuestas son una cosa mala, y de que las entidades debe tener identidicadores "sintticos" (claves sustitutas), entonces encontrar un tanto raro que las asociaciones de-muchosa-muchos y las colecciones que le hemos mostrado hasta ahora se mapean todas a tablas con claves compuestas! Este punto es debatible. Una tabla que sea puramente "de asociacin" no se beneficia mucho con la existencia de una clave sustituta (aunque una coleccin de valores compuestos s podra). De todos modos, Hibernate provee un mecanismo que permite mapear asociaciones de-muchos-a-muchos y colecciones de valores a una tabla con clave sustituta. El elemento <idbag> le permite mapear una List (o Collection) con semntica de bag.
<idbag name="lovers" table="LOVERS"> <collection-id column="ID" type="long"> <generator class="sequence"/> </collection-id> <key column="PERSON1"/> <many-to-many column="PERSON2" class="Person" fetch="join"/> </idbag>

87 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

Como se puede ver, una <idbag> tiene un generador de id "sinttico", igual que una clase de entidad! A cada fila de la coleccin se le asigna una clave sustituta diferente. Si embargo, Hibernate no provee ningn mecanismo para descubrir el valor de la clave sustituta de una fila en particular. Note que la performance al actualizar una <idbag> es mucho mejor que la de una <bag> comn! Hibernate puede localizar filas individuales eficientemente, y actualizarlas o borraras individualmente, como si fuera una list, un map o un set. En la implementacin actual, el identificador native como estrategia de generacin de identificadores no se soporta para las <idbag>s.

6.4. Ejemplos de colecciones


Las secciones precedentes son bastante confusas. As que veamos un ejemplo. Esta clase:
package eg; import java.util.Set; public class Parent { private long id; private Set children; public long getId() { return id; } private void setId(long id) { this.id=id; } private Set getChildren() { return children; } private void setChildren(Set children) { this.children=children; } .... .... }

Tiene una coleccin de instancias Child. Si cada child (hijo) tiene como mucho un padre, el mapeo ms natural es una asociacin de-uno-a-muchos:
<hibernate-mapping> <class name="Parent"> <id name="id"> <generator class="sequence"/> </id> <set name="children"> <key column="parent_id"/> <one-to-many class="Child"/> </set> </class> <class name="Child"> <id name="id"> <generator class="sequence"/> </id> <property name="name"/> </class> </hibernate-mapping>

Esto se mapea a las siguientes definiciones de tabla:


create table parent ( id bigint not null primary key ) create table child ( id bigint not null primary key, name varchar(255), parent_id bigint ) alter table child add constraint childfk0 (parent_id) references parent

If the parent is required, use a bidirectional one-to-many association:


<hibernate-mapping> <class name="Parent"> <id name="id"> <generator class="sequence"/> </id>

88 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

<set name="children" inverse="true"> <key column="parent_id"/> <one-to-many class="Child"/> </set> </class> <class name="Child"> <id name="id"> <generator class="sequence"/> </id> <property name="name"/> <many-to-one name="parent" class="Parent" column="parent_id" not-null="true"/> </class> </hibernate-mapping>

Note la constraint NOT NULL:


create table parent ( id bigint not null primary key ) create table child ( id bigint not null primary key, name varchar(255), parent_id bigint not null ) alter table child add constraint childfk0 (parent_id) references parent

Alternativamente, si usted insiste absolutamente en que la asociacin debe ser unidireccional, debe declarar la constraint NOT NULL en el mapeo de la <key>.
<hibernate-mapping> <class name="Parent"> <id name="id"> <generator class="sequence"/> </id> <set name="children"> <key column="parent_id" not-null="true"/> <one-to-many class="Child"/> </set> </class> <class name="Child"> <id name="id"> <generator class="sequence"/> </id> <property name="name"/> </class> </hibernate-mapping>

Por otra parte, si un hijo tiene mltiles padres, lo apropiado es una relacin de-muchos-a-muchos.
<hibernate-mapping> <class name="Parent"> <id name="id"> <generator class="sequence"/> </id> <set name="children" table="childset"> <key column="parent_id"/> <many-to-many class="Child" column="child_id"/> </set> </class> <class name="Child"> <id name="id"> <generator class="sequence"/> </id> <property name="name"/> </class> </hibernate-mapping>

Definiciones de tablas:
create table parent ( id bigint not null primary key )

89 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

create table child ( id bigint not null primary key, name varchar(255) ) create table childset ( parent_id bigint not null, child_id bigint not null, primary key ( parent_i alter table childset add constraint childsetfk0 (parent_id) references parent alter table childset add constraint childsetfk1 (child_id) references child

Para ms ejemplos, y una explicacin paso a paso del mapeo de una relacin padre-hijo, vea Captulo 21, Ejemplo: Padre/Hijo. Son posibles mapeos de asociaciones an ms exticas. Catalogaremos todas las posibilidades en el captulo siguiente.

Captulo 7. Mapeos de asociaciones 7.1. Introduccin


Los mapeos de asociaciones son lo ms difcil de comprender correctamente. En esta seccin revisaremos los casos cannicos uno por uno, empezando con los mapeos unidireccionales, y siguiendo con los bidireccionales. Usaremos Person y Address ("persona" y "direccin") en todos los ejemplos. Clasificaremos las asociaciones segn usen o no una tabla de asociacin, y segn su multiplicidad. Las claves forneas anulables no son consideradas una prctica recomendable, en la modelizacin de datos tradicional, as que todos nuestros ejemplos usarn claves forneas no nulas. Esto no es obligatorio, los mapeos an funcionaran si se eliminara la constraint de nulabilidad.

7.2. Asociaciones unidireccionales.


7.2.1. de-muchos-a-uno
Una asociacin unidireccional de-muchos-a-uno es el tipo ms comn de asociacin unidireccional.
<class name="Person"> <id name="id" column="personId"> <generator class="native"/> </id> <many-to-one name="address" column="addressId" not-null="true"/> </class> <class name="Address"> <id name="id" column="addressId"> <generator class="native"/> </id> </class> create table Person ( personId bigint not null primary key, addressId bigint not null ) create table Address ( addressId bigint not null primary key )

7.2.2. de-uno-a-uno
Una asociacin unidireccional de-uno-a-uno por clave fornea es prcitcamente idntica. La nica diferencia es la constraint de unicidad.
<class name="Person"> <id name="id" column="personId"> <generator class="native"/> </id> <many-to-one name="address" column="addressId" unique="true" not-null="true"/> </class> <class name="Address"> <id name="id" column="addressId">

90 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

<generator class="native"/> </id> </class> create table Person ( personId bigint not null primary key, addressId bigint not null unique ) create table Address ( addressId bigint not null primary key )

Una asociacin unidirectional de-uno-a-uno por clave primaria normalmente usa un generador de id especial (note que hemos revertido la direccin de la asociacin en este ejemplo).
<class name="Person"> <id name="id" column="personId"> <generator class="native"/> </id> </class> <class name="Address"> <id name="id" column="personId"> <generator class="foreign"> <param name="property">person</param> </generator> </id> <one-to-one name="person" constrained="true"/> </class> create table Person ( personId bigint not null primary key ) create table Address ( personId bigint not null primary key )

7.2.3. de-uno-a-muchos
Una asociacin unidireccional de-uno-a-muchos por clave fornea es un caso muy inusual, que no recomendamos usar.
<class name="Person"> <id name="id" column="personId"> <generator class="native"/> </id> <set name="addresses"> <key column="personId" not-null="true"/> <one-to-many class="Address"/> </set> </class> <class name="Address"> <id name="id" column="addressId"> <generator class="native"/> </id> </class> create table Person ( personId bigint not null primary key ) create table Address ( addressId bigint not null primary key, personId bigint not null )

Pensamos que para este caso es mejor usar una tabla de asociacin.

7.3. Asociaciones unidireccionales con tablas de asociacin


7.3.1. de-uno-a-muchos
Una asociacin unidireccional de-uno-a-muchos por tabla de asociacin es mucho ms recomendable. Note que al especificar unique="true", hemos cambiado la multiplicidad de "de-muchos-a-muchos" a "de-uno-a-muchos".
<class name="Person"> <id name="id" column="personId"> <generator class="native"/> </id>

91 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

<set name="addresses" table="PersonAddress"> <key column="personId"/> <many-to-many column="addressId" unique="true" class="Address"/> </set> </class> <class name="Address"> <id name="id" column="addressId"> <generator class="native"/> </id> </class> create table Person ( personId bigint not null primary key ) create table PersonAddress ( personId not null, addressId bigint not null primary key ) create table Address ( addressId bigint not null primary key )

7.3.2. de-muchos-a-uno
Una asociacin A unidireccional de-muchos-a-uno por tabla de asociacin es muy comn, cuando la asociacin es optativa
<class name="Person"> <id name="id" column="personId"> <generator class="native"/> </id> <join table="PersonAddress" optional="true"> <key column="personId" unique="true"/> <many-to-one name="address" column="addressId" not-null="true"/> </join> </class> <class name="Address"> <id name="id" column="addressId"> <generator class="native"/> </id> </class> create table Person ( personId bigint not null primary key ) create table PersonAddress ( personId bigint not null primary key, addressId bigint not null ) create table Address ( addressId bigint not null primary key )

7.3.3. de-uno-a-uno
Una asociacin unidireccional de-uno-a-uno por tabla de asociacin es muy inusual, pero posible.
<class name="Person"> <id name="id" column="personId"> <generator class="native"/> </id> <join table="PersonAddress" optional="true"> <key column="personId" unique="true"/> <many-to-one name="address" column="addressId" not-null="true" unique="true"/> </join> </class> <class name="Address"> <id name="id" column="addressId"> <generator class="native"/> </id> </class> create table Person ( personId bigint not null primary key ) create table PersonAddress ( personId bigint not null primary key, addressId bigint not null unique create table Address ( addressId bigint not null primary key )

7.3.4. de-muchos-a-muchos

92 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

Finalmente, tenemos una asociacin unidireccional de-muchos-a-muchos.


<class name="Person"> <id name="id" column="personId"> <generator class="native"/> </id> <set name="addresses" table="PersonAddress"> <key column="personId"/> <many-to-many column="addressId" class="Address"/> </set> </class> <class name="Address"> <id name="id" column="addressId"> <generator class="native"/> </id> </class> create table Person ( personId bigint not null primary key ) create table PersonAddress ( personId bigint not null, addressId bigint not null, primary key (pers create table Address ( addressId bigint not null primary key )

7.4. Asociaciones bidireccionales


7.4.1. de-uno-a-muchos / de-muchos-a-uno
Una asociacin bidireccional de-muchos-a-uno es el tipo ms comn de asociacin (la relacin padre/hijo estndar).
<class name="Person"> <id name="id" column="personId"> <generator class="native"/> </id> <many-to-one name="address" column="addressId" </class> <class name="Address"> <id name="id" column="addressId"> <generator class="native"/> </id> <set name="people" inverse="true"> <key column="addressId"/> <one-to-many class="Person"/> </set> </class> create table Person ( personId bigint not null primary key, addressId bigint not null ) create table Address ( addressId bigint not null primary key )

not-null="true"/>

Si se usa una List (u otra coleccin idexada) se necesitar asignarle not null a la columna "key" de la clave fornea, y dejar que Hibernate maneje la asociacin desde el extremo "muchos" para mantener el ndice de cada elemento (convirtiendo el otro lado virtualmente en inverso, al especificar update="false" y insert="false"):
<class name="Person"> <id name="id"/> ... <many-to-one name="address" column="addressId" not-null="true" insert="false" update="false"/> </class> <class name="Address"> <id name="id"/> ... <list name="people"> <key column="addressId" not-null="true"/> <list-index column="peopleIdx"/> <one-to-many class="Person"/> </list> </class>

93 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

Es importante que se defina not-null="true" en el elemento <key> del mapeo de la coleccin, si la columna de clave fornea sunyacente es NOT NULL. No debe declararse solamente not-null="true" en un posible elemento <column> anidado, sino en el elemento <key>.

7.4.2. de-uno-a-uno
Un asociacin bidireccional de-uno-a-uno por clave fornea es bastante comn
<class name="Person"> <id name="id" column="personId"> <generator class="native"/> </id> <many-to-one name="address" column="addressId" unique="true" not-null="true"/> </class> <class name="Address"> <id name="id" column="addressId"> <generator class="native"/> </id> <one-to-one name="person" property-ref="address"/> </class> create table Person ( personId bigint not null primary key, addressId bigint not null unique ) create table Address ( addressId bigint not null primary key )

Un asociacin bidireccional de-uno-a-uno por clave primaria usa el generador de id especial.


<class name="Person"> <id name="id" column="personId"> <generator class="native"/> </id> <one-to-one name="address"/> </class> <class name="Address"> <id name="id" column="personId"> <generator class="foreign"> <param name="property">person</param> </generator> </id> <one-to-one name="person" constrained="true"/> </class> create table Person ( personId bigint not null primary key ) create table Address ( personId bigint not null primary key )

7.5. Asociaciones bidireccionales por tablas de asociacin


7.5.1. de-uno-a-muchos / de-muchos-a-uno
Un asociacin bidireccional de-uno-a-muchos por tabla de asociacin. Note que el inverse="true" puede ir an cualquier extremo de la asociacin, en la coleccin, o en el join.
<class name="Person"> <id name="id" column="personId"> <generator class="native"/> </id> <set name="addresses" table="PersonAddress"> <key column="personId"/> <many-to-many column="addressId" unique="true" class="Address"/> </set> </class> <class name="Address"> <id name="id" column="addressId"> <generator class="native"/>

94 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

</id> <join table="PersonAddress" inverse="true" optional="true"> <key column="addressId"/> <many-to-one name="person" column="personId" not-null="true"/> </join> </class> create table Person ( personId bigint not null primary key ) create table PersonAddress ( personId bigint not null, addressId bigint not null primary key ) create table Address ( addressId bigint not null primary key )

7.5.2. de-uno-a-uno
Un asociacin bidireccional de-uno-a-uno por tabla de asociacin es extremadamente inusual, pero posible.
<class name="Person"> <id name="id" column="personId"> <generator class="native"/> </id> <join table="PersonAddress" optional="true"> <key column="personId" unique="true"/> <many-to-one name="address" column="addressId" not-null="true" unique="true"/> </join> </class> <class name="Address"> <id name="id" column="addressId"> <generator class="native"/> </id> <join table="PersonAddress" optional="true" inverse="true"> <key column="addressId" unique="true"/> <many-to-one name="person" column="personId" not-null="true" unique="true"/> </join> </class> create table Person ( personId bigint not null primary key ) create table PersonAddress ( personId bigint not null primary key, addressId bigint not null unique create table Address ( addressId bigint not null primary key )

7.5.3. de-muchos-a-muchos
Finalmente, tenemos una asociacin bidireccional de-muchos-a-muchos.
<class name="Person"> <id name="id" column="personId"> <generator class="native"/> </id> <set name="addresses" table="PersonAddress"> <key column="personId"/> <many-to-many column="addressId" class="Address"/> </set> </class> <class name="Address"> <id name="id" column="addressId"> <generator class="native"/> </id> <set name="people" inverse="true" table="PersonAddress"> <key column="addressId"/> <many-to-many column="personId" class="Person"/> </set> </class> create table Person ( personId bigint not null primary key ) create table PersonAddress ( personId bigint not null, addressId bigint not null, primary key (pers create table Address ( addressId bigint not null primary key )

7.6. Mapeos de asociaciones ms complejas


95 de 198 17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

Asociaciones ms complejas son extremadamente raras. Hibernate posibilita manejar asociaciones ms complejas usando fragmentos SQL incrustados en el documento de mapeo. Por ejemplo, si una tabla con informacin contable histrica definiere las columnas accountNumber, effectiveEndDate and effectiveStartDate, mapeadas de esta manera:
<properties name="currentAccountKey"> <property name="accountNumber" type="string" not-null="true"/> <property name="currentAccount" type="boolean"> <formula>case when effectiveEndDate is null then 1 else 0 end</formula> </property> </properties> <property name="effectiveEndDate" type="date"/> <property name="effectiveStateDate" type="date" not-null="true"/>

entonces podemos mapear una asociacin a la instancia actual (la que tiene effectiveEndDate nula) usando:
<many-to-one name="currentAccountInfo" property-ref="currentAccountKey" class="AccountInfo"> <column name="accountNumber"/> <formula>'1'</formula> </many-to-one>

En un ejemplo ms complejo, imagine que la asociacin entre Employee y Organization estuviere mantenida por una tabla Employment, llena de datos histricos de empleo. Entonces, una asociacin al empleador ms reciente de un empleado (el que tuviere la startDate ms reciente) podra ser mapeada de esta manera:
<join> <key column="employeeId"/> <subselect> select employeeId, orgId from Employments group by orgId having startDate = max(startDate) </subselect> <many-to-one name="mostRecentEmployer" class="Organization" column="orgId"/> </join>

Uno se puede poner bastante creativo con esta funcionalidad, pero normalmente es ms prctico manejar estos casos unando HQL o consultas Criteria.

Captulo 8. Mapeos de componentes


La nocin de componente (en ingls, component) se reusa a lo largo y a lo ancho de Hibernate en distintos contextos, para distintos propsitos.

8.1. Objetos dependientes


Un componente es un objeto contenido, que es persistido como "value type", no como referencia a una entidad. El trmino "componente" se refiere a la nocin orientada a objetos de "composicin" (no a "componentes" a nivel de arquitectura). Por ejemplo, se puede modelar a una persona as:
public class Person { private java.util.Date birthday; private Name name; private String key; public String getKey() { return key; } private void setKey(String key) { this.key=key; } public java.util.Date getBirthday() { return birthday; } public void setBirthday(java.util.Date birthday) { this.birthday = birthday; } public Name getName() {

96 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

return name; } public void setName(Name name) { this.name = name; } ...... ...... } public class Name { char initial; String first; String last; public String getFirst() { return first; } void setFirst(String first) { this.first = first; } public String getLast() { return last; } void setLast(String last) { this.last = last; } public char getInitial() { return initial; } void setInitial(char initial) { this.initial = initial; } }

Ahora, Name puede ser persistida como un componente de Person (en ingls, "nombre" y "persona", respectivamente). Note que Name define mtodos getter y setter para sus propiedades persistentes, pero no necesita declarar ninguna interfaz ni propiedades identiicadoras. Nuestro mapeo Hibernate se vera as:
<class name="eg.Person" table="person"> <id name="Key" column="pid" type="string"> <generator class="uuid"/> </id> <property name="birthday" type="date"/> <component name="Name" class="eg.Name"> <!-- el atributo 'class" es optativo --> <property name="initial"/> <property name="first"/> <property name="last"/> </component> </class>

La tabla PERSON tendra las columnas pid, birthday, initial, first y last. Como todos los "value types", los componentes no soportan referencias compartidas. Dos personas pueden tener el mismo nombre, pero los dos objetos Person correspondientes contendrn dos objetos nombre independientes, slo que con "el mismo" valor. La semntica de nulo de un componente es ad hoc. Cuando se recargue el objeto contenedor, Hibernate assumir que el componente entero es nulo. Esto debera alcanzar para la mayora de los casos. Las propiedades de un componente pueden ser de cualquier tipo Hibernate (colecciones, asociaciones de-muchos-a-uno, otros componentes, etc). Los componentes anidados no deben ser considerados una rareza. Se espera que Hibernate soporte un modelo de objetos muy jerrquico y detallado en este sentido. El elemento <component> acepta un subelemento <parent> que se mapee a una propiedad desde la clase del componente como referencia de vuelta a la entidad contenedora.
<class name="eg.Person" table="person"> <id name="Key" column="pid" type="string"> <generator class="uuid"/> </id> <property name="birthday" type="date"/> <component name="Name" class="eg.Name" unique="true"> <parent name="namedPerson"/> <!-- referencia de vuelta a Person --> <property name="initial"/>

97 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

<property name="first"/> <property name="last"/> </component> </class>

8.2. Colecciones de objetos dependientes


Hay soporte para colecciones de componentes (por ejemplo, un array de tipos Name). Declare su coleccin de componentes reemplazando la tag del elemento <element> con una tag <composite-element>.
<set name="someNames" table="some_names" lazy="true"> <key column="id"/> <composite-element class="eg.Name"> <!-- el atributo class es obligatorio --> <property name="initial"/> <property name="first"/> <property name="last"/> </composite-element> </set>

Nota: si se define un Set de elementos compuestos, es importante implementar equals() y hashCode() correctamente. Los elementos compuestos pueden contener otros componentes, pero no colecciones. Si su componente compuesto a su vez contiene componentes, use la tag <nested-composite-element>. ste es un caso batante extico: una coleccin de componentes que a su vez tengan componentes. A este punto usted debera preguntarse si no sera ms apropiada una asociacin de-uno-a-muchos. Trate de remodelar el elemento compuesto como una entidad, pero dse cuenta de que, aunque el modelo de Java es el mismo, le modelo relacional y la semntica de persistencia son an ligeramente diferentes. Por favor, note que un mapeo de elemento compuesto no soporta propiedades anulables si se est usando un <set>. Hibernate tiene que usar el valor de cada columna para identificar un registro cuando se borra objetos (no hay una clave primaria separada en la tabla de elementos compuestos), lo cual no es posible con valores nulos. Se deber o bien usar slo valores no nulos en un <composite-element>, o bien elegir una <list>, <map>, <bag> o <idbag>. Un caso especial de elemento compuesto ese el elemento compuesto que tiene un elemento <many-to-one> anidado. Un mapeo como ste permite mapear columnas extra de una tabla de asociacin de-muchos-a-muchos a la clase del elemento compuesto. La siguiente es una asociacin de-muchos-a-muchos de from Order a Item (de orden a tem) en donde la fecha de compra ( purchaseDate), el precio (price) y la cantidad (quantity) son propiedades de la asociacin.
<class name="eg.Order" .... > .... <set name="purchasedItems" table="purchase_items" lazy="true"> <key column="order_id"> <composite-element class="eg.Purchase"> <property name="purchaseDate"/> <property name="price"/> <property name="quantity"/> <many-to-one name="item" class="eg.Item"/> <!-- el atributo "clase" es optativo --> </composite-element> </set> </class>

Por supuesto, no puede haber una referencia a la compra del otro lado, para proveer navegacin bidireccional de la asociacin. Recuerde que los componentes son "value types", y no aceptan referencias compartidas. Una simple compra (Purchase) puede estar en el set de una Order, pero no puede ser referida por el Item al mismo tiempo. Incluso son posibles asociaciones ternarias o cuaternarias:
<class name="eg.Order" .... > .... <set name="purchasedItems" table="purchase_items" lazy="true"> <key column="order_id"> <composite-element class="eg.OrderLine"> <many-to-one name="purchaseDetails class="eg.Purchase"/> <many-to-one name="item" class="eg.Item"/> </composite-element> </set>

98 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

</class>

Los elementos compuestos pueden aparecer en consultas, usando la misma sintaxis que las entidades.

8.3. Componentes como ndices de un Map


El elemento <composite-map-key> (clave compuesta de mapa) permite mapear una clase componente como la clave de un Map. Asegrese de reemplazar correctamente los mtodos hashCode() y equals() en la clase componente.

8.4. Componentes usados como identificadores compuestos


Se puede usar un componente como identificador de una clase entidad. Dicho componente debe satisfacer ciertos requisitos: Debe implementar java.io.Serializable. Debe reimplementar equals() y hashCode(), de una manera consistente con la nocin de igualdad para la clave compuesta en la DB. Nota: en Hibernate3, el segundo requisito no es "sine qua non", pero cmplalo de todos modos. No se puede usar un IdentifierGenerator para generar claves compuestas. En lugar de eso, la aplicacn debe asignar sus propios identificadores. Use la tag <composite-id> (con elementos <key-property> anidados) en lugar de la declaracin de <id> usual. Por ejemplo, la clase OrderLine (lnea de una orden) tiene una clave primaria que depende de la clave (compuesta) de Order.
<class name="OrderLine"> <composite-id name="id" class="OrderLineId"> <key-property name="lineId"/> <key-property name="orderId"/> <key-property name="customerId"/> </composite-id> <property name="name"/>

<many-to-one name="order" class="Order" insert="false" update="false"> <column name="orderId"/> <column name="customerId"/> </many-to-one> .... </class>

Ahora, cualquier clave fornea que se refiera a la tabla ORDERLINE, tambin ser compuesta. Esto se debe declarar en los mapeos para otras clases. La asociacin con OrderLine sera mapeada as:
<many-to-one name="orderLine" class="OrderLine"> <!-- el atributo "class" es optativo, como de costumbre --> <column name="lineId"/> <column name="orderId"/> <column name="customerId"/> </many-to-one>

(Note que la tag <column> es una alternativa al atributo column en todos lados.) Una asociacin de-muchos-a-muchos a OrderLine tambin usa la clave fornea compuesta.
<set name="undeliveredOrderLines"> <key column name="warehouseId"/> <many-to-many class="OrderLine"> <column name="lineId"/> <column name="orderId"/>

99 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

<column name="customerId"/> </many-to-many> </set>

La coleccin de OrderLines en Order usara:


<set name="orderLines" inverse="true"> <key> <column name="orderId"/> <column name="customerId"/> </key> <one-to-many class="OrderLine"/> </set>

(El elemento <one-to-many>, como es usual, no declara ninguna columna). Si la OrderLine misma posee una coleccin, tambin tiene una clave fornea compuesta.
<class name="OrderLine"> .... .... <list name="deliveryAttempts"> <key> <!-- una coleccin hereda el tipo de clave compuesta --> <column name="lineId"/> <column name="orderId"/> <column name="customerId"/> </key> <list-index column="attemptId" base="1"/> <composite-element class="DeliveryAttempt"> ... </composite-element> </set> </class>

8.5. Componentes dinmicos


Se puede incluso mapear una propiedad de tipo Map:
<dynamic-component name="userAttributes"> <property name="foo" column="FOO" type="string"/> <property name="bar" column="BAR" type="integer"/> <many-to-one name="baz" class="Baz" column="BAZ_ID"/> </dynamic-component>

La semntica de un mapeo <dynamic-component> es idntica a la de <component>. La ventaja de este tipo de mapeo es la capacidad de determinar las verdaderas propiedades del bean en tiempo de despliegue (deployment), simplemente editando el archivo de mapeo. Tambin es posible la manipulacin en tiempo de ejecucin del documento de mapeo, usando un parser DOM. Mejor an, se puede acceder al meta-modelo de tiempo de configuracin de Hibernate (y cambiarlo) usando el objeto Configuration .

Captulo 9. Mapeo de herencia 9.1. Las tres estrategias


Hibernate soporta tres estrategias bsicas de mapeo de herencia: una tabla por jerarqua de clases una tabla por subclase una tabla por clase concreta

100 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

Adicionalmente, Hibernate soporta una cuarta clase de polimorfismo, ligeramente diferente: polimorfismo implcito Es posible usar estrategias de mapeo diferentes para distintas ramas de la misma jerarqua de herencias, y despus hacer uso del polimorfismo implcito para lograr polimorfismo todo a lo largo de dicha jerarqua. Sin embargo, Hibernate no soporta mezclar mapeos de <subclass>, and <joined-subclass> y <union-subclass> bajo el mismo elemento <class> de la clase raz. S es posible mezclar las estrategias de "una tabla por jerarqua" y de "una tabla por subclase" bajo el mismo elemento <class>, combinando los elementos <subclass> y <join> (vase a continuacin). Es posible definir mapeos de subclass, union-subclass, y joined-subclass en documentos de mapeo separados, justo debajo de hibernate-mapping. Esto permite extender la jerarqua de clases, simplemente agregando un nuevo archivo de mapeo. Se debe especificar el atributo extends en el mapeo de la subclase, nombrando una superclase previamente mapeada. Nota: en el pasado, esta caracterstica haca que el orden de los documentos de mapeo fuese relevante. Desde Hibernate 3, el orden no importa cuando se usa la palabra "extends". El orden dentro de cada documento individual, an tiene que tener las superclases antes de las subclases.
<hibernate-mapping> <subclass name="DomesticCat" extends="Cat" discriminator-value="D"> <property name="name" type="string"/> </subclass> </hibernate-mapping>

9.1.1. Una tabla por jerarqua de clases


Suponga que tenemos una interfaz Payment (pago), implementada por las clases CreditCardPayment, CashPayment, ChequePayment (pago por tarjeta de crdito, efectivo y cheque respectivamente). El mapeo de "una tabla por jerarqua" se vera as:
<class name="Payment" table="PAYMENT"> <id name="id" type="long" column="PAYMENT_ID"> <generator class="native"/> </id> <discriminator column="PAYMENT_TYPE" type="string"/> <property name="amount" column="AMOUNT"/> ... <subclass name="CreditCardPayment" discriminator-value="CREDIT"> <property name="creditCardType" column="CCTYPE"/> ... </subclass> <subclass name="CashPayment" discriminator-value="CASH"> ... </subclass> <subclass name="ChequePayment" discriminator-value="CHEQUE"> ... </subclass> </class>

Se requiere exactamente una tabla. Con esta estrategia de mapeo, hay una gran limitacin: las columnas declaradas por las subclases, como CCTYPE, no pueden tener constraints NOT NULL.

9.1.2. Una tabla por subclase


El mapeo de una tabla por sublcase se vera as:
<class name="Payment" table="PAYMENT"> <id name="id" type="long" column="PAYMENT_ID"> <generator class="native"/> </id> <property name="amount" column="AMOUNT"/> ...

101 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

<joined-subclass name="CreditCardPayment" table="CREDIT_PAYMENT"> <key column="PAYMENT_ID"/> <property name="creditCardType" column="CCTYPE"/> ... </joined-subclass> <joined-subclass name="CashPayment" table="CASH_PAYMENT"> <key column="PAYMENT_ID"/> ... </joined-subclass> <joined-subclass name="ChequePayment" table="CHEQUE_PAYMENT"> <key column="PAYMENT_ID"/> ... </joined-subclass> </class>

Se requieren 4 tablas. Las tres tablas de subclases tienen asociaciones por clave primaria a la tabla de la superclase (de modo que el modelo relacional es en realidad una asociacin de-uno-a-uno).

9.1.3. Una tabla por subclase, usando un discriminador


Note que la implementacin de Hibernate para "una tabla por subclase" no requiere una columna discriminadora. Otros mapeadores objeto/relacionales usan una implementacin diferente de "una tabla por subclase", que s requiere una columna discriminadora en la tabla de la superclase. El enfoque adoptado por Hibernate es mucho ms difcil de implementar, pero probablemente ms correcto desde el punto de vista relacional. Si usted desea usar una columna discriminadora con la estrategia de "una tabla por subclase", puede combinar el uso de <subclass> y <join>, como sigue:
<class name="Payment" table="PAYMENT"> <id name="id" type="long" column="PAYMENT_ID"> <generator class="native"/> </id> <discriminator column="PAYMENT_TYPE" type="string"/> <property name="amount" column="AMOUNT"/> ... <subclass name="CreditCardPayment" discriminator-value="CREDIT"> <join table="CREDIT_PAYMENT"> <key column="PAYMENT_ID"/> <property name="creditCardType" column="CCTYPE"/> ... </join> </subclass> <subclass name="CashPayment" discriminator-value="CASH"> <join table="CASH_PAYMENT"> <key column="PAYMENT_ID"/> ... </join> </subclass> <subclass name="ChequePayment" discriminator-value="CHEQUE"> <join table="CHEQUE_PAYMENT" fetch="select"> <key column="PAYMENT_ID"/> ... </join> </subclass> </class>

La declaracin optativa fetch="select" le dice a Hibernate que no capture los datos de la subclase ChequePayment usando un outer join cuando se consulte a la superclase.

9.1.4. Mezclar "una tabla por jerarqua de clases" con "una tabla por subclase"
Incluso se pueden mezclar las estrategias de "una tabla por jerarqua de clases" con "una tabla por subclase" usando este abordaje:
<class name="Payment" table="PAYMENT">

102 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

<id name="id" type="long" column="PAYMENT_ID"> <generator class="native"/> </id> <discriminator column="PAYMENT_TYPE" type="string"/> <property name="amount" column="AMOUNT"/> ... <subclass name="CreditCardPayment" discriminator-value="CREDIT"> <join table="CREDIT_PAYMENT"> <property name="creditCardType" column="CCTYPE"/> ... </join> </subclass> <subclass name="CashPayment" discriminator-value="CASH"> ... </subclass> <subclass name="ChequePayment" discriminator-value="CHEQUE"> ... </subclass> </class>

Para cualquiera de estas estrategias de mapeo, una asociacin polimrfica a la clase raz Payment se mapea usando <many-to-one>.
<many-to-one name="payment" column="PAYMENT_ID" class="Payment"/>

9.1.5. Una tabla por clase concreta


Con la estrategia de "una tabla por clase concreta" podramos proceder de dos maneras. La primera es usar <unionsubclass>.
<class name="Payment"> <id name="id" type="long" column="PAYMENT_ID"> <generator class="sequence"/> </id> <property name="amount" column="AMOUNT"/> ... <union-subclass name="CreditCardPayment" table="CREDIT_PAYMENT"> <property name="creditCardType" column="CCTYPE"/> ... </union-subclass> <union-subclass name="CashPayment" table="CASH_PAYMENT"> ... </union-subclass> <union-subclass name="ChequePayment" table="CHEQUE_PAYMENT"> ... </union-subclass> </class>

Para las subclases, hay tres clases involucradas. Cada tabla define columnas para todas las propiedades de la subclase, incluso las propiedades heredadas. La limitacin de este abordaje, es que si la propiedad est mapeada en la superclase, el nombre de la columna debe ser el mismo en todas las tablas de subclases. (Podemos relajar este requisito en versiones futuras de Hibernate). La estrategia de generador de identidad no est permitida para una herencia que est usando union-subclass. Lgico, dado que la clave primaria debe ser compartida por todas las subclases de la jerarqua participantes en la unin. Si su superclase es abstracta, mapela con abstract="true". Por supuesto, si no es abstracta, se necesita una tabla adicional (por defecto sera PAYMENT en el ejemplo anterior) para almacenar instancias de la superclase.

9.1.6. Una tabla por cada clase concreta, usando polimorfismo implcito
Un enfoque alternativo es usar polimorfismo implcito:
<class name="CreditCardPayment" table="CREDIT_PAYMENT"> <id name="id" type="long" column="CREDIT_PAYMENT_ID"> <generator class="native"/>

103 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

</id> <property name="amount" column="CREDIT_AMOUNT"/> ... </class> <class name="CashPayment" table="CASH_PAYMENT"> <id name="id" type="long" column="CASH_PAYMENT_ID"> <generator class="native"/> </id> <property name="amount" column="CASH_AMOUNT"/> ... </class> <class name="ChequePayment" table="CHEQUE_PAYMENT"> <id name="id" type="long" column="CHEQUE_PAYMENT_ID"> <generator class="native"/> </id> <property name="amount" column="CHEQUE_AMOUNT"/> ... </class>

Ntese que no mencionamos explcitamente en ningn lado la interfaz Payment. Tambin ntese que las propiedades de Payment estn mapeadas en cada una de las subclases. Si se quiere evitar la duplicacin, considere usar entidades XML (por ejemplo, [ <!ENTITY allproperties SYSTEM "allproperties.xml"> ] en la declaracin de DOCTYPE y &allproperties; en el mapeo). La desventaja de este enfoque, es que Hibernate no generar SQL UNIONs cuando ejecute consultas polimrficas. Segn esta estrategia de mapeo, una asociacin polimrfica a Payment sera normalmente mapeada usando <any>.
<any name="payment" meta-type="string" id-type="long"> <meta-value value="CREDIT" class="CreditCardPayment"/> <meta-value value="CASH" class="CashPayment"/> <meta-value value="CHEQUE" class="ChequePayment"/> <column name="PAYMENT_CLASS"/> <column name="PAYMENT_ID"/> </any>

9.1.7. Mezclar polimorfismo implcito con otras estrategias de mapeo de herencia


Hay una cosa ms que resaltar, acerca de este mapeo. Como cada una de las subclases est mapeada en su propio elemento <class> (y dado que Payment slo es una interfaz), cada una de las subclases podra fcilmente ser parte de otra jerarqua de clases! (y an se podran usar consultas polimrficas contra la interfaz Payment).
<class name="CreditCardPayment" table="CREDIT_PAYMENT"> <id name="id" type="long" column="CREDIT_PAYMENT_ID"> <generator class="native"/> </id> <discriminator column="CREDIT_CARD" type="string"/> <property name="amount" column="CREDIT_AMOUNT"/> ... <subclass name="MasterCardPayment" discriminator-value="MDC"/> <subclass name="VisaPayment" discriminator-value="VISA"/> </class> <class name="NonelectronicTransaction" table="NONELECTRONIC_TXN"> <id name="id" type="long" column="TXN_ID"> <generator class="native"/> </id> ... <joined-subclass name="CashPayment" table="CASH_PAYMENT"> <key column="PAYMENT_ID"/> <property name="amount" column="CASH_AMOUNT"/> ... </joined-subclass> <joined-subclass name="ChequePayment" table="CHEQUE_PAYMENT">

104 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

<key column="PAYMENT_ID"/> <property name="amount" column="CHEQUE_AMOUNT"/> ... </joined-subclass> </class>

De nuevo no necesitamos mencionar la interfaz Payment explcitamente. Hibernate devuelve automticamente instancias de, por ejemplo, CreditCardPayment y sus subclases, que tambin implementan Payment, pero no instancias de NonelectronicTransaction.

9.2. Limitaciones
Hay ciertas limitaciones del abordaje a la estrategia "una tabla por clase concreta" usando polimorfismo implcito. Y hay limitaciones un tanto menos restrictivas para los mapeos que usan <union-subclass>. Una comparacin de las limitaciones de ambas estrategias se muestra en la tabla siguiente: Tabla 9.1. Caractersticas de los mapeos de herencia polimrfica Estrategia de polimrfica polimrfica polimrfica de-muchosherencia de-muchos-a-uno de-uno-a-uno de-uno-a-muchos a-muchos una tabla por jerarqua de clase

load()/get()

polimrficos

<de-muchosa-uno>

<de-unoa-uno>

<de-unoa-muchos>

<de-muchoss.get(Payment.class, id) a-muchos>

una tabla por subclase una tabla por clase concreta (unionsubclass)

<de-muchosa-uno>

<de-unoa-uno>

<de-unoa-muchos>

<de-muchoss.get(Payment.class, id) a-muchos>

<de-muchosa-uno>

<de-unoa-uno>

<de-unoa-muchos> (for <de-muchoss.get(Payment.class, id) inverse="true" a-muchos>

only)

una tabla por clase <any> concreta (polimorfismo implcito)

not supported

not supported

<manyto-any>

s.createCriteria(Payment.class). Restrictions.idEq(id) ).uniqueResult()

Captulo 10. Trabajar con objetos


Hibernate es un dispositivo completo de mapeo objeto/relacional, que no slo escuda al programador contra los detalles de gestin del sistema de base de datos subyacente, sino que ofrece manejo del estado de sus objetos. Y sta es una forma muy natural de manejar la persistencia en una aplicacin de Java, al contrario de los comandos SQL en las capas usuales de persistencia JDBC/SQL. En otras palabras, los programadores en Hibernate siempre deberan pensar en trminos del estado de sus objetos, y no necesariamente en trminos de qu comandos SQL estn siendo ejecutados. De esto se encarga Hibernate, y slo es relevante para el programador cuando se trate de ajustar la perfomance del sistema.

10.1. Estados de un objeto de Hibernate


Hibernate define y soporta los siguientes estados de un objeto:

105 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

Transitorio (en ingls, transient): un objeto es transitorio cuando ha sido instanciado usando el operador new , y no est asociado con una sesin de Hibernate. No tiene representacin persistente en la base de datos y no se le ha asignado ningn identificador. Las instancias transitorias sern destruidas por el recolector de basura (garbage collector), si la aplicacin ya no tiene ninguna referencia a ellas. Use la sesin de Hibernate para volver persistente un objeto (y deje que Hibernate se encargue de los comandos SQL que sean necesarios para dicha transicin). Persistente (en ingls, persistent): una instancia persistente ya tiene una representacin en la base de datos, y un valor de identificador. Aunque recin haya sido cargada o grabada, por definicin ya est inscripta en el alcance de la sesin. Hibernate detectar cualquier cambio que se efecte sobre un objeto en estado persistente, y sincronizar su estado con el de la base de datos cuando la unidad de trabajo se complete. Si el objeto persistente es tranformado en transitorio, el programador no necesita ejecutar comandos UPDATE ni DELETE manualmente. Desprendido (en ingls, detached): un objeto desprendido es un objeto que era persistente, pero cuya sesin ha sido cerrada. La referencia al objeto an es vlida, y la instancia desprendida puede incluso ser modificada en este estado. Una instancia desprendida puede ser reasociada a una nueva sesin en el futuro, volvindola persistente de nuevo (junto con todas las modificaciones que haya sufrido). Esta caracterstica es ideal para programar unidades de trabajo largas, que necesiten darle a la aplicacin tiempo para "pensar". Las llamamos transacciones "de la aplicacin", esto es, una unidad del trabajo desde el punto de vista del usuario. Ahora discutiremos los estados y las transiciones entre ellos (as como los mtodos de Hibernate que disparan estas transiciones) con ms detalle.

10.2. Volver persistente un objeto


Las instancias recientemente creadas de una clase son consideradas transitorias por Hibernate. Podemos convertir una instancia transitoria en persistente asocindola con una sesin:
DomesticCat fritz = new DomesticCat(); fritz.setColor(Color.GINGER); fritz.setSex('M'); fritz.setName("Fritz"); Long generatedId = (Long) sess.save(fritz);

Si Cat tiene un identificador autogenerado, dicho identificador se genera y se le asigna a cat cuando save() sea llamado. Si Cat tiene un identificador asignado externamente, o una clave compuesta, dicho identificador debera serle asignado a cat antes de invocar save(). Se puede usar persist() em lugar de save(), con la semntica definida en el borrador temprano de EJB3.
persist() convierte una instancia transitoria en persistente. Pero no garantiza que el identificador le vaya a ser asignado a la instancia inmediatamente: la asignacin puede ocurrir al aplicrsele "flush" a la sesin. persist() tambin garantiza que nos ejecutar un comando INSERT si es llamado fuera de los lmites de una transaccin. Esto es til para conversaciones de largo aliento, con un contexto de sesin/persistencia extendido. save() s garantiza la devolucin de un identificador, Si hay que ejecutar un INSERT (por ejemplo, porque el generador es "identity" y no "sequence") el INSERT ocurre inmediatamente, sin importar si se est dentro o fuera de una transaccin. Esto es indeseable en conversaciones largas, con un contexto de sesin/persistencia extendido.

Alternativamente, se puede asignar el identificador usando una versin sustituida (overloaded) de of save().
DomesticCat pk = new DomesticCat(); pk.setColor(Color.TABBY); pk.setSex('F'); pk.setName("PK"); pk.setKittens( new HashSet() ); pk.addKitten(fritz); sess.save( pk, new Long(1234) );

Si el objeto que se hace persistente tiene objetos asociados, (por ejemplo, la coleccin "kittens", gatitos, en el ejemplo anterior), dichos objetos pueden ser hechos persistentes en cualquier orden, a menos que exista una constraint NOT NULL en una columna de clave fornea. El riesgo de violar una constraint de clave fornea no existe, pero s se puede llegar a violar una constraint NOT NULL si se les aplica save() a los objetos en el orden incorrecto. Normalmente, usted no debe preocuparse por estos detalles, dado que, muy probablemente, usted terminar usando la caracterstica de Hibernate llamada persistencia transitiva para grabar los objetos asociados automticamente. Con ella, ni siquiera las violaciones de NOT NULL ocurren, Hibernate se hace cargo de todo. La persistencia transitiva se discute ms

106 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

adelante en este captulo.

10.3. Cargar un objeto


El mtodo load() de Session provee una manera de capturar una instancia persistente, si ya se conoce su identificador. load() acepta un objeto Class, y cargar el estado en una nueva instancia de esa clase, inicializada en el momento, en estado persistente.
Cat fritz = (Cat) sess.load(Cat.class, generatedId); // se necesita "envolver" los identificadores de tipos primitivos long id = 1234; DomesticCat pk = (DomesticCat) sess.load( DomesticCat.class, new Long(id) );

Alternativamente, se puede cargar estado en una instancia ya existente:


Cat cat = new DomesticCat(); // cargar el estado identificado por la clave primaria en Cat sess.load( cat, new Long(pkId) ); Set kittens = cat.getKittens();

Dese cuenta de que load() lanzar una excepcin irrecuperable si no existe la fila de base de datos correspondiente. Si la clase es mapeada con un proxy, load() simplemente devuelve un proxy no inicializado, y no hay contacto con la base de datos hasta que realmente se invoque un mtodo del proxy. Este comportamiento es muy til si se desea crear una asociacin con un objeto, sin realmente cargarlo desde la base de datos. Tambin permite cargar mltiples instancias en lotes, si batch-size est definido para la clase. Cuando no se est seguro de que exista una fila correspondiente, debera usarse el mtodo get(), el cual consulta la base de datos inmediatamente y devuelve null si no existe una fila correspondiente.
Cat cat = (Cat) sess.get(Cat.class, id); if (cat==null) { cat = new Cat(); sess.save(cat, id); } return cat;

Incluso se puede cargar un objeto usando un SQL SELECT ... FOR UPDATE, usando LockMode. Vea la documentacin de la API para ms informacin.
Cat cat = (Cat) sess.get(Cat.class, id, LockMode.UPGRADE);

Note que ni las instancias asociadas ni las colecciones contenidas son seleccionadas FOR UPDATE (con el propsito de ser modificadas), a menos que se especifiquen los valores lock o all en el parmetro de mapeo "cascade". Se puede recargar un objeto y todas sus asociaciones an cualquier momento, usndo el mtodo refresh(). Esto es muy til cuando se estn usando triggers de DB para inicializar algunas de las propiedades del objeto.
sess.save(cat); sess.flush(); //fuerza el SQL INSERT sess.refresh(cat); //relee el estado (luego de que el trigger se ejecuta)

Llegados a este punto,usualmente se plantea una cuestin: Cunto carga Hibernate de la base de datos?Cuntos SQL SELECTs se usan? Esto depende de la estrategia de captura (fetching strategy) y se explica en la Seccin 19.1, Estrategias de captura (fetch).

10.4. Consultas
Si no se conocen los identificadores de los objetos que se est buscando, se necesita una consulta (query). Hibernate soporta un lenguaje para consultas poderoso pero fcil de usar: HQL (las siglas en ingls de "Hibernate Query Language"). Para la creacin programtica de consultas, Hibernate soporta dos clases muy sofisticadas, Criteria y Example (a veces referidos como QBC y QBE, por "query by criteria" y "query by example", respectivamente). Tambin se puede expresar la consulta en el lenguaje nativo de su base de datos, con soporte opcional de conversin de su resultado en objetos.

107 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

10.4.1. Ejecutar consultas


Las consultas en HQL y en SQL nativo son representadas por una instancia de org.hibernate.Query. Esta interfaz ofrece mtodos para vincular parmetros, manejo de resultsets, y la ejecucin de la consulta misma. Siempre se obtiene el Query a partir la sesin actual.
List cats = session.createQuery( "from Cat as cat where cat.birthdate < ?") .setDate(0, date) .list(); List mothers = session.createQuery( "select mother from Cat as cat join cat.mother as mother where cat.name = ?") .setString(0, name) .list(); List kittens = session.createQuery( "from Cat as cat where cat.mother = ?") .setEntity(0, pk) .list(); Cat mother = (Cat) session.createQuery( "select cat.mother from Cat as cat where cat = ?") .setEntity(0, izi) .uniqueResult();]] Query mothersWithKittens = (Cat) session.createQuery( "select mother from Cat as mother left join fetch mother.kittens"); Set uniqueMothers = new HashSet(mothersWithKittens.list());

Una consulta normalmente se ejecuta invocando list(), el resultado de la consulta ser cargado completamente en una coleccin en memoria. Las entidades de instancia que son devueltas estn en estado persistente. El mtodo uniqueResult() ofrece un atajo si usted ya sabe que la consulta devolver un solo objeto. Note que las consultas que hacen uso de "captura ansiosa" (eager fetching), normalmente devuelven duplicados del objeto raz, con sus colecciones inicializadas. Estos duplicados se pueden eliminar, simplemente usando un Set.

10.4.1.1. Iterar resultados


Ocasionalmente, es posible que se obtenga una mejor performace si se ejecuta la consulta usando el mtodo iterate(). Esto es normalmente cierto si se espera que las instancias de entidad devueltas por la consulta ya estarn en la sesin, o en el cach de 2do nivel. Si no estn en el cach, iterate() ser ms lento que list(), y es posible que requiera varios viajes a la base de datos para una simple consulta: normalmente 1 SELECT inicial que slo devuelve los identificadores, y N SELECTs adicionales que inicializan las instancias propiamente dichas.
// captura de ids Iterator iter = sess.createQuery("from eg.Qux q order by q.likeliness").iterate(); while ( iter.hasNext() ) { Qux qux = (Qux) iter.next(); // captura de un objeto // alguna comprobacin complicada que no podamos expresar en la consulta if ( qux.calculateComplicatedAlgorithm() ) { // borrar la isntancia actual iter.remove(); // no necesitamos procesar el resto break; } }

10.4.1.2. Consultas que devuelven T-uplas


Las consultas de Hibernate a veces devuelven t-uplas de objetos, en cuyo caso cada t-upla se devuelve como un array.
Iterator kittensAndMothers = sess.createQuery( "select kitten, mother from Cat kitten join kitten.mother mother") .list() .iterator(); while ( kittensAndMothers.hasNext() ) { Object[] tuple = (Object[]) kittensAndMothers.next();

108 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

Cat kitten = (Cat) tuple[0]; Cat mother = (Cat) tuple[1]; .... }

10.4.1.3. Resultados escalares


Una consulta pueden especificar una propiedad de la clase en la clusula SELECT. Las funciones agregadas son consideradas resultados "escalares", y no entidades en estado persistente.
Iterator results = sess.createQuery( "select cat.color, min(cat.birthdate), count(cat) from Cat cat " + "group by cat.color") .list() .iterator(); while ( results.hasNext() ) { Object[] row = (Object[]) results.next(); Color type = (Color) row[0]; Date oldest = (Date) row[1]; Integer count = (Integer) row[2]; ..... }

10.4.1.4. Parmetros vinculados


En Query se proveen mtodos para vincular valores con parmetros nombrados, o parmetros ? al estilo JDBC. Al contrario que con JDBC, Hibernate numera los parmetros empezando de 0. Los parmetros nombrados son identificadores con la forma :name en la caden de la consulta. Las ventajas de los parmetros nombrados son: los parmetros nombrados son independientes del orden en que ocurren en la cadena de la consulta pueden ocurrir varias veces en la misma consulta son autodocumentados
//parmetro nombrado (la forma preferida) Query q = sess.createQuery("from DomesticCat cat where cat.name = :name"); q.setString("name", "Fritz"); Iterator cats = q.iterate(); //parmetro posicional Query q = sess.createQuery("from DomesticCat cat where cat.name = ?"); q.setString(0, "Izi"); Iterator cats = q.iterate(); //lista de parmetros nombrada List names = new ArrayList(); names.add("Izi"); names.add("Fritz"); Query q = sess.createQuery("from DomesticCat cat where cat.name in (:namesList)"); q.setParameterList("namesList", names); List cats = q.list();

10.4.1.5. Paginacin
Si se necesita establecer lmtes en el resultset (el mximo nmero de filas que se quiere capturar / desde qu fila se desea obtener datos), deberan usarse los siguientes mtodos de la interfaz Query:
Query q = sess.createQuery("from DomesticCat cat"); q.setFirstResult(20); q.setMaxResults(10); List cats = q.list();

Hibernate sabe cmo traducir este lmite al el SQL nativo de su base de datos.

109 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

10.4.1.6. Iteracin navegable


Si su driver de JDBC soporta ResultSets navegables, la interfaz Query puede ser usada para obtener un objeto ScrollableResults, el cual permite una navegacin flexible del los resultados de la consulta.
Query q = sess.createQuery("select cat.name, cat from DomesticCat cat " + "order by cat.name"); ScrollableResults cats = q.scroll(); if ( cats.first() ) { // encuentra el primer nombre en cada pgina de una lista alfabtica de gatos, por nombre. firstNamesOfPages = new ArrayList(); do { String name = cats.getString(0); firstNamesOfPages.add(name); } while ( cats.scroll(PAGE_SIZE) ); // ahora obtiene la primera pgina de gatos pageOfCats = new ArrayList(); cats.beforeFirst(); int i=0; while( ( PAGE_SIZE > i++ ) && cats.next() ) pageOfCats.add( cats.get(1) ); } cats.close()

Ntese que para esta funcionalidad se requiere una conexin abierta a la base de datos. y un cursor. Use setMaxResult()/setFirstResult() si necesita funcionalidad de paginacin desconectada.

10.4.1.7. Externalizar consultas nombradas


Se puede definir consultas nombradas (named queries) en el documento de mapeo. Recuerde usar una seccin CDATA si su consulta contiene carateres que podran ser interpretados como caracteres reservados de XML).
<query name="ByNameAndMaximumWeight"><![CDATA[ from eg.DomesticCat as cat where cat.name = ? and cat.weight > ? ] ]></query>

La vinculacin de parmetros y la ejecucin se hacen programticamente.


Query q = sess.getNamedQuery("ByNameAndMaximumWeight"); q.setString(0, name); q.setInt(1, minWeight); List cats = q.list();

Note que el cdigo del programa propiamente dicho es independiente del lenguaje de consultas que se use; se pueden definir consultas SQL nativas en metadata, o migrar consultas existentes a Hibernate colocndolas en archivos de mapeo. Tambin note que la declaracin dentro de un elemento <hibernate-mapping> requiere un nombre globalmente nico para la consulta, mientras que la declaracin de una consulta dentro de un elemento <class> se vuelve nica automticamente al afijarle el nombre enteramente calificado de la clase, por ejemplo, eg.Cat.PorNombreYPesoMaximo.

10.4.2. Filtrar colecciones


El filtro de una coleccin es un tipo especial de consulta que puede aplicrsele a una coleccin persistente, o a un array. La cadena de la consulta puede hacer uso de this, refirindos el elemento actual de la coleccin.
Collection blackKittens = session.createFilter( pk.getKittens(), "where this.color = ?") .setParameter( Color.BLACK, Hibernate.custom(ColorUserType.class) ) .list() );

110 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

La coleccin devuelta se considera una bag, y es una copia de a coleccin dada. La coleccin original no es modificada (lo cual es conceptualmente opuesto a la idea de un "filtro", pero consistente en cuanto al resultado que se espera). Observe que los filtros no requieren una clusula FROM (aunque pueden tenerla si es necesario). Los filtros no estn limitados a devolver los elementos de colecciones mismos.
Collection blackKittenMates = session.createFilter( pk.getKittens(), "select this.mate where this.color = eg.Color.BLACK.intValue") .list();

Incluso un filtro con su consulta vaca es til, por ejemplo para cargar un subconjunto de elementos en una coleccin enorme:
Collection tenKittens = session.createFilter( mother.getKittens(), "") .setFirstResult(0).setMaxResults(10) .list();

10.4.3. Consultas "Criteria"


HQL es extremadamente poderoso, pero algunos programadores prefieren ir construyendo sus consultas dinmicamente, usando una API orientada a objetos, en lugar de utilidar cadenas. Hibernate provee una API intuitiva, Criteria, para estos casos:
Criteria crit = session.createCriteria(Cat.class); crit.add( Restrictions.eq( "color", eg.Color.BLACK ) ); crit.setMaxResults(10); List cats = crit.list();

Las APIs de Criteria y su pariente Example se discuten con ms detalle en Captulo 15, Consultas Criteria.

10.4.4. Consultas en SQL nativo


Se puede expresar una consulta en SQL, usando createSQLQuery() y dejar que Hibernate se haga cargo del mapeo del resultset a objetos. Note que en cualquier momento se puede llamar session.connection() y usar la Connection de JDBC directamente. Si decide usar la API de Hibernate, debe incluir los alias de SQL entre llaves:
List cats = session.createSQLQuery("SELECT {cat.*} FROM CAT {cat} WHERE ROWNUM<10") .addEntity("cat", Cat.class) .list(); List cats = session.createSQLQuery( "SELECT {cat}.ID AS {cat.id}, {cat}.SEX AS {cat.sex}, " + "{cat}.MATE AS {cat.mate}, {cat}.SUBCLASS AS {cat.class}, ... " + "FROM CAT {cat} WHERE ROWNUM<10") .addEntity("cat", Cat.class) .list()

Las consultas SQL pueden contener parmetros nombrados o posicionales, al igual que las consultas de Hibernate. Se puede encontrar ms informacin sobre las consultas SQL nativas en Captulo 16, SQL Nativo.

10.5. Modificar objetos persistentes


Las instancias persistentes transaccionales (esto es, los objetos cargados, grabados, creados o consultados por las sesin) pueden ser manipulados por la aplicacin, y cualquier cambio a su estado de persistencia ser persistido cuando se le aplique "flush" a la sesin (como se discute ms adelante en este captulo). No hay necesidad de invocar ningn mtodo en particular (como por ejemplo update(), que sirve para otra cosa) para que las modificaciones se vuelvan persistentes. As que la manera ms sencilla y directa de actualizar el estado de un objeto es cargarlo con load(), y luego manipularlo directamente, mientras la sesin est abierta.
DomesticCat cat = (DomesticCat) sess.load( Cat.class, new Long(69) ); cat.setName("PK"); sess.flush(); // los cambios se detectan y son persistidos automticamente

111 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

A veces, este modelo de programacin es ineficiente, dado que requerira tanto un SQL SELECT (para cargar el objeto) como un SQL UPDATE (para persistir su estado modificado) en la misma sesin. Por lo tanto, Hibernate ofrece un abordaje alternativo, usando instancias desprendidas: Note que Hibernate no expone una API propia para ejecutar comandos UPDATE o DELETE directamente. Hibernate es un servicio de manejo de persistencia, y no se lo debe concebir en trminos de qu comandos ejecuta. JDBC es una API perfectamente adecuada para ejecutar comandos SQL, se puede obtener una conexin de JDBC en cualquier momento invocando session.connection(). Ms an, la nocin de "operaciones en masa" entra en conflicto con el mapeo objeto/relacional para las aplicaciones orientadas al procesamiento de transacciones en lnea. Puede ser, sin embargo, que versiones futuras de Hibernate provean funciones especiales para procesamiento en masa. Vase Captulo 13, Procesamiento en lotes para posibles trucos de operacin en lote.

10.6. Modificar objetos desprendidos


Muchas aplicaciones necesitan capturar un objeto en una transaccin, mandarlo a la capa de interfaz de usuario para su manipulacin, y grabar sus cambios en una nueva transaccin. Las aplicaciones que usan este tipo de estrategia en entornos de alta concurrencia, normalmente usan datos versionados para garantizar aislamiento durante la "larga" unidad de trabajo. Hibernate soporta este modelo, proveyendo "reasociacin" de entidades desprendidas usando los mtodos Session.update() o Session.merge():
// en la primera sesin Cat cat = (Cat) firstSession.load(Cat.class, catId); Cat potentialMate = new Cat(); firstSession.save(potentialMate); // en una capa ms alta de la aplicacin cat.setMate(potentialMate); //mate=pareja // luego, en una nueva sesin secondSession.update(cat); // actualiza cat secondSession.update(mate); // actualiza mate

Si el Cat con identificador catId ya hubiera sido cargado por la segunda sesin (secondSession) cuando la sesin trataba de reasociarlo, se habra producido una excepcin. Use update() si usted est seguro de que la sesin no contiene una instancia que ya es persistente con el mismo id, merge() si usted desea consolidar sus modificaciones en cualquier momento, independientemente del estado de esa instancia en la sesin. En otras palabras, update() es normalmente el primer mtodo que se invocar en una sesin nueva, garantizando que la reasociacin de las instancias desprendidas sea la primera operacin que ocurra. La aplicacin debera aplicarles update() a las instancias desprendidas dependientes de la instancia desprendida en cuestin, si y slo si desea que su estado tambin sea actualizado. Esto puede ser automatizado, por supuesto, usando persistencia transitiva, vea la Seccin 10.11, Persistencia transitiva. El mtodo lock() tambin le permite a la aplicacin reasociar un objeto con una sesin nueva. Sin embargo, la instancia desprendida no debe haber sido modificada!
//simplemente reasocia sess.lock(fritz, LockMode.NONE); //primero verifique la versin, luego reasocie sess.lock(izi, LockMode.READ); //primero verifique la versin usando SELECT ... FOR UPDATE, luego reasocie sess.lock(pk, LockMode.UPGRADE);

Note que lock() puede ser usado con varios LockModes, vea la documentacn de la API y el captulo sobre manejo de transacciones para ms informacn. Reasociar no es el nico uso que lock() tiene. Otros modelos para unidades largas de trabajo se discuten en Seccin 11.3, Control de concurrencia optimista.

10.7. Deteccin de estado automtica


Los usuarios de Hibernate han solicitado un mtodo de uso general, que o bien grabe una instancia transitoria (generando

112 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

un identificador nuevo), o bien actualice/reasocie las instancias desprendidas asociadas con el identificador actual. El mtodo saveOrUpdate() implementa tal funcionalidad:
// en la primera sesin Cat cat = (Cat) firstSession.load(Cat.class, catID); // en una capa ms alta de la aplicacin Cat mate = new Cat(); cat.setMate(mate); // luego, en una nueva sesin secondSession.saveOrUpdate(cat); secondSession.saveOrUpdate(mate);

// actualice el estado existente (cat tiene un id no nulo) // grabe la instancia nueva (mate tiene un id nulo)

El uso y semntica de saveOrUpdate() les parece confuso a los nuevos usuarios. En primer lugar, a menos que se est intentando usar instancias de una sesin en otra sesin nueva, no hay necesidad de usar update(), saveOrUpdate(), ni merge(). Hay aplicaciones enteras que jams utilizarn ninguno de estos mtodos. Usualmente, update() o saveOrUpdate() se usan en el siguiente escenario: la aplicacin carga un objeto en la primera sesin el objeto es pasado a la capa de interfaz de usuario se le hacen algunas modificaciones al objeto el objeto baja de nuevo a la capa de lgica de negocios la aplicacin persiste estas modificaciones invocando update() en una segunda sesin
saveOrUpdate() hace

lo siguiente

si el objeto ya es persistente en esta sesn, no hace nada si ya hay otro objeto asociado con la sesin con el mismo identificador, se produce una excepcin si el objeto no tiene una valor de identificador, se invoca save() si el identificador del objeto es asignable, y le ha sido recientemente asignado a una instancia recin creadam se invoca save(). si el objeto es versionado (por una <version> o <timestamp>), y la propiedad versin es el mismo valor asignado a un objeto recin instanciado, se invoca save() en cualquier otro caso, se invoca update() y merge() es muy distinto si ya hay una instancia persistente con el mismo identificador asociada con la sesin, copia el estado del objeto dado en la instancia persistente. si no hay ninguna instancia asociada con la sesin, intenta cargarla de la base de datos, o crear una nueva instancia persistente. se devuelve la instancia persistente la instancia dada (como parmetro) no se vuelve asociada con la sesin, permanece desprendida.

10.8. Borrar objetos persistentes


Session.delete() quitar el estado de un objeto de la base de datos. Por supuesto, su aplicacin podra an contener una referencia al objeto quitado. Es mejor pensar que delete() est convirtiendo una instancia persistente en transitoria. sess.delete(cat);

Se puede borrar objetos en cualquier orden que se desee, sin temor de causar violaciones de clave fornea. Pero s es

113 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

posible violar constraints NOT NULL aplicadas a la columna de clave fornea, por ejemplo si se borra al padre antes que al hijo.

10.9. Replicar un objeto entre dos repositorios de datos distintos


Ocasionalmente, es til poder tomar un rbol de instancias persistentes y hacerlas persistentes en otro repositorio de datos distinto, sin tener que regenerar los valores de los identificadores.
//obtener un cat de la base de datos Session session1 = factory1.openSession(); Transaction tx1 = session1.beginTransaction(); Cat cat = session1.get(Cat.class, catId); tx1.commit(); session1.close(); //reconciliar con la segunda base de datos Session session2 = factory2.openSession(); Transaction tx2 = session2.beginTransaction(); session2.replicate(cat, ReplicationMode.LATEST_VERSION); tx2.commit(); session2.close();

El ReplicationMode determina cmo el mtodo replicate() lidiar con conflictos que puedan existir con filas existentes en la base de datos.
ReplicationMode.IGNORE: ignorar

el objeto cuando exista una fila de base de datos con el mismo identificador. fila existente en la base de datos que tenga el mismo

ReplicationMode.OVERWRITE: sobrescribir cualquier

identificador.
ReplicationMode.EXCEPTION: lanzar una

excepcin si ya existe una fila en la base de datos que tenga el mismo fila si su nmero de versin es ms antiguo que el del objeto.

identificador.
ReplicationMode.LATEST_VERSION: sobrescribir la

En caso contrario, ignorar. Algunos casos de uso para esta caracterstica incluyen: reconciliar datos ingresados en dos instancias distintas de base de datos, actualizar la informacin de configuracin del sistema durante la actualizacin de un producto, dar marcha atrs (rollback) con cambios hechos durante transacciones carentes de integridad transaccional (non-ACID), y muchos ms.

10.10. "Flush" de la sesin


De tanto en tanto la sesin ejecutar los comandos SQL que sean necesarios para sincronizar el estado de la conexin JDBC con el estado de los objetos mantenidos en la memoria. Este proceso llamado el "nivelado" o "desagote" de la sesin (en ingls, flush), ocurre por defecto en los siguientes puntos: antes de algunas ejecuciones de consultas en org.hibernate.Transaction.commit() en Session.flush() Los comandos SQL son ejecutados en el siguiente orden todas las inserciones de entidades, en el mismo orden en que los objetos hayan sido grabados con Session.save() todas las actualizaciones a entidades todos los borrados de colecciones todos los borrados, modificaciones e inserciones de elementos en las colecciones todas las inserciones de colecciones todos los borrados de entidades, en el mismo orden en que los objetos hayan sido borrados usando

114 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

Session.delete()

(una excepcin es que los objetos que usen la generacin de identificador native sern insertados al invocar save). A excepcin de cuando se invoque flush() explcitamente, no hay absolutamente ninguna garanta acerca de cundo los llamados JDBC sern ejecutados por la sesin, slo acerca del orden en que sern ejecutados. Sin embargo, Hibernate garantiza que Query.list(..) nunca devolver datos rancios. Es posible cambiar el comportamiento por defecto para que el "flush" ocurra menos frecuentemente. La clase FlushMode define tres modos diferentes: slo provocar el "flush" al momento de llamar "commit" (y esto slo en una transaccin de la API de Hibernate), provocar el "flush" automticamente usando la rutina explicada, o nunca provocar el "flush" menos que flush() sea invocado explcitamente. Este ltimo modo es til para unidades de trabajo largas, en donde la sesin se mantiene abierta y desconectada por largo tiempo (vase la Seccin 11.3.2, Sesin extendida y versionado automtico).
sess = sf.openSession(); Transaction tx = sess.beginTransaction(); sess.setFlushMode(FlushMode.COMMIT); // permite que las consultas devuelvan datos rancios Cat izi = (Cat) sess.load(Cat.class, id); izi.setName(iznizi); // podra devolver datos rancios sess.find("from Cat as cat left outer join cat.kittens kitten"); // el cambio a izi no ha tenido "flushing"! ... tx.commit(); // flush occurs sess.close();

Durante el "flush", puede ocurrir una excepcin (por ejemplo, si una operacin de creacin de datos viola una constraint). Como el manejar excepciones involucra algn conocimiento del comportamiento transaccional de Hibernate, lo discutiremos en el Captulo 11, Transacciones y concurrencia.

10.11. Persistencia transitiva


Es bastante engorroso grabar, borrar o reasociar objetos individuales, especialmente si se est lidiando con un rbol de objetos asociados. Un caso comn es el de la relacin padre/hijo. Considere el siguiente ejemplo: Si los hijos en una relacin padre/hijo fuesen de la ndole "value type" (por ejemplo una coleccin de direcciones, o de cadenas), su ciclo de vida dependera del padre, y no hara falta hacer nada para que la propagacin en cascada se efectuare de manera adecuada ante cambios de estado. Cuando el padre es grabado, los hijos "value type" son grabados tambin; cuando se borra al padre, a los hijos tambin, etc. Esto inclusive funciona para operaciones como el borrado de un hijo de una coleccin: Si un "value type" hijo es borrado de una coleccin, como los "value types" no pueden tener referencias compartidas, ya no tiene razn se ser, e Hibernate lo borrar de la base de datos. Ahora considere el mismo escenario, pero con objetos padre e hijos siendo entidades, no "value types" (por ejemplo, categoras e items, o gata y gatitos). Las entidades tienen su propio ciclo de vida, soportan referencias compartidas (as que quitar a una referncia de una coleccin no significa que pueda ser borrada), y por defecto no hay propagacin en cascada de una entidad a sus entidades asociadas. Hibernate no implementa el el concepto de persistir todo lo que est al alcance (persistence by reachability) por defecto. Para cada operacin bsica de la sesin de Hibernate, incluyendo: persist(), merge(), saveOrUpdate(), delete(), lock(), refresh(), evict(), replicate() hay un estilo de propagacin en cascada correspondiente. Se se quiere que una operacin sea propagada en cascada en la direccin de una asociacin, eso se debe indicar en el documento de mapeo. Por ejemplo:
<one-to-one name="person" cascade="persist"/>

Los estilos de propagacin en cascada pueden ser combinados.


<one-to-one name="person" cascade="persist,delete,lock"/>

Incluso se puede usar cascade="all" para indicar que todas las operaciones deben ser propagadas en direccin de esa asociacin. El valor por defecto, cascade="none", especifica que ninguna operacin debe ser propagada.

115 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

Un tipo especial de propagacin en cascada, delete-orphan, se aplica slo a las asociaciones de-uno-a-muchos, e indica que la operacin delete() debe ser aplicada a cualquier hijo cuyo padre haya sido borrado. Recomendaciones:
to-many>.

Normalmente no tiene sentido habilitar la propagacin en cascada para asociaciones <many-to-one> o <manyLa propagacin es usualmente til para asociaciones <one-to-one> y <one-to-many>.

Si el ciclo del vida del hijo est ligado al del padre, convirtalo en un objeto de ciclo de vida especificando cascade="all,delete-orphan". En cualquier otro caso, puede que usted no necesite usar cascade en absoluto. Pero si usted calcula que deber trabajar a menudo con el padre y los hijos en la misma transaccin, y quiere ahorrarse algo de tecleo, considere usar cascade="persist,merge,save-update". Mapear una asociacin (ya sea de un solo valor, o de una coleccin) con cascade="all" marca la asociacin como "del estilo padre/hijo", en donde una grabacin/actualizacin/borrado del padre resulta en una grabacin/actualizacin/borrado de los hijos. Ms an, una mera referencia a un hijo desde un padre persistente resultar en la grabacin/actualizacin del hijo. Lo inverso no se da, sin embargo. Un hijo a quien el padre deje de hacer referencia no es automticamente borrado, excepto en el caso de una asociacin de-uno-a-muchos mapeada con cascade="delete-orphan". La semntica exacta de la relacin padre/hijo es como sigue: Si se le pasa un padre (como parmetro) a un persist(), todos sus hijos sern tambin pasados a persist() Si se le pasa un padre a un merge(), todos sus hijos sern tambin pasados a merge() Si se le pasa un padre a un save(), update() o saveOrUpdate(), todos sus hijos sern tambin pasados a saveOrUpdate(). Si un hijo transitorio o desprendido empieza a ser referido por un padre persistente, se le pasa a saveOrUpdate() si un padre es borrado, todos sus hijos le son pasados a delete() Si un hijo deja de ser referido por un padre persistente, no pasa nada en especial: la aplicacin debera borrar el hijo explcitamente si hace falta (a menos que haya cascade="delete-orphan", en cuyo caso la clase el hijo que se ha vuelto hurfano ser borrado). Por ltimo, note que la propagacin de operaciones en cascada se le puede aplicar a un objeto al momento de invocarlo o al momento de efectuar "flush". Todas las operaciones, si estn habilitadas, se propagan en cascada hacia todas las entidades que estn a su alcance cuando la operacin es ejecutada. Sin embargo, save-upate y delete-orphan son transitivas hacia las entidades asociadas cuando ocurre el "flush" de la sesin.

10.12. Usar metadatos


Hibernate requiere un modelo muy frondoso, a un meta-nivel, de todas sus entidades y "value-types". De tanto en tanto, este modelo le es muy til a la aplicacin misma. Por ejemplo, la aplicacin podra usar los metadatos de Hibernate para implementar un algoritmo inteligente de "copia profunda" (deep copy) que entienda cules objetos deben ser copiados (por ejemplo, "value types" mutables) y cules no (por ejemplo, "value types" inmutables y, posiblemente, entidades asociadas). Hibernate expone metadatos mediante las interfaces ClassMetadata y CollectionMetadata, y la jerarqua de Type. Instancias de las interfaces de metadatos se obtienen de la SessionFactory.
Cat fritz = ......; ClassMetadata catMeta = sessionfactory.getClassMetadata(Cat.class); Object[] propertyValues = catMeta.getPropertyValues(fritz); String[] propertyNames = catMeta.getPropertyNames(); Type[] propertyTypes = catMeta.getPropertyTypes(); // obtiene un Map de todas las propiedades que no sean colecciones o asociaciones Map namedValues = new HashMap(); for ( int i=0; i<propertyNames.length; i++ ) { if ( !propertyTypes[i].isEntityType() && !propertyTypes[i].isCollectionType() ) {

116 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

namedValues.put( propertyNames[i], propertyValues[i] ); } }

Captulo 11. Transacciones y concurrencia


El punto ms importante acerca de Hibernate y el control de concurrencia, es que es muy fcil de entender. Hibernate usa directamente las conecciones JDBC y los recursos de JTA sin agregar ningn mecanismo adicional de "locking". Le recomendamos que pase un buen tiempo revisando la documentacin sobre JDBC, ANSI, y cmo funciona el aislamiento de transacciones en su base de datos en particular. Hibernate no efecta "lock" de objetos en memoria. Si aplicacin puede esperar el comportamiento que est definido por el nivel de aislamiento de sus transacciones de base de datos. Note que, gracias a la sesin, que es tambin un cach con alcance a la transaccin, Hibernate provee lecturas repetibles para la bsqueda por identificadores, y consultas de entidad (no consultas "de reporte" que devuelvan valores escalares). Adems de versionar para lograr un control de concurrencia optimista, Hibernate tambin ofrece una API (mnima) para efectuar un "lock" de filas pesimista, usando la sintaxis SELECT FOR UPDATE. El control de concurrencia optimista, y esta API, se discuten ms adelante en este captulo. Comenzaremos la discusin sobre el control de concurrencia en Hibernate involucrando los conceptos de configuracin (Configuration), la fbrica de sesiones (SessionFactory), y la sesin, as como las transacciones de base de datos y las conversaciones largas.

11.1. La sesin y el alcance (scope) de las transacciones


La fbrica de sesiones (SessionFactory) es un objeto seguro en cuanto al acceso por threads mltiples (thread-safe), y es costosa de crear. Se la concibi para ser compartida por todos los threads de la aplicacin. Se la crea una sola vez, normalmente durante el arranque de la aplicacin, a partir de una instancia de Configuration. Una sesin individual (Session), en cambio, es barata de crear, y no es segura en cuanto al acceso por mltiples threads (no es "threadsafe"). Se espera que sea usada una sola vez, para una interaccin simple o "request" (una sola solicitud, una sola "conversacin" o "unidad de trabajo"), y luego sea descartada. Una sesin no intentar obtener una conexin de JDBC, ni una fuente de datos (Connection, Datasource) a menos que sea necesario. Por lo tanto, no consume recursos mientras no es usada. Para completar este panorama se debe pensar tambin en las transacciones de base de datos. Una transaccin de base de datos debe ser lo ms corta posible, para reducir las posibilidades de conflictos de "lock" en la base de datos. Las transacciones largas impiden que la aplicacin sea "escalable" (es decir, que se adapte con facilidad a una mayor demanda y tamao), por no poder soportar una mayor carga de demandas concurrentes. Por tal motivo, mantener una transaccin abierta mientras el usuario "piensa" y hasta que la unidad de trabajo se complete, casi nunca es una buena idea. Cul es el alcance de una unidad de trabajo? Una simple sesin de Hibernate puede abarcar varias transacciones de base de datos, o sus alcances son similares y con una relacin uno a uno? Cundo se debe abrir y cerrar una sesin, y cmo se demarcan los lmites de una transaccin de base de datos?

11.1.1. Unidad de trabajo


Antes que nada, no emplee la prctica desaconsejada (antipattern) de una-sesin-por-operacin, es decir, no abra y cierre una sesin para cada llamado a la base de datos en un mismo thread! En una aplicacin, los llamdos a la base de datos son hechos en un orden planificado, y son agrupados en unidades de trabajo atmicas. (Ntese que esto tambin significa que tener la conexin en auto-commit despus de cada comando SQL es intil en una aplicacin, esta modalidad de trabajo es ms acorde con trabajo ad-hoc en una consola SQL. Hibernate inhabilita el auto-commit inmediatamente, o espera que el servidor de aplicaciones lo haga). Las transacciones de base de datos nunca son opcionales, toda comunicacin con la base de datos debe ocurrir dentro de una transaccin, ya sea para escribir o para leer datos. Como se dijo anteriormente, el comportamiento "auto-commit" debe evitarse, dado que es improbable que un conjunto de muchas pequeas transacciones tenga mejor performance que una unidad de trabajo claramente definida. Esta ltima es tambin ms flexible y extensible. El patrn ms comn, en una aplicacin cliente/servidor multiusuario, es "una sesin por cada solicitud" (sessionper-request) . Segn este modelo, una solicitud o "request" del cliente se enva al servidor (en donde est ejecutndose la

117 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

capa de persistencia Hibernate), se abre una nueva sesin, y todas las operaciones de base de datos son ejecutadas e esta unidad de trabajo. Una vez que el trabajo se haya completado (y la respuesta para el cliente se haya preparado), la sesin sufre un "flush" y se cierra. Tambin se usara una sola transaccin de base de datos para atender la solicitud del cliente, comenzndola y efectuando "commit" cuando se abra y cierre la conexin, respectivamente. La relacin entre sesin y transaccin es una a una, y este modelo es perfectamente adecuado para muchas aplicaciones. El desafo radica en la implementacin. Hibernate ya trae un sistema incluido que se puede usar para simplificar el uso de este patrn, y manejar lo que se considera la "sesin actual". Todo lo que el programador debe hacer, es comenzar una transaccin cuando haya que procesar una solicitud (request) al servidor, y finalizar la transaccin antes de que la respuesta le sea enviada al cliente. Esto se puede lograr de varias maneras: las soluciones ms comunes son: -un filtro (ServletFilter) -un interceptor basado en AOP, que tenga sus "pointcuts" en los mtodos del servicio, -un contenedor de proxies/intercepciones, etc. Una manera estndar de implementar aspectos que conciernen de una misma forma a varios niveles y reas de la aplicacin (en ingls, "cross-cutting aspects"), es usar un contenedor de EJB, el cual puede implementar transacciones de una manera declarativa y manejada por el contenedor mismo (CMT). Si se decide usar la demarcacin de transacciones programtica, prefirase la API de Transaction de Hibernate, que es fcil y porttil. El cdigo de su aplicacin puede acceder a la "sesin actual" para procesar una request, simplemente invocando en cualquier lugar, y tan a menudo como haga falta. Siempre se obtendr una sesin que estar dentro del alcance o "scope" de la transaccin de base de datos actual. Esto tiene que ser configurado, ya sea para entornos de recursos locales o para JTA (vase la Seccin 2.5, Sesiones contextuales.
sessionFactory.getCurrentSession()

A veces es conveniente extender los alcances de la sesin y de la transaccin de base de datos hasta que la vista o "view" le haya sido presentada al usuario. Esto es especialmente til en aplicaciones basadas en servlets, las cuales utilizan una fase separada de presentacn posterior al procesamiento de la solicitud o "request". Extender la transaccin de base de datos hasta que la "view" sea presentada es fcil si se implementa un interceptor propio. Sin embargo, no es fcil de hacer si uno se apoya en un EJBs con transacciones CMT, dado que la transaccin se completar tras el return de los mtodos de los EJBs, antes de que la presentacin de ninguna view hubiere comenzado. Visite el sitio de web de Hibernate para consejos y ejemplos acerca de este patrn Open Session in View.

11.1.2. Conversaciones largas


El patrn "una-sesin-por-solicitud" (session-per-request) no es el nico concepto til que puede usarse para disear unidades de trabajo. Muchos procesos de negocios requieren toda una serie de interacciones con el usuario, entretejidas con accesos a la base de datos. En las aplicaciones de web y corporativas, no es aceptable que una transaccin de base de datos dure a lo largo de toda la interaccin con el usuario. Considere el siguiente ejemplo: Aparece la primera ventana de dilogo, los datos que ve el usuario han sido cargados en una sesin y transaccin de base de datos en particular. El usuario es libre de modificar los objetos. El usuario pulsa "Grabar" luego de 5 minutos, y espera que sus modificaciones sean hechas persistentes; tambin espera haber sido la nica persona que haya editado esa informacin, y que no puedan haber ocurrido otras modificaciones conflictivas. A esto le llamamos una "unidad de trabajo"; desde el punto de vista del usuario, una conversacin (o transaccin de la aplicacin). Hay varias maneras de implementar esto en su aplicacin. Una primera implementacin ingenua sera manetner la sesin y la transaccin de base de datos abiertas durante el tiempo que el usuario se tome para pensar, lo cual ejerce un "lock" sobre la base de datos para impedir modificaciones concurrentes, y garantizar aislamiento y atomicidad. Esto es, por supuesto, una prctica a evitar o "anti-patrn" (antipattern), dado que los conflictos de lock no le permitirn a nuestra aplicacin adaptarse a una mayor demanda por usuarios concurrentes. Claramente, debemos usar varias transacciones de BD para implementar la conversacin. En este caso, mantener un aislamiento entre los procesos de negocio se vuelve en parte responsabilidad de la capa de la aplicacin. Una simple conversacin normalmente abarca varias transacciones de base de datos. Ser atmica si slo una de dichas transacciones (la ltima) es la que almacena los datos modificados, todas las otras simplemente leen datos (por ejemplo, en una ventana de dilogo tipo "paso a paso" o "wizard", que abarque varios ciclos solicitud/respuesta). Esto es ms fcil de implementar de lo que parece, especialmente si se utilizan las ventajas que provee Hibernate: Versionado automtico: Hiebernate puede efectuar automticamente por usted un control de concurrencia optimista, puede detectar automticamente si ocurri una modificacin durante el tiempo que el usuario se tom para reaccionar. Usualmente, esto slo se verifica al final de la conversacin.

118 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

Objetos desprendidos: si se decide usar el patrn una sesin por solicitud (session-per-request) ya discutido, todas las instancias cargadas se convertirn en "desprendidas" (detached) durante el tiempo que el usario se tome para pensar. Hibernate le permite reasociar estos objetos y persistir las modificaciones; este patrn se llama una-sesinpor-solicitud-con-objetos-desprendidos. Para aislar modificaciones concurrentes se usa versionado automtico. Sesin larga (o "extendida"): la sesin de Hibernate puede desconectarse de la conexin JDBC subyacente luego de que la transaccin haya ejecutado su commit, y reconectada cuando ocurra una nueva solicitud del cliente. Este patrn se conoce como una-sesin-por-conversacin y hace que la reasociacin de objetos sea innecesaria. Para aislar modificaciones concurrentes se usa versionado automtico, y a la sesin no se le permite hacer "flush" automtico, sino explcito. Ambos patrones, una-sesin-por-spolicitud y una-sesin-por-conversacin tienen ventajas y desventajas. Las discutiremos ms adelante, en el contexto del control de concurrencia optimista.

11.1.3. Considerar la identidad de los objetos


Una aplicacin puede aceder en forma concurrente al mismo estado persistente en dos sesiones diferentes. Pero una instancia de una clase persistente nunca se comparte entre dos instancias de Session. Por lo tanto, hay dos nociones diferentes de identidad: Identidad de base de datos
foo.getId().equals( bar.getId() )

Identidad de JVM
foo==bar

Entonces, para objetos asociados a una sesin en particular, (esto es, en el mismo alcance o "scope" de una sesin) las dos nociones son equivalentes, e Hibernate garantiza que la identidad JVM equivale a la identidad de BD. Sin embargo, si la aplicacin accede en forma concurrente al mismo dato, puede ocurrir que la misma identidad persistente est contenida en dos instancias de objeto en dos sesiones distintas. En este caso la identidad persistente o de base de datos existe, pero la identidad de JVM no, los objetos son "diferentes". Estos conflictos se resuelven a nivel usando versionado automtico (cuando ocurren los "flush"/"commit"), usando el enfoque optmista. Este enfoque deja que Hibernate se preocupe por la concurrencia. Tambin provee la mejor "escalabilidad", dado que garantizar la identidad slo a nivel de unidades de trabajo en un thread simple no requiere un costoso "lock" ni otros medios de sincronizacin. La aplicacin no necesita sincronizar ningn objeto, siempre y cuando se atenga a que se usar un solo thread por sesin. Dentro de una sesin, la aplicacin puede usar == tranquilamente para comparar objetos. Sin embargo, una aplicacin que use == fuera de una sesin, se puede topar con resultados inesperados. Esto puede ocurrir incluso en lugares inslitos, por ejemplo, si se colocan dos instancias desprendidas en el mismo Set, existe la posibilidad de que ambas tengan la misma identidad de base de datos (es decir, que representen la misma fila) pero no la misma identidad JVM. El programador debe sustituir los mtodos equals() y hashCode() en las clases persistentes, e implementar su propia nocin de igualdad entre objetos. Slo una advertencia: nunca use el identificador de base de datos para implementar igualdad; use una "clave de negocios", una combinacin nica y normalmente inmutable de atributos. Si la instancia transitoria es almacenada en un Set, cambiar el hashcode rompe el contrato del Set. Los atributos de las "claves de negocio" no necesitan ser tan estables como las claves primarias de una base de datos. Slo necesitan poder establecer, de manera estable, diferencias o igualdad entre los objetos que estn en un Set. Vea el sitio de web de Hibernate para una discusin ms detallada sobre este tema. Tambin note que ste no es un problema de Hibernate, sino la manera en que los objetos de Java implementan identidad e igualdad.

11.1.4. Problemas comunes


Nunca use los anti-patrones una-sesin-por-cada-interaccin-con-el-usuario ni una-sesin-para-toda-la-aplicacin (por supuesto, puede haber raras excepciones a esta regla). Note que los problemas que listamos a continuacin pueden aparecer incluso si se estn usando los patrones que s recomendamos. Asegrese de que entiende las implicancias de la decisin de diseo que tome. Una sesin (Session) no es segura en cuanto a acceso concurrente por mltiples threads (no es "thread-safe"). Las cosas que se supone funcionen en forma concurrente, como las HTTP requests, los session beans, o los workers de Swing workers, causaran condiciones de conflicto por recursos conocidas como "race conditions" si la instancia de una sesin de Hibernate fuese compartida. Si la sesin de Hibernate est contenida en una sesin de HTTP

119 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

(HttpSession, la cual se discute ms adelante), se debera considerar el sincronizar el acceso a la sesin HTTP. De otra manera, cualquier usuario que cliquee "reload" lo suficientemente rpido, es probable que termine usando la misma sesin (de Hibernate) en dos threads ejecutndose en forma concurrente. Si Hibernate produce una excepcin, significa que hay que desandar (rollback) la transaccin de base de datos, y cerrar la sesin inmediatamente (como se discute luego en ms detalle),. Si la sesin est asociada a la aplicacin, debe detenerse la aplicacin. Efectuar un "rollback" de la transaccin no restaura los objetos de negocio al estado en el que estaban antes de que la transaccin ocurriese. Esto significa que el estado de la base de datos y el de los objetos de negocio s quedan fuera de fase. Normalmente esto no es problema, porque las excepciones no son recuperables, y de todos modos es necesario comenzar todo de nuevo luego de un "rollback". La sesin almacena en su cach cada objeto que est en estado persistente (habiendo vigilado y comprobado Hibernate si su estado es "sucio"). Esto significa que crecer para siempre, hasta provocar un error de memoria (OutOfMemoryException) si se la deja abierta por mucho tiempo o simplemente se le cargan demasiados datos. Una solucin para esto, es invocar clear() y evict() para manejar el cach de la sesin, pero lo que ms probablemente se debera considerar es un procedimiento de base de datos almacenado (stored procedure) si se necesitan operaciones masivas de datos. Algunas soluciones se muestran en el Captulo 13, Procesamiento en lotes. Mantener una sesin abierta durante toda la interaccin con el usuario tambin aumenta la probabilidad de que los datos se vuelvan "rancios".

11.2. Demarcacin de transacciones de base de datos


La demarcacin de las transacciones de base de datos (o de sistema) siempre es necesaria. No puede ocurrir ninguna comunicacin con la base de datos si no es dentro de una transaccin. (Esto parece confundir a algunos programadores acostumbrados a trabajar siempre en modo "auto-commit"). Siempre deben emplearse lmites de transaccin claros, incluso para las operaciones de lectura. Dependiendo del niverl de aislamiento y de las posibilidades de la base de datos, esto puede no ser obligatorio, pero no hay ninguna desventaja ni se puede dar ninguna razn en contra de demarcar explcitamente, siempre, los lmites de una transaccin. Una nica transaccin de base de datos, ciertamente tendr mucha mejor performance que mltiples pequeas transacciones, incluso al leer datos. Una aplicacin de Hibernate puede ser ejecutada en un entorno "no manejado", "no administrado" (es decir, autosuficiente, una simple aplicacin de web o Swing), y tambin en entornos J2EE "administrado" (managed environments). En un entorno "no manejado", Hibernate normalmente es responsable por su propio "pool" de conexiones. El programador tiene que establecer los limites de las transacciones manualmente (en otras palabras, invocar los mtodos begin, commit y rollback de las transacciones l mismo). Un entorno "administrado", normalmente provee transacciones administradas por el contenedor ("container-managed transactions o CMT por sus siglas en ingls), con la disposicin de las tranascciones definida declarativamente en los archivos de descripcin de despliegue o "deployment descriptors" de los session beans EJB, por ejemplo. En tal caso, la demarcacin manual o "programtica" de las transacciones no es necesaria. Sin embargo, a veces es deseable mantener la capa de persistencia porttil entre entornos administrados y no administrados. Utilizar la demarcacin programtica se puede usar.en ambos casos. Hibernate ofrece una API llamada Transaction que se traduce en el sistema nativo de transacciones del entorno en el cual el programa haya sido desplegado. Esta API es opcional, pero recomendamos usarla siempre, a menos que el cdigo est en un session bean, dentro de un servidor con CMT. Usualmente, finalizar una sesin involucra las siguientes fases: invocar el "flush" de la sesin invocar "commit" en la transaccin de base de datos cerrar la sesin manejar las excepciones que hayan podido ocurrir Efectuar el "flush" de la sesin ha sido discutido antes; ahora le daremos una mirada ms detallada a la demarcacin de transacciones y al manejo de excepciones, tanto en un entorno administrado como no administrado.

11.2.1. Entornos no administrados


Si la capa de persistencia e Hibernate se ejecuta en un entorno no-administrado, las coneiones a la base de datos usualmente son manejadas por un "pool" de conexiones simple (es decir, no una DataSource) del cual Hibernta obtiene las

120 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

conexiones que necesite. El estilo de manejo de sesin/tranasccin se ve as:


// Non-managed environment idiom Session sess = factory.openSession(); Transaction tx = null; try { tx = sess.beginTransaction(); // efectuar algo de trabajo ... tx.commit(); } catch (RuntimeException e) { if (tx != null) tx.rollback(); throw e; // o mostrar un mensaje de error } finally { sess.close(); }

No hace falta invocar el "flush" de la sesin explcitamente: el llamaod a commit() dispara automticamente la sincronizacin (dependiendo del Modo de "flush" para la sesin. Un llamado a close() marca el fi de la sesin. La implicancia ms importante de close() es que la conexin JDBC ser cedidad por la sesin. Este cdigo Java es porttil, y puede ejecutarse tanto en entornos administrados como no administrados. Una solucin muchio ms flexible (que ya viene incorporad en Hibernate), es el manejo del contexto de "sesin actual", como se describin anterioromente.
// Estilo para un entorno no-administrado con getCurrentSession() try { factory.getCurrentSession().beginTransaction(); // efectuar algo de trabajo ... factory.getCurrentSession().getTransaction().commit(); } catch (RuntimeException e) { factory.getCurrentSession().getTransaction().rollback(); throw e; // o mostrar un mensaje de error }

Se podrn encontrar fragmentos de cdigo como stos en cualquier aplicacin normal. Las excepciones fatales, de sistema, deberan ser capturadas en la capa superior. En otras plabras, el cdigo que ejecuta los llamados a Hibernate, en la capa de persistencia, y el cdigo que maneja las RuntimeExceptions (y normalmente hace las tareas de limpeza y salida) estn en capas diferentes. El "manejo de contexto actual" hecho por Hibernate puede simplificar este diseo considerablemente, todo lo que se necesita es accedeso a la SessionFactory. El manejo de excepciones se discute ms adelante en este captulo. Note que debera seleccionarse org.hibernate.transaction.JDBCTransactionFactory (el valor pord efecto), y, para el segundo ejemplo, el valor "thread" para hibernate.current_session_context_class.

11.2.2. Usar JTA


Si la capa de persistencia se ejecuta en un servidor de aplicaciones (por ejemplo, detrs de EJB session beans), cada conexin de base de datos obtenida por Hibernate ser automticamente parte de la transaccin global JTA. Tambin se puede instalar una implementacin JTA autnoma, y usarla sin EJB. Hibernate ofrece dos estrategias para integracin con JTA: Si se usan tranascciones manejadas por beans (bean-managed transactions o BMT por sus siglas en ingls), Hibernate le dir al servidor de aplicaciones que empiece y finalice una transacccin BMT si se usa la API de Transaction API. De este modo, le cdigo e manejo de transacciones para un entorno no administrado es idntico al de un entorno administrado.
// estilo BMT Session sess = factory.openSession(); Transaction tx = null; try {

121 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

tx = sess.beginTransaction(); // efectuar algo de trabajo ... tx.commit(); } catch (RuntimeException e) { if (tx != null) tx.rollback(); throw e; // o mostrar un mensaje de error } finally { sess.close(); }

Si se desea usar la sesin asociada a una transaccin, es decir, la funcionalidad getCurrentSession() para una ms fcil propagacin del contexto, se debe usar la API de JTA UserTransaction directamente:
// estilo BMT con getCurrentSession() try { UserTransaction tx = (UserTransaction)new InitialContext() .lookup("java:comp/UserTransaction"); tx.begin(); // efectuar algo de trabajo con la sesin asociada a la transaccin factory.getCurrentSession().load(...); factory.getCurrentSession().persist(...); tx.commit(); } catch (RuntimeException e) { tx.rollback(); throw e; // o mostrar un mensaje de error }

Con CMT, la demarcacin de transacciones se hace en los descriptores de despliegue (dployment descriptors) del session bean, no se hace programticamente. As que el cdigo queda reducido a:
// estilo CMT Session sess = factory.getCurrentSession(); // efectuar algo de trabajo ...

En un entorno CMT/EJB incluso el rollback ocurre automticamente, puesto que una RuntimeException no capturada emitida por el mtodo de un session bean le dice al contenedor que efecte rollback en la transaccin global. Esto significa que no hace falta usar la API de Transaction API de Hibernate en absoluto con BMT or CMT, e igualmente se obtiene propagacin automtica de la sesin "actual" asociada a la transaccin. Cuando se elige la fbrica (factory) de transacciones, note que debera elegirse org.hibernate.transaction.JTATransactionFactory si se usa JTA directamente (BMT), y debera usarse org.hibernate.transaction.CMTTransactionFactory en un session bean CMT. Ms an, asegrese de que su hibernate.current_session_context_class ha sido o bien eliminado (por compatibilidad hacia a trs o "backwards compatibility"), o bien puesto a "jta". La operacin getCurrentSession() tiene una desventaja en un entorno JTA:, Hay una advertencia sobre el uso del modo de liberacin de conexiones after_statement, el cual es el valor por defecto. Debido a una tonta limitacin de la especificacin JTA, para Hibernate no es posible limpiar automticamente instancias no cerrada de ScrollableResults o Iterator que hayan sido devueltas por scroll() o iterate(). Usted debe liberar el cursor de base de datos subyacente invocando explcitamente cursor by calling ScrollableResults.close() o Hibernate.close(Iterator) en el bloque finally. (Por supuesto, la mayora de las aplicaciones pueden fcilmente evitar usar en absoluto scroll() o iterate() en el cdigo JTA o CMT).

11.2.3. Manejo de excepciones


Si la sesin provoca una excepcin (incluida cualquier SQLException), se debera efectuar un rollback de la transaccin de base de datos inmediatamente, invocar Session.close() y descartar la instancia de la sesin. Algunos mtodos de Session no dejarn a la sesin en un estado consistente. Ninguna excepcin generada por Hibernate puede ser tratada

122 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

como recuperable. Asegrese de que la sesin ser cerrada invocando close() en el bloque finally. la cual envuelve la mayora de los errores que ocurren en la capa de persistencia de Hibernate, es una excepcin del tipo "unchecked" (esto es, que no requiere captura obligatoriamente en tiempo de compilacin). No lo era en versiones anteriores de Hibernate. En nuestra opinin, no se debera forzar al programador a capturar excepciones de bajo nivel en la capa de persistencia. En la mayora de los sistemas, las excepciones "unchecked" son manejadas en uno de los primeros "marcos" de la pila de invocaciones a mtodos (es decir, en las capas ms "altas" de la aplicacin), y se le presenta un mensaje de error al usuario de la aplicacin, o se adopta algn otro curso de accin apropiado. Note que Hibernate puede tambin emitir otras exceptiones, adems de HibernateException. stas son, de nuevo, no recuperables, y se debe adoptar las medidas apropiadas para lidiar con ellas. Hibernate envuelve las excepciones SQLException generadas al interactuar c con la base de datos en una JDBCException. De hecho, Hibernate intentar convertir la excepcin en una subclase de JDBCException que tenga ms sentido. La SQLException subyacente est siempre disponible via JDBCException.getCause(). Hibernate convierte las SQLException en subclases apropiadas de JDBCException usando el conversor SQLExceptionConverter que est asociado a la fbrica SessionFactory. POr defecto, el SQLExceptionConverter es definido de acuerdo al dialecto SQL elegido. Pero es posible enchufar una implementacin a medida (ver los javadocs para la clase SQLExceptionConverterFactory por detalles). Los subtipos estndar de JDBCException son:
JDBCConnectionException: indica SQLGrammarException: indica HibernateException,

un error en la comunicacin con la JDBC subyacente

un error sintctico o gramatical con el SQL emitido alguna forma de violacin de una constraint de integridad

ConstraintViolationException: indica LockAcquisitionException: indica

un error al adquirir el nivel de "lock" necesario para efectuar la operacin

solicitada.
GenericJDBCException: una

excepcin genrica que no cae en ninguna de las otras categoras.

11.2.4. Expiracin de transacciones


Una caracterstica extremadamente importante provista por un entorno aministrado, como EJB, la cual nunca es provista por un entorno no administrado, es la expiracin de las transacciones, o "transaction timeout". Los "timeouts" de las transacciones que ninguna trnasaccin "rebelde" ocupe indefinidamente los recursos del sistema sin devolverle respuesta alguna al usuario. Fuera de un entorno administrado (JTA), Hibernate no puede proveer esta funcionalidad en forma completa. Sin embargo, puede al menos controlar las operaciones de acceso a datos, asegurndose de que los "puntos muertos" (deadlocks) y las consultas con resultados enormes estn limitadas a un tiempo definido. En un entorno administrado, Hibernate puede delegar el "timeout" de las transacciones en JTA. Esta funcionalidad es abstrada por el objeto Transaction de Hibernate.

Session sess = factory.openSession(); try { //set transaction timeout to 3 seconds sess.getTransaction().setTimeout(3); sess.getTransaction().begin(); // do some work ... sess.getTransaction().commit() } catch (RuntimeException e) { sess.getTransaction().rollback(); throw e; // or display error message } finally { sess.close(); }

Note que setTimeout() no puede ser llamada desde un bean en CMT, en donde los "timeouts" de las transacciones son definidos declarativamente.

11.3. Control optimista de concurrencia

123 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

El nico abordaje consistente con una alta concurrencia y un alta "escalabilidad", es el control de concurrencia optimista con versionado. El chequeo de versiones usa nmeros de versin, o timestamps, para detectar adtualizaciones conflictivas (y evitar que se pierdan modificaciones). Hibernate ofrece 3 enfoques distintos para escribir una aplicacin que use concurrencia optimista. Los casos de uso que mostraremos ocurren en el contexto de una conversacin larga, pero el chequeo de versiones tiene la ventaja de tambin prevenir la prdida de modificaciones en transacciones de base de datos simples.

11.3.1. Chequeo de versin hecho por la aplicacin


En una implementacin sin mucha ayuda de Hibernate, cada interaccin con la base de datos ocurre en una nueva sesin, y el programador es responsable de recargar todas las instancias persistentes desde la base de datos antes de manipularlas. Este enfoque fuerza a la aplicacn a efectuar su propio chequeo de versiones, para asegurar el aislamiento en al conversacin transaccional. Este abordaje es el menos eficiente en trminos de acceso a la base de datos, y es el ms parecido a los "entity beans" de EJB.
// foo es una instancia cargada por una sesin previa session = factory.openSession(); Transaction t = session.beginTransaction(); int oldVersion = foo.getVersion(); session.load( foo, foo.getKey() ); // cargar el estado actual if ( oldVersion != foo.getVersion() ) throw new StaleObjectStateException(); foo.setProperty("bar"); t.commit(); session.close();

(N.del.T):"foo" y "bar", de origen incierto, son locuciones que se usan en ingls como ejemplos de nombres para cualquier cosa, especialmente en el mbito de la computacin. Si se usa "foo" como nombre en un ejemplo, casi siempre se espera que el siguiente nombre sea "bar". La propiedad version se mapea usando <version>, e Hibernate incrementar el nmero automticamente durante el "flush" si la entidad est sucia. Por supuesto, si se opera en un entorno de baja concurrencia de datos, y no se requiere un chequeo de versiones, se puede usar este abordaje pero saltearse el chequeo de versiones. En tal caso, la estrategia por defecto para conversaciones largas ser "el ltimo commit es el que gana". Tenga en cuenta que esto puede confundir a los usuarios de la aplicacin, dado que pueden experimentar prdidas de actualizaciones sin mensajes de error, o sufrir la posibilidad de conflictos cuando los cambios se sincronicen. Claramente, el chequeo manual de versiones slo es factible en circunstancias muy triviales, y en la mayora de las aplicaciones no es prctico. A menudo hay que chequear no slo instancias simples, sino todo un rbol de objetos modificados. Hibernate ofrece chequeo automtico de versin, usando uno de estos paradigmas de diseo: "sesin extendida", o "instancais desprendidas".

11.3.2. Sesin extendida y versionado automtico


Una sola instancia de sesin y sus clases persistentes son usadas por toda la conversacin (lo cual se conoce como una-sesin-por-conversacin). Hibernate chequea las instancias de las versiones cuando ocurre el "flush", emitiendo una excepcin si se detecta modificaciones concurrentes. El capturar y manejar estas excepciones queda a cargo del programador (opciones comunes que se le dan al usuario son: sincronizar los cambios manualmente, o recomenzar la conversacin de negocios con datos que no estn "rancios"). La sesin es desconectada de toda conexin JDBC subyacente mientras se espera que el usuario complete su interaccin. Esta estrategia es la ms eficiente en trminos de acceso a la base de datos. La aplicacin no necesita preocuparse por chequear versiones o reasociar instancias desprendidas, ni tiene que recargar instancias en cada transaccin de base de datos.
// foo es una instancia cargada anteriormente por una sesn anterior Transaction t = session.beginTransaction(); // obtiene una nueva conexin JDBC, comienza la transac foo.setProperty("bar"); session.flush(); t.commit(); session.close(); // slo para la ltima transaccin de la conversacin // tambien devuelve la conexin JDBC // slo para la ltima transaccin de la conversacin

124 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

El objeto foo todava sabe en qu sesin fue cargado. Comenzar una nueva transaccin de base de datos en una sesin vieja, obtiene una nueva conexin y reanuda la sesin. Efectuar un "commit" de una transaccin de base de datos desconecta una sesin de la coinexin JDBC y devuelve la conexin al "pool". Tras la reconexin, para forzar un chequeo de versin en los datos que no se estn actualizando, se puede invocar Session.lock() con LockMode.READ en cualquier objeto que pueda haber sido actualizado por otra transaccin. Usted no necesita un "lock" sobre cualquier dato que usted est actualizando. Usualmente, se le debe asignar FlushMode.MANUAL a una sesin extendida, de manera que, en realidad, slo a la ltima transaccin de base de datos se le permita persistir todas las modificaciones hechas durante esa conversacin. Por eso, slo esta ltima transaccin de BD incluira la operacin flush(), y luego tambin el llamado de la sesin a close() para cerrar la conversacin. Este patrn es problemtico si la sesin es demasiado grande para como para ser almacenada durante el tiempo que el usuario se toma para reaccionar. Por ejemplo, una HttpSession debera mantenerse tan chica como sea posible. Como la sesin es tambin el cach de primer nivel, y contiene todos los objetos cargados, probablementa slo podamos usar esta estrategia en uns pocos ciclos solicitur/respuesta. Una sesin debera usarse para una sola conversacin, dado que pronto contendr datos "pasados". (Note que versiones anteriores de Hibernate requeran que la sesin se conectara y desconectara explcitamente. Dichos mtodos ahora son obsoletos (deprecated), y comenzar y terminar una transaccin tiene el mismo efecto). Tambin note que se debera mantener la sesin desconectada cerca de la capa de persistencia. En otras palabras, use un "stateful session bean" de EJB para contener la sesin en un entorno de tres capas, y no la transfiera al entorno de web (ni siquiera la serialice para transferirla a otra capa separada) para almacenarla en una HttpSession. El patrn de "sesin extendida" una-sesin-por-conversacin, es ms difcil de implementar con control automtico del contexto de sesin actual. Para esto se necesita proveer una implementacin a medida de CurrentSessionContext. Vea la Wiki de Hibernate para ejemplos:

11.3.3. Objetos desprendidos y versionado automtico


Cada interaccin con el repositorio persistente ocurre en una nueva sesin. Sin embargo, las mismas instancias persistentes son reusadas para cada interaccin con la DB. La aplicacin manipula el estado de las instancias desprendidas, orignialmente cargadas en otra sesin, y lyego las reasocia usando Session.update(), Session.saveOrUpdate(), or Session.merge().
// foo es una instancia cargada en una sesin previa foo.setProperty("bar"); session = factory.openSession(); Transaction t = session.beginTransaction(); session.saveOrUpdate(foo); // use merge() si "foo" puede haber sido cargada anteriormente t.commit(); session.close();

De nuevo, Hibernate chequear ls versiones de instancia al ocurrir el "flush", lanzando una excepcin si han ocurrido actualizaciones conflictivas. Se puede tambin invocar lock() en lugar de update(), y usar LockMode.READ (efectuando un cheque de versin, eludiando todos los cachs) si se est seguro de que el objeto no ha sido modificado.

11.3.4. Crear un mtodo a medida para el versionado automtico


Se puede inhabilitar el incremento automtico de versin de Hibernate para propiedades y colecciones especficas, asignndole al atributo de mapeo optimistic-lock el valor false. Hibernate no incrementar ms las versiones, si la propiedad est sucia. Los sistemas de base de datos anticuados a menudo son estticos y no pueden ser modificados. U otras aplicaciones pueden estar accediendo a dichas base de datos, sin saber cmo manejar nmeros de versiones ni incluso timestamps. En ambos casos, el versionado no puede basarse en una columna en particular de una tabla. Para forzar un chequeo de versin sin un mapeo de versin o timestamp, con una comparacin del estado de todos los campos en una fila, habilite optimistic-lock="all" en el mapeo de <class>. Note que esto slo funciona, conceptualmente, si Hibernate puede comparar el estado nuevo con el viejo, es decir, si se usa una sola sesin larga y no una-sesin-por-solicitud-con-objetosdesprendidos. A veces la modificacion concurrente puede ser permitida, simepre y cuando los cambios que hayan sido efectuados no se superpongan. Si se asigna optimistic-lock="dirty" al mapear la <class>, Hibernate slo comparar los campos sucios

125 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

cuando ocurra el "flush". En ambos casos, sea con columnas dedicadas de versin/timestamp, o con comparacin completa/de campos sucios, Hibernate usa un solo comando UPDATE (con una clusula WHERE apropiada) por entidad para ejecutar el chequeo de versin y actualizar la informacin. Si se desa usar persistencia transitiva para la reasociacin en cascada de entidades relacionadas, es posible que Hibernate ejecute algunos UPDATEs innecesarios. Esto normalmente no es un problema, pero puede que se ejecuten triggers on update en la base de datos, cuando no se les ha efectuado ningn cambio a las instancias desprendidas. Se puede personalizar este comportamiento ms a medida, asignando select-before-update="true" em el mapeo de <class>, forzando a Hibernate a practicar un SELECT de la instancia para asegurarse de que realmente hayan ocurrido cambios, antes de actualizar la fila.

11.4. "Lock" pesimista


La idea no es que los programadores inviertan demasiado tiempo preocupndose por estrategias de "lock". Normalmente, es suficiente que se especifique un nivel de asilamiento para las conexiones JDBC y despus simplemente dejar que la base de datos haga todo el trabajo. No obstante, los programadores avanzados probablemente deseen a veces obtener "locks" pesimistas exclusivos, o recapturar locks al comienzo de una transaccin nueva. Hibernate siempre usar el mecanismo de lock de la base de datos, nunca "lock" de objetos en memoria! La clase LockMode define los distintos niveles de "lock" que pueden ser adquiridos por Hibernate. Un lock se obtiene por los mecanismos siguientes:
LockMode.WRITE se LockMode.UPGRADE

adquiere automticamente cuando Hibernate actualiza o inserta una fila.

puede ser adquirido ante una solicitud explcita del usuario, usando SELECT ... FOR UPDATE en una base de datos que soporte dicha sintaxis.
LockMode.UPGRADE_NOWAIT puede UPDATE NOWAIT bajo Oracle.

ser adquirido ante una solicitud explcita del usuario, usando SELECT ... FOR

LockMode.READ es adquirido automticamente cuando Hibernate lee datos bajo los niveles de aislamiento "Repeatable Read" o "Serializable". Puede ser readquirido por solicitud especfica del usuario. LockMode.NONE representa la ausencia de "locks". Todos los objetos pasan a este modo de lock al final de una transaccin. Los objetos asociados con la sesin a travs de un llamado a update() o saveOrUpdate() tambin comienzan en este modo de "lock".

La "solicitud (request) explcita del usuario" se expresa de alguna de las siguientes maneras: Un llamado a Session.load(), especificando un LockMode. Un llamado a Session.lock(). Un llamado a Query.setLockMode(). Si Session.load() es invocado con UPGRADE o UPGRADE_NOWAIT, y el objeto requerido an no haba sido cargado por la sesin, el objeto es cargado usando SELECT ... FOR UPDATE. Si se invoca load() para un objeto que ya est cargado, con un "lock" menos restrictivo que el que se est pidiendo, Hibernate invoca lock() para dicho objeto.
Session.lock() preactica un chequeo del nmero de versin si el "lock" especificado es READ, UPGRADE o UPGRADE_NOWAIT. (En el caso de UPGRADE o UPGRADE_NOWAIT, se usa SELECT ... FOR UPDATE).

Si la base de datos no soporta el lock mode solicitado, Hibernate usar un modo alternativo apropiado (en lugar de emitir una excepcin). Esto asegura que la aplicacin sea porttil.

11.5. Modos de liberacin de conexiones


El antiguo comportamento de Hibernate (2.x) en relacin con el manejo de conexiones JDBC era que un sesin obtena una conexin cuando se necesitaba por primera vez, y luego se aferraba a dicha conexin hasta que la sesin se cerrara. Hibernate 3.x introdujo la sesin de "modos de liberacin de conexiones". Note que la discusin siguiente, slo es pertinente para conexiones provistas a travs de un ConnectionProvider; las conexiones provistas por el usuario quedan afuera del horizonte de esta discusin. Los diferentes modos de liberacin se identifican con valores enumerados de

126 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

org.hibernate.ConnectionReleaseMode:

el comportamiento anticuado descrito anteriormente. La sesin de Hibernate obtiene una conexin cuando es necesario efectuar algn acceso a JDBC, y retiene dicha conexin hasta que la sesin se cierre.
AFTER_TRANSACTION: dice

ON_CLOSE: es esencialmente

que se liberen las conexiones una vez que la org.hibernate.Transaction se haya

completado.
AFTER_STATEMENT (tambin conocida

como "liberacin agresiva"): dice que las conexiones se liberen luego de la ejecucin de todos y cada uno de los comandos. Esta liberacin agresiva es omitida si el comando deja recursos abiertos que an estn asociados con la sesin actual; actualmente la nica situacin en la que esto ocurre es cuando se usa un org.hibernate.ScrollableResults.

El parmetro de configuracin hibernate.connection.release_mode se usa para especificar qu modo de liberacin usar. Los valores posibles son:
auto (el valor por defecto): esta opcin le delega la decisin al modo de liberacin recibido por el mtodo org.hibernate.transaction.TransactionFactory.getDefaultReleaseMode(). Con JTATransactionFactory,

devuelve ConnectionReleaseMode.AFTER_STATEMENT; con JDBCTransactionFactory, devuelve ConnectionReleaseMode.AFTER_TRANSACTION. Casi nunca es buena idea cambiar el comportamiento por defecto, porque las fallas en relacin con este valor normalmente indican errores de programacin (bugs) o suposiciones incorrectas en el cdigo.
on_close: indica que se use ConnectionReleaseMode.ON_CLOSE. Este valor se conserva por compatibilidad hacia atrs, pero su uso se desaconseja. after_transaction: indica

que se use ConnectionReleaseMode.AFTER_TRANSACTION. Este valor no debera ser usado en entornos JTA. Tambin note que, con ConnectionReleaseMode.AFTER_TRANSACTION, si una sesin se considera que est en modo auto-commit, las conexiones sern liberadas como si el modo de liberacin fuera AFTER_STATEMENT.

after_statement: indica que se usa ConnectionReleaseMode.AFTER_STATEMENT. Adicionalmente, el ConnectionProvider que est configurado es consultado para comprobar si soporta este valor (supportsAggressiveRelease()). Si no, el modo de liberacin es reinicializado a

ConnectionReleaseMode.AFTER_TRANSACTION. Este valor es seguro slo en entornos en donde se puede o bien recapturar la misma conexin JDBC subyacente cada vez que hacemos un llamado a ConnectionProvider.getConnection(), o bien en entornos con auto-commit en donde no importa si es la misma conexin la que nos es devuelta.

Captulo 12. Interceptores y eventos


A menudo es til que la aplicacin reaccione a ciertos eventos que ocurren dentro de Hibernate. Esto permite la implementacin de ciertos tipos de funcionalidad genrica, y extender la funcionalidad de Hibernate.

12.1. Interceptores
La interfaz Interceptor provee mtodos de retorno o "callbacks" desde la sesin a la aplicacin, permitindole a la aplicacin inspeccionar y/o manipular propiedades de un objeto persistente antes de grabarlo. Un uso posible de esto es, escribir informacin de seguimiento/auditora. Por ejemplo, el interceptor siguiente asigna automticamente la propiedad createTimestamp cuando se crea un Auditable, y actualiza la propiedad lastUpdateTimestamp cuando un Auditable es actualizado. Se puede o bien implementar Interceptor directamente, o (preferentemente) extender EmptyInterceptor.
package org.hibernate.test; import java.io.Serializable; import java.util.Date; import java.util.Iterator; import org.hibernate.EmptyInterceptor; import org.hibernate.Transaction;

127 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

import org.hibernate.type.Type; public class AuditInterceptor extends EmptyInterceptor { private int updates; private int creates; private int loads; public void onDelete(Object entity, Serializable id, Object[] state, String[] propertyNames, Ty // no hace nada } public boolean onFlushDirty(Object entity, Serializable id, Object[] currentState, Object[] pre String[] propertyNames, Type[] types) { if ( entity instanceof Auditable ) { updates++; for ( int i=0; i < propertyNames.length; i++ ) { if ( "lastUpdateTimestamp".equals( propertyNames[i] ) ) { currentState[i] = new Date(); return true; } } } return false; } public boolean onLoad(Object entity, Serializable id, Object[] state, String[] propertyNames, T if ( entity instanceof Auditable ) { loads++; } return false; } public boolean onSave(Object entity, Serializable id, Object[] state, String[] propertyNames, T if ( entity instanceof Auditable ) { creates++; for ( int i=0; i<propertyNames.length; i++ ) { if ( "createTimestamp".equals( propertyNames[i] ) ) { state[i] = new Date(); return true; } } } return false; } public void afterTransactionCompletion(Transaction tx) { if ( tx.wasCommitted() ) { System.out.println("Creaciones: " + creates + ", Actualizaciones: " + updates, "Cargas: } updates=0; creates=0; loads=0; } }

Los interceptores vienen en dos variantes: Con alcance de sesin (session-scoped), y con alcance de toda la fbrica de sesiones (sessionfactory-scoped). Un interceptor con alcance de sesin se especifica cuando la sesin se abra usando uno de los mtodos adicionales (overloaded) SessionFactory.openSession() que acepta un Interceptor como parmetro.
Session session = sf.openSession( new AuditInterceptor() );

Un interceptor con alcance de SessionFactory se registra con el objeto Configuration antes de consctruir la SessionFactory. En este caos, el interceptor provisto ser a aplicado a todas las sesiones abiertas por esa fbrica de sesiones. Esto es cierto, a menos que se use una sesin que haya sido abierta especificando explcitamente otro interceptor. El cdigo de los interceptores de alcance de SessionFactory debe ser seguro en cuando a acceso concurrente (thread-safe), dado que su cdigo ser (potencialmente) usado por varias sesiones al mismo tiempo. Asegrese de no almacenar estado especfico de una sesin.
new Configuration().setInterceptor( new AuditInterceptor() );

128 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

12.2. Sistema de eventos


Si se tiene que reaccionar a eventos especficos de la capa de persistencia, se puede hacer uso de la arquitectura de eventos de Hibernate3. El sistema de eventos puede ser usado por aadidura a los interceptores, o en reemplazo de ellos. Esencialmente todos los mtodos de la interfaz Session estn correlacionados con un evento. Hay un LoadEvent, un FlushEvent, etc. (consulte la DTD del archivo de configuracin XML o el paquete org.hibernate.event para una lista completa de los tipos de evento definidos). Cuando se invoca uno de estos mtodos, la sesin de Hibernate genera el evento apropiado y lo pasa a los "listeners" (escuchas) de eventos que hayan sido configurados para ese tipo. De fbrica y por defecto, esos "listeners" implementan el mismo procesamiento en el que esos mtodos habran resultado. De todos modos, usted es libre de crear listener a medida, que implemente alguna de la interfaces correspondientes (por ejemplo, el evento LoadEvent es procesado por una implementacin registrada de la interfaz LoadEventListener interface), en cuyo caso la implementacin es la que se vuelve responsable de procesar todo llamado a load() que la sesn haga. A los efectos prcticos, los "listeners" deben ser considerados singletons, lo cual significa que sern compartidos entre solicitudes de clientes, y no deberan almacenar estado como variables de instancia. Un listener a medida debera implementar la interfaz apropiada para el evento que quiera procesar, y/o extender una de las clases utilitarias de base (o incluso los listeners que ya vienen incluidos en Hibernate, dado que fueron declarados como no-finales con ese propsito). Los listeners a medida pueden ser registrados programticamente a travs del objeto Configuration, o especificados declarativamente en el archivo de configuracin XML de Hibernate (no se soporta la configuracin declarativa mediante el archivo ".properties"). He aqu un ejemplo de un listener a medida para el evento "load".
public class MyLoadListener implements LoadEventListener { // ste es el nico mtodo definido por la interfaz LoadEventListener public void onLoad(LoadEvent event, LoadEventListener.LoadType loadType) throws HibernateException { if ( !MySecurity.isAuthorized( event.getEntityClassName(), event.getEntityId() ) ) { throw MySecurityException("Unauthorized access"); } } }

Tambin se necesita una entrada de configuracin, indicndole a Hibernate que use este listener, adems del listener por defecto.
<hibernate-configuration> <session-factory> ... <event type="load"> <listener class="com.eg.MyLoadListener"/> <listener class="org.hibernate.event.def.DefaultLoadEventListener"/> </event> </session-factory> </hibernate-configuration>

O se lo puede registrar programticamente:


Configuration cfg = new Configuration(); LoadEventListener[] stack = { new MyLoadListener(), new DefaultLoadEventListener() }; cfg.EventListeners().setLoadEventListeners(stack);

Los listeners registrados declarativamente no pueden compartir instancias. Si la misma clase es usada por muchos elementos <listener/>, cada referencia resultar en una instancia separada de esa clase. Se se necesita la capacidad de compartir instancias de listener entre distintos tipos de listener, se debe usar la forma programtica de registrarlos. Por qu impementar una interfaz y tambin definir un tipo especfico durante la configuracin? Porque una implementacin de listener puede estar implementando ms de una interfaz. Al tener que especificar tambin el tipo durante el registro, se vuelve fcil habilitar/inhanilitar los listeners a medida durante la cofiguracin.

12.3. Seguridad declarativa de Hibernate

129 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

La seguridad declarativa de Hibernate usualmente se maneja en una capa de "fachada de sesin" (session faade). A partit de Hibernate3, a algunas acciones se les puede asignar permisos va JACC, y se pueden autorizar va JAAS. sta es una funcionalidad opcional, construida encima de la arquitectura de eventos. Primero se deben configurar los listeners de eventos, para habilitar el uso de autorizaciones JAAS.
<listener type="pre-delete" class="org.hibernate.secure.JACCPreDeleteEventListener"/> <listener type="pre-update" class="org.hibernate.secure.JACCPreUpdateEventListener"/> <listener type="pre-insert" class="org.hibernate.secure.JACCPreInsertEventListener"/> <listener type="pre-load" class="org.hibernate.secure.JACCPreLoadEventListener"/>

Note que <listener type="..." class="..."/> es simplemente una forma abreviada de <event type="..."> <listener class="..."/></event> para cuando hay exactamente un listener para un tipo de evento en particular. Luego, todava en hibernate.cfg.xml, se vinculan los permisos a roles:
<grant role="admin" entity-name="User" actions="insert,update,read"/> <grant role="su" entity-name="User" actions="*"/>

Los nombres de los roles son aqullos que sean comprendidos por su proveedor JACC.

Captulo 13. Procesamiento en lotes


Un abordaje ingenuo al problema de insertar 100.000 filas en una base de datos podra verse as:
Session session = sessionFactory.openSession(); Transaction tx = session.beginTransaction(); for ( int i=0; i<100000; i++ ) { Customer customer = new Customer(.....); session.save(customer); } tx.commit(); session.close();

Esto fallara. provocando un OutOfMemoryException ms o menos alrededor de la lnea nmero 50.0000. Esto se debe a que Hibernate guarda todas las instancias de Customer en el cach de sesin a medida que las va insertando. En este captulo le mostramos cmo evitar este problema. Pero primero, si se est usando procesamiento en lotes (en ingls, "batch processing"), es indispensable habilitar el uso del procesamiento en lotes JDBC, si se pretende alcanzar una performance razonable. Asgnele un valor razonable al tamao del lote JDBC, digamos, de 10 a 50.
hibernate.jdbc.batch_size 20

Note que Hibernate inhabilita la insercin por lotes a nivel de JDBC en forma transparente si se est usando un generador de identificadores identiy. Tal vez se quiera realizar este tipo de trabajo en un proceso en donde la interaccin con el cach de 2do nivel est completamente inhabilitada:
hibernate.cache.use_second_level_cache false

Pero esto no es absolutamente necesario, dado que se puede inhabilitar el CacheMode especficamente, para anular la interaccin con el cach de 2do nivel.

13.1. Inserciones en lotes


Cuando se persisten los objetos, se debe efectuar el flush() de la sesin, y luego clear() con regularidad, para controlar el tamao del cach de 1er nivel.
Session session = sessionFactory.openSession(); Transaction tx = session.beginTransaction();

130 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

for ( int i=0; i<100000; i++ ) { Customer customer = new Customer(.....); session.save(customer); if ( i % 20 == 0 ) { //20, igual que el tamao del lote JDBC //aplicarle "flush" a un lote de inserts y liberar memoria session.flush(); session.clear(); } } tx.commit(); session.close();

13.2. Actualizaciones en lotes


Para capturar y modificar data se aplican las mismas ideas. Adicionalmente, se necesita usar scroll() para tomar ventaja de los cursores que existan del lado del servidor de BD, para consultas que devuelvan muchas filas de datos.
Session session = sessionFactory.openSession(); Transaction tx = session.beginTransaction(); ScrollableResults customers = session.getNamedQuery("GetCustomers").setCacheMode(CacheMode.IGNORE). int count=0; while ( customers.next() ) { Customer customer = (Customer) customers.get(0); customer.updateStuff(...); if ( ++count % 20 == 0 ) { //aplicarle "flush" a un lote de actualizaciones y liberar memoria session.flush(); session.clear(); } } tx.commit(); session.close();

13.3. La interfaz StatelessSession


Alternativamente, Hibernate provee una API orientada a comandos, que puede ser usada por datos que fluyan desde y hacia la base de datos en forma de objetos desprendidos. Una StatelessSession (sesin sin estado) no tiene un contexto de persistencia asociado ni provee mucha de la semntica de alto nivel respecto del ciclo de vida, que s proveen las sesiones normales; en particular, no tiene un cach de 1er nivel ni interacta con un cach de 2do nivel. No implementa un write-behind transaccional ni chequeo automtico de datos "sucios". Las operaciones que se efecten usando una sesin sin estado nunca se propagan en cascada. Las sesiones sin estado ingoran las colecciones y los modelos de eventos e interceptores. Tambin son vulnerables a los efectos de "data aliasing", dado que carecen de cach de 1er nivel. Una sesin sin estado es una abstraccin de ms bajo nivel, muy cercana a la JDBC subyacente.
StatelessSession session = sessionFactory.openStatelessSession(); Transaction tx = session.beginTransaction(); ScrollableResults customers = session.getNamedQuery("GetCustomers") .scroll(ScrollMode.FORWARD_ONLY); while ( customers.next() ) { Customer customer = (Customer) customers.get(0); customer.updateStuff(...); session.update(customer); } tx.commit(); session.close();

Note que, en este ejemplo de cdigo, las instancias de Customer (cliente) devueltas por la consulta son automticamente desprendidas. Nunca estn asociadas con ningn contexto de persistencia. Se considera que las operaciones insert(), update() y delete() definidas por la interfaz StatelessSession son operaciones directamente a nivel de fila de la base de datos, lo cual resulta en la ejecucin inmediata de un SQL INSERT, UPDATE o DELETE, respectivamente. Por esto, su semntica es muy diferente de las operaciones save(), saveOrUpdate() y delete() definidas por la interfaz Session.

131 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

13.4. Operaciones del tipo "Lenguaje de Modificacion de Datos" (DML-style)


Como se discuti anteriormente, el mapeo automtico objeto/relacional automtico y transparente se ocupa de la administracin del "estado" de los objetos. Esto significa que el estado de un objeto dado est disponible en memoria, por lo que manipular la BD directamente usando comandos SQL del tipo "operaciones de modificacin de datos" (data modification language o DML por sus siglas en ingls: es decir, INSERT, UPDATE, DELETE) no afectar el estado en memoria. De todos modos, el lenguaje HQL de Hibernate provee mtodos para este tipo de ejecucin de comandos de modificacin de datos, llamada "modificacin de datos en masa" o "bulk-style DML". Vase HQL.
where_conditions)?.

La pseudo-sintaxis para os comandos UPDATE y DELETE es: ( UPDATE | DELETE ) FROM? NombreDeLaEntidad (WHERE Algunos puntos a destacar: en la clusula "from", la palabra FROM es optativa Slo se puede nombrar una entidad en la clusula "from"; opcionalmente, sta puede tener un alias. Si lo tiene, entonces cualquier referencia a propiedades debe estar calificada usando dicho alias. Si la entidad no tiene alias, entonces es ilegal que las propiedades estn calificadas. En estas consultas HQL de "modificacin en masa" no se puede especificar ningn joins (ni implcito, ni explcito). S se pueden usar subconsultas (subqueries) en la clusula "where", y estas subconsultas s pueden contener joins. La clusula "where" tambin es optativa.

A modo de ejemplo: para ejecutar un HQL UPDATE, use el mtodo Query.executeUpdate() (el mtodo se bautiz en honor al mtodo de JDBC PreparedStatement.executeUpdate()):
Session session = sessionFactory.openSession(); Transaction tx = session.beginTransaction(); String hqlUpdate = "update Customer c set c.name = :newName where c.name = :oldName"; // o tambin: String hqlUpdate = "update Customer set name = :newName where name = :oldName"; int updatedEntities = s.createQuery( hqlUpdate ) .setString( "newName", newName ) .setString( "oldName", oldName ) .executeUpdate(); tx.commit(); session.close();

Por defecto, los comandos UPDATE, no afectan las propiedades version ni timestamp de las entidades involucradas; esto es consistente con la especificacin de EJB3. Sin embargo, se puede forzar a Hibernate a reinicializar adecuadamente los valores de las propiedades version y timestamp usando un a "actualizacin versionada" (versioned update). Esto se logra agregando la palabra VERSIONED luego de UPDATE keyword.
Session session = sessionFactory.openSession(); Transaction tx = session.beginTransaction(); String hqlVersionedUpdate = "update versioned Customer set name = :newName where name = :oldName"; int updatedEntities = s.createQuery( hqlUpdate ) .setString( "newName", newName ) .setString( "oldName", oldName ) .executeUpdate(); tx.commit(); session.close();

Note que los tipos de versin a medida (org.hibernate.usertype.UserVersionType) no se permiten en conjuncin con comandos update versioned. Para ejecutar un HQL DELETE, use el mismo mtodo Query.executeUpdate():
Session session = sessionFactory.openSession(); Transaction tx = session.beginTransaction(); String hqlDelete = "delete Customer c where c.name = :oldName"; // o tambin: String hqlDelete = "delete Customer where name = :oldName"; int deletedEntities = s.createQuery( hqlDelete ) .setString( "oldName", oldName ) .executeUpdate(); tx.commit(); session.close();

132 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

El valor int devuelto por el mtodo Query.executeUpdate() indica el nmero de entidades afectadas por la operacin. Considere que esto puede corresponder o no con el nmero de filas afectadas en la base de datos. Una operacin HQL en masa puede resultar en la ejecucin de mltiples comandos SQL (para las joined-subclass, por ejemplo). El nmero devuelto indica el nmero real de entidades afactadas por el comando. Volviendo al ejemplo de la joined-subclass, un comando DELETE ejecutado contra una de las subclases podra resultar en borrados no slo en la tabla a la cual la subclase est mapeada, sino tambin borrados en la tabla "raz", y potencialmente en otras tablas de joined-subclass ms abajo en la jerarqua de herencias. La pseudo-sintaxis de los comandos INSERT es: INSERT INTO NombreDeLaEntidad lista_de_propiedades comando_select. Algunos puntos a destacar: Slo se soporta la forma INSERT INTO ... SELECT ... ; la forma INSERT INTO ... VALUES ... no. La especificacin de la lista_de_propiedades es anloga a la especificacin de columnas en un comando SQL INSERT. Para entidades que estn involucradas en una herencia mapeada, slo las propiedades que estn definidas directamente en ese nivel de clase en particular pueden ser usadas en la lista_de_propiedades: las propiedades de la superclase no estn permitidas, y las de subclases no tienen sentido. En otras palabras, los comandos INSERT son inherentemente polimrficos. el comando_select puede ser cualquier consulta vlida de seleccin HQL, con la precaucin de que los tipos de retorno deben corresponder con los tipos esperados por el insert. Actualmente, esto es verificado durante la compilacin, en lugar de relegar dicho chequeo a la base de datos. Note, sin embargo, que esto podra causar problemas entre tipos que Hibernate considere o no "equivalentes" ms que "iguales". Por ejemplo, para Hibernate no son iguales los tipos org.hibernate.type.DateType y org.hibernate.type.TimestampType, aunque la base de datos no diferencie entre ambos o sea capaz de manejar la conversin entre ambos. En relacin a la propiedad id, el comando de insercin ofrece dos opciones. Se puede o bien especificarla explcitamente en la lista_de_propiedades (en cuyo caso el valor se toma del comando_select) o se puede omitir de la lista de propiedades (en cuyo caso se usa un valor generado). Esta ltima opcin est disponible solamente cuando se usen generadores de id que operen dentro de la base de datos, intentar usarla con generadores del tipo "residente en memoria" causar una excepcin durante el parsing del comando. Para los efectos de esta discusin, se consideran "generadores residentes en memoria" org.hibernate.id.SequenceGenerator (y sus subclases), y cualquier implementacin de org.hibernate.id.PostInsertIdentifierGenerator. org.hibernate.id.TableHiLoGenerator tampoco se puede usar, porque no expone una manera facitble de obtener sus valores en un comando "select". Para las propiedades mapeadas como version o timestamp, el comando INSERT da dos opciones: se puede o bien especificarlas explcitamente en la lista_de_propiedades (en cuyo caso el valor se toma del comando_select) o se las puede puede omitir de la lista de propiedades (en cuyo caso se usa el valor semilla o "seed value" definido por org.hibernate.type.VersionType). Un ejemplo de ejecucin del comando HQL INSERT:
Session session = sessionFactory.openSession(); Transaction tx = session.beginTransaction(); String hqlInsert = "insert into DelinquentAccount (id, name) select c.id, c.name from Customer c wh int createdEntities = s.createQuery( hqlInsert ).executeUpdate(); tx.commit(); session.close();

Captulo 14. HQL: El lenguaje de consultas de Hibernate


Hibernate est equipado con un lenguaje de consultas extremadamente potente: HQL. Aunque cuenta con una sintaxis deliberadamente parecida a SQL, HQL es totalmente orientado a objetos, capaz de entender nociones como herencia, polimorfismo y asociacin.

14.1. Relevancia de maysculas y minsculas


En las consultas, el uso de maysculas o minsculas es irrelevante, excepto por los nombres de propiedades y clases de Java. De modo que SeLeCT es lo mismo que sELEct y lo mismo que SELECT, pero org.hibernate.eg.FOO no es lo

133 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

mismo que org.hibernate.eg.Foo, y foo.barSet no es lo mismo que foo.BARSET. Este manual usa minsculas para las palabras HQL. A algunos usuarios les parece que las consultas escritas todas en maysula son ms legibles, pero a nosotros esta convencin nos parece fea cuando est inserta en cdigo Java.

14.2. La clusula "from"


La consulta de Hibernate ms simple tiene esta forma:
from eg.Cat

la cual simplemente devuelve todas las instancias de la clase eg.Cat. Normalmente no necesitamos calificar el nombre de la clase de esta manera, dado que el valor por defecto es auto-import. As que casi siempre escribimos:
from Cat

La mayora de las veces har falta asignarle un alias, dado que querremos referirnos a Cat en otras partes de la consulta:
from Cat as cat

Esta consulta le asigna el alias cat a las instancias de Cat, de manera que podamos usar dicho alias ms adelante en la consulta. La palabra as es optativa, tambin podramos escribir:
from Cat cat

Pueden aparecer varias clases, resultando en un producto cartesiano o "cross join".


from Formula, Parameter from Formula as form, Parameter as param

Se considera una prctica buena el nombrar los alias en las consultas usando una minscula inicial, en concordancia con los estndares de nombrado para variables locales en Java. (por ejemplo domesticCat).

14.3. Asociaciones y "joins"


Se les puede asignar alias a entidades asociadas, o incluso a elementos de una coleccin de valores, usando la palabra join.
from Cat as cat inner join cat.mate as mate left outer join cat.kittens as kitten from Cat as cat left join cat.mate.kittens as kittens from Formula form full join form.parameter param

Los tipos de join son un prstamo de la especificacin ANSI de SQL.


inner join left outer join right outer join full join (el cual normalmente

no es muy til)

Las frases inner join, left outer join and right outer join pueden abreviarse as:
from Cat as cat join cat.mate as mate

134 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

left join cat.kittens as kitten

Y se pueden especificar condiciones adicionales del join, usando la palabra with:


from Cat as cat left join cat.kittens as kitten with kitten.bodyWeight > 10.0

Adicionalmente, un join calificado con la palabra "fetch" (captura) permite que las asociaciones o colecciones de valores sean inicializados junto con sus objetos padres, usando un solo SELECT. Esto es particularmente til en el caso de las colecciones; efectivamente reemplaza los "outer joins" y las inicializaciones haraganas (lazy) del archivo de mapeo para asociaciones y colecciones. Vea la Seccin 19.1, Estrategias de captura (fetch) para ms informacin.
from Cat as cat inner join fetch cat.mate left join fetch cat.kittens

A un join del tipo "fetch" normalmente no se le asignan alias, porque los objetos asociados que devuelve no deberan ser usados en la clusula "where", ni en ninguna otra clusula. Adems, los objetos asociados no son devueltos directamente en el resultado de la consulta; en cambio, se puede acceder a ellos a travs del objeto padre. La nica razn por la que se podra necesitar un alias, es si se est usando un join tipo "fetch" recursivo a otra coleccin ms.
from Cat as cat inner join fetch cat.mate left join fetch cat.kittens child left join fetch child.kittens

Note que la construcciones con fetch no deben ser usadas en consultas que luego invoquen iterate() (aunque s se puede con scroll()). Tampoco debera usarse fetch con consultas que usen setMaxResults() o setFirstResult() (los mtodos de paginacin), dado que dichas operaciones se basan en el nmero de filas del resultado, el cual normalmente contendr duplicados debido a esta "captura ansiosa", y por lo tanto la cantidad de filas no ser la que se espera. Tampoco se debe usar fetch junto con condiciones "with" ad hoc. Al efectuar un join tipo "fetch" con ms de una coleccin, es posible crear un producto cartesiano, as que tenga cuidado en este caso. Usar joins "fetch" con mltiples colecciones, adems, da a menudo resultados inesperados con los mapeos de "bag", as que tenga cuidado acerca de cmo formula sus consultas en este caso. Por ltimo, note que las construcciones full join fetch y right join fetch no tienen sentido. Si se est usando captura haragana (lazy fetching) a nivel de las propiedades, con instrumentacin bytecode, es posible forzar a Hibernate para que capture esas propiedades haraganas inmediatamente en la primera consulta, usando fetch all properties.
from Document fetch all properties order by name from Document doc fetch all properties where lower(doc.name) like '%cats%'

14.4. Formas de la sintaxis de los "joins"


HQL soporta dos formas de asociacin por "joins": implcita y explcita. Las consultas mostradas en la seccin anterior usan todas la forma explcita en donde la palabra "join" es explcitamente usada en la clusula "from". sta es la forma que se recomienda. La forma implcita no usa la palabra "join". En lugar de eso, las asociaciones son "des-referidas" (dereferenced) usando la notacin de puntos. Los joins implcitos pueden aparecer en cualquiera de las clusulas HQL (select, from, where). Un join implcito se traduce en "inner joins" en el comando SQL resultante.
from Cat as cat where cat.mate.name like '%s%'

14.5. Referirse a la propiedada identificadora


En general, hay 2 maneras de referirse a la propiedad indentificadora de una entidad:

135 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

La propiedad especial id puede ser usada para referirse a la propiedad indentificadora de una entidad siempre y cuando dicha entidad no haya definido otra propiedad no-identificadora tambin llamada "id". Si la entidad define una propiedad indentificadora con nombre, se puede usar dicho nombre. Las referencias a identificadores compuestos siguen las mismas relgas. Si la entidad tiene una propiedad no-identificadora llamda "id", la propiedad identificadora compuesta slo puede ser referida por el nombre asignado. En caso contrario, se puede usar la propiedad especial id para referirse a la propiedad identificadora. Nota: esto ha cambiado significativamente a partir de la versin 3.2.2. En versiones anteriores, id siempre haca alusin a la propiedad identificadora, sin importar el verdadero nombre. A consecuencia de esto, cuando haba propiedades no-identificadoras llamadas id, las consultas no podan referirse a ellas.

14.6. La clusula "select"


La clusula select elige qu objetos y propiedades sern devueltos como conjunto de resultados o "resultset". Sea:
select mate from Cat as cat inner join cat.mate as mate

Esta consulta seleccionar los mates (en ingls, "compaeros") de otros Cats. En realidad, se puede expresar esta consulta de una forma ms compacta, como:
select cat.mate from Cat cat

Las consultas pueden devolver propiedades de cualquier tipo de valor, incluidos valores de tipo "componente":
select cat.name from DomesticCat cat where cat.name like 'fri%' select cust.name.firstName from Customer as cust

Las consultas pueden devolver mltiples objetos, en un array Object[],


select mother, offspr, mate.name from DomesticCat as mother inner join mother.mate as mate left outer join mother.kittens as offspr

o como una List,


select new list(mother, offspr, mate.name) from DomesticCat as mother inner join mother.mate as mate left outer join mother.kittens as offspr

o como un verdadero objeto Java, seguro en cuanto a tipo (typesafe)


select new Family(mother, mate, offspr) from DomesticCat as mother join mother.mate as mate left join mother.kittens as offspr

asumiendo que la clase Family tuviere el constructor apropiado Se les pueden asignar alias a las expresiones seleccionadas usando as:
select max(bodyWeight) as max, min(bodyWeight) as min, count(*) as n from Cat cat

Esto es de lo ms util cuando se usa en conjuncin con select new map:

136 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

select new map( max(bodyWeight) as max, min(bodyWeight) as min, count(*) as n ) from Cat cat

Esta consulta devuelve un Map de los alias a los valores seleccionados.

14.7. Funciones agregadas


Las consultas HQL incluso pueden devolver los resultados de funciones agregadas que fueran aplicadas a propiedades:
select avg(cat.weight), sum(cat.weight), max(cat.weight), count(cat) from Cat cat

Las funciones agregadas que se soportan son:


avg(...), sum(...), min(...), max(...) count(*) count(...), count(distinct ...), count(all...)

En la clusula "select" se pueden usar operadores aritmticos, concatenacin, y funciones SQL reconocidas:
select cat.weight + sum(kitten.weight) from Cat cat join cat.kittens kitten group by cat.id, cat.weight select firstName||' '||initial||' '||upper(lastName) from Person

Las palabras distinct y all pueden ser usadas, y con la misma semntica que en SQL.
select distinct cat.name from Cat cat select count(distinct cat.name), count(cat) from Cat cat

14.8. Consultas polimrficas


Una consulta como:
from Cat as cat

devuelve no slo instancias de Cat, sino tambin de las subclases como DomesticCat. Las consultas de Hibernate pueden nombrar cualquier clase o interfaz Java en la clusula from. La consulta devolver las instancias de todas las clases persistentes que extiendan o implementen dicha clase o interfaz. La siguiente consuta devuelve todos los objetos persistentes:
from java.lang.Object o

Sea una interfaz Named, implementada por varias clases persistentes:


from Named n, Named m where n.name = m.name

Note que las dos ltimas consultas requerirn ms de dos comandos SQL SELECT. Esto implica que un clusula order by no ordenara correctamente la totalidad del conjunto de resultados, y que no se puede usar Query.scroll() para navegarlos.

14.9. la clusula "where"


La clusula where permite acotar la lista de instancias devueltas. Si no hay alias, uno puede referirse a las propiedades por su nombre:

137 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

from Cat where name='Fritz'

si hay un alias, sese un nombre de propiedad calificado:


from Cat as cat where cat.name='Fritz'

devuelve las instancias de gatos llamados 'Fritz'.


select foo from Foo foo, Bar bar where foo.startDate = bar.date

devolver las instancias de Foo para las cuales exista una instancia de Bar cuya propiedad date sea igual a la propiedad startDate de Foo. Las expresiones con "path" compuesto hacen que la clusula "where" sea extremadamente poderosa. Considere:
from Cat cat where cat.mate.name is not null

Esta consulta se traducira en un comando SQL con varios (inner) joins. Si se escribiera algo como esto:
from Foo foo where foo.bar.baz.customer.address.city is not null

en SQL se acabara con una consulta que requerira 4 joins de tablas. El operador = puede usarse para comparar no slo propiedades, sino tambin instancias:
from Cat cat, Cat rival where cat.mate = rival.mate select cat, mate from Cat cat, Cat mate where cat.mate = mate

La propiedad id (en minscula), puede usarse para hacer referencia al identificador nico de un objeto. Vase la Seccin 14.5, Referirse a la propiedad identificadora para ms informacin.
from Cat as cat where cat.id = 123 from Cat as cat where cat.mate.id = 69

La segunda consulta es eficiente, no requiere joins. Tambin se pueden usar propiedades de los identificadores compuestos. Supongamos que Person tiviera un identificador compuesto que consistiese en country y medicareNumber. (de nuevo, vase la Seccin 14.5, Referirse a la propiedad identificadora para ms informacin acerca de referirse a las propiedades identificadoras):
from bank.Person person where person.id.country = 'AU' and person.id.medicareNumber = 123456 from bank.Account account where account.owner.id.country = 'AU' and account.owner.id.medicareNumber = 123456

Nuevamente, la segunda consulta no requiere "joins" Del mismo modo, la propiedad especial class accede al valor discriminador de una instancia, en caso de que se est usando persistencia polimrfica. Un nombre de clase de Java incrustado en la clusula "where" ser traducido como su valor de discriminador.
from Cat cat where cat.class = DomesticCat

Tambim se pueden usar componentes, o tipos a medida compuestos, o las propiedades de dichos tipos de componentes/tipos. Vea la Seccin 14.17, Componentes para ms informacin.

138 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

Un tipo "any" tiene las propiedades especiales id y class, que permiten expresar un join de la siguiente manera (en donde AuditLog.item es una propiedad mapeada con <any>):
from AuditLog log, Payment payment where log.item.class = 'Payment' and log.item.id = payment.id

Note que, en la consulta precedente, log.item.class y payment.class se estaran refiriendo a valores de columnas completamente diferentes de la base de datos.

14.10. Expresiones
Las expresiones que se permiten en la clusula where incluyen la mayora de las que se podra escribir en SQL: operadores matemticos +, -, *, / operadores de comparacin binaria =, >=, <=, <>, !=, like operaciones lgicas and, or, not parntesis ( ), para indicar agrupamientos
in, not in, between, is null, is not null, is empty, is not empty, member of and not member of

la forma de "case" simple, "Simple" case, case ... when ... then ... else ... end, y la forma de "case" llamada "searched", case when ... then ... else ... end concatencin de cadenas ...||... or concat(...,...)
current_date(), current_time(), current_timestamp() second(...), minute(...), hour(...), day(...), month(...), year(...),

Cualquier funcin u operador definido por EJB-QL 3.0: substring(), trim(), lower(), upper(), length(),
locate(), abs(), sqrt(), bit_length(), mod() coalesce() y nullif() str()

para convertir valores numricos o temporales en una cadena legible

cast(... as ...), en donde el segundo argumento es el nombre de un tipo de Hibernate, y extract(... from ...) si la base de datos subyacente soporta las funciones ANSI cast() y extract().

la funcin HQL index(), que se aplica a los alias de una colecin asociada indexada. funciones HQL que aceptan expresiones tipo "path" con valor de coleccin: size(), minelement(), maxelement(), minindex(), maxindex(), junto con las funciones especiales elements() e indices, las cuales pueden ser cuantificadas usando some, all, exists, any, in. cualqiuer funcin escalar SQL soportada por la base de datos, como sign(), trunc(), rtrim(), sin() parmetros ppsicionales al estilo JDBC parmetros nombrados: :name, :start_date, :x1 expresiones SQL literales 'foo', 69, 6.66E+2, '1970-01-01 10:00:01.0' constantes public static final de java eg.Color.RAYADO
in y between

pueden ser usados como sigue:

from DomesticCat cat where cat.name between 'A' and 'B' from DomesticCat cat where cat.name in ( 'Foo', 'Bar', 'Baz' )

y la forma negada puede ser escrita:

139 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

from DomesticCat cat where cat.name not between 'A' and 'B' from DomesticCat cat where cat.name not in ( 'Foo', 'Bar', 'Baz' )

Del mismo modo. is null y is not null pueden ser usadas para chequear valores nulos. Se puede usar fcilmente valores booleanos, declarando sustituciones de consulta HQL en la configuracin de Hibernate:
<property name="hibernate.query.substitutions">true 1, false 0</property>

Esto reemplazar las palabras true y false con los valores literales 1 y 0 en el SQL traducido desde este HQL.
from Cat cat where cat.alive = true

Se puede chequear el tamao de la coleccin con la propiedad especial size, o con la funcin especial size().
from Cat cat where cat.kittens.size > 0 from Cat cat where size(cat.kittens) > 0

Para las colecciones indexadas, es preferible referirse a los valores mnimos y mximos usando las funciones minindex y maxindex. Anlogamente, se puede aludir a los elementos mnimo y mximo de una coleccin de un tipo bsico utilizando las funciones minelement y maxelement.
from Calendar cal where maxelement(cal.holidays) > current_date from Order order where maxindex(order.items) > 100 from Order order where minelement(order.items) > 10000

Las funciones SQL any, some, all, exists, in se soportan cuando se les pasa como parmetro el conjunto de elementos o ndices de una coleccin (stas son las funciones elements e indices), o el resultado de una subconsulta (vase abajo).
select mother from Cat as mother, Cat as kit where kit in elements(foo.kittens) select p from NameList list, Person p where p.name = some elements(list.names) from Cat cat where exists elements(cat.kittens) from Player p where 3 > all elements(p.scores) from Show show where 'fizard' in indices(show.acts)

Note que las construcciones: size, elements, indices, minindex, maxindex, minelement, maxelement slo pueden ser usadas en la clusula "where" en Hibernate3 Uno se puede referir a los elementos en las colecciones indexadas (arrays, lists, maps) por ndice (slo en la clausula "where").
from Order order where order.items[0].id = 1234 select person from Person person, Calendar calendar where calendar.holidays['national day'] = person.birthDay and person.nationality.calendar = calendar select item from Item item, Order order where order.items[ order.deliveredItemIndices[0] ] = item and order.id = 11 select item from Item item, Order order

140 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

where order.items[ maxindex(order.items) ] = item and order.id = 11

La expresin dentro de [] puede incluso ser una expresin aritmtica.


select item from Item item, Order order where order.items[ size(order.items) - 1 ] = item

HQL tambin trae una funcin index() ya incorporada, para elementos de una asociacin de-uno-a-muchos, o una coleccin de valores.
select item, index(item) from Order order join order.items item where index(item) < 5

Pueden ser usadas las funciones SQL escalares que la DB subyacente soporte:
from DomesticCat cat where upper(cat.name) like 'FRI%'

Si todo esto an no lo ha convencido, piense cunto ms largo y menos legible habra sido esta consulta en SQL:
select cust from Product prod, Store store inner join store.customers cust where prod.name = 'widget' and store.location.name in ( 'Melbourne', 'Sydney' ) and prod = all elements(cust.currentOrder.lineItems)

Para que se d una idea, algo como:


SELECT cust.name, cust.address, cust.phone, cust.id, cust.current_order FROM customers cust, stores store, locations loc, store_customers sc, product prod WHERE prod.name = 'widget' AND store.loc_id = loc.id AND loc.name IN ( 'Melbourne', 'Sydney' ) AND sc.store_id = store.id AND sc.cust_id = cust.id AND prod.id = ALL( SELECT item.prod_id FROM line_items item, orders o WHERE item.order_id = o.id AND cust.current_order = o.id )

14.11. La clusula "order by"


La lista devuelta por una consulta puede ser ordenada por cualquier propiedad de las clases o componentes devueltos:
from DomesticCat cat order by cat.name asc, cat.weight desc, cat.birthdate

Las palabras opcionales asc o desc indican orden ascendente o descendente respectivamente.

14.12. La clusula "group by"


Una consulta que devuelva valores agregados, puede ser agrupada por cualquier propiedad de las clases o componentes devueltos.
select cat.color, sum(cat.weight), count(cat) from Cat cat group by cat.color

141 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

select foo.id, avg(name), max(name) from Foo foo join foo.names name group by foo.id

Tambin se permite la clusula having:


select cat.color, sum(cat.weight), count(cat) from Cat cat group by cat.color having cat.color in (eg.Color.TABBY, eg.Color.BLACK)

si la base de datos subyacente lo soporta (por ejemplo, MySQL no), dentro de having se permiten funciones SQL, y dentro del order by se permiten funciones agregadas.
select cat from Cat cat join cat.kittens kitten group by cat.id, cat.name, cat.other, cat.properties having avg(kitten.weight) > 100 order by count(kitten) asc, sum(kitten.weight) desc

Note que ni la clusula group by ni la order by pueden contener expresiones aritmticas. Y tambin que Hibernate no "expande" una entidad agrupada: as que no se puede escribir group by cat si todas las propiedades de cat son no-agregadas; hay que listar todas las propiedades no-agregadas explcitamente.

14.13. Subconsultas
Para las base de datos que soporten subconsultas (subqueries), Hibernate soporta subconsultas dentro de una consulta. Una subconsulta debe estar rodeada por parntesis (a menudo por un llamado a una funcin SQL agregada). Incluso se permiten subconsultas correlacionadas (subconsultas que hagan referencia a un alias en la consulta exterior.
from Cat as fatcat where fatcat.weight > ( select avg(cat.weight) from DomesticCat cat ) from DomesticCat as cat where cat.name = some ( select name.nickName from Name as name ) from Cat as cat where not exists ( from Cat as mate where mate.mate = cat ) from DomesticCat as cat where cat.name not in ( select name.nickName from Name as name ) select cat.id, (select max(kit.weight) from cat.kitten kit) from Cat as cat

Note que las subconsultas HQL pueden ocurrir slo en las clusulas "select" o "where". Note que las subconsultas tambin pueden utilizar sintaxis de constructor del valor de fila (row value constructor). Vea la Seccin 14.18, Constructor del valor de fila para ms detalles.

14.14. Ejemplos de HQL


Las consultas en Hibernate pueden llegar a ser bastante potentes y complejas. De hecho, el poder del lenguaje de consultas es una de las caractersticas ms "vendedoras" de Hibernate. He aqu algunas consultas de ejemplo, muy similares a las que he usado en un proyecto reciente. Note que la mayora de las consultas que usted escribir sern mucho ms simples que stas!

142 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

La siguiente consulta devuelve el id de la orden, el nmero de items y el valor total de todas las rdenes impagas por un cliente en particular, y dado un valor total mnimo, ordenando los resultados por valor total. Para determinar los precios, usa el catlogo actual. El SQL resultante, efectuado contra las tablas ORDER, ORDER_LINE, PRODUCT, CATALOG y PRICE tiene 4 "inner joins" y una subconsulta (no correlacionada).
select order.id, sum(price.amount), count(item) from Order as order join order.lineItems as item join item.product as product, Catalog as catalog join catalog.prices as price where order.paid = false and order.customer = :customer and price.product = product and catalog.effectiveDate < sysdate and catalog.effectiveDate >= all ( select cat.effectiveDate from Catalog as cat where cat.effectiveDate < sysdate ) group by order having sum(price.amount) > :minAmount order by sum(price.amount) desc

Qu monstruo! En realidad, en la vida real no soy muy amigo de las subconsultas, as que mi consulta qued ms bien de esta manera:
select order.id, sum(price.amount), count(item) from Order as order join order.lineItems as item join item.product as product, Catalog as catalog join catalog.prices as price where order.paid = false and order.customer = :customer and price.product = product and catalog = :currentCatalog group by order having sum(price.amount) > :minAmount order by sum(price.amount) desc

La consulta siguiente cuenta el nmero de pagos en cada estado, exceptuando los pagos que figuren como "aprobacin pendiente" (AWAITING_APPROVAL) en donde el cambio de estado ms reciente haya sido efectuado por el usuario actual. Se traduce en una consulta SQL con 2 inner joins y una subconsulta correlacionada, contra las clases PAYMENT, PAYMENT_STATUS y PAYMENT_STATUS_CHANGE.
select count(payment), status.name from Payment as payment join payment.currentStatus as status join payment.statusChanges as statusChange where payment.status.name <> PaymentStatus.AWAITING_APPROVAL or ( statusChange.timeStamp = ( select max(change.timeStamp) from PaymentStatusChange change where change.payment = payment ) and statusChange.user <> :currentUser ) group by status.name, status.sortOrder order by status.sortOrder

Si yo hubiera mapeado la coleccin statusChanges collection como una lista, la consulta habra sido mucho ms fcil de escribir.
select count(payment), status.name from Payment as payment join payment.currentStatus as status where payment.status.name <> PaymentStatus.AWAITING_APPROVAL or payment.statusChanges[ maxIndex(payment.statusChanges) ].user <> :currentUser group by status.name, status.sortOrder order by status.sortOrder

143 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

La siguiente consulta usa la funcin isNull() de MS SQL Server para devolver todas las cuentas y pagos no efectuados a la organizacin a la cual pertenece el usuario actual. Se traduce en un SQL con tres inner joins, un outer join y un subselect contra las tablas the ACCOUNT, PAYMENT, PAYMENT_STATUS, ACCOUNT_TYPE, ORGANIZATION y ORG_USER.
select account, payment from Account as account left outer join account.payments as payment where :currentUser in elements(account.holder.users) and PaymentStatus.UNPAID = isNull(payment.currentStatus.name, PaymentStatus.UNPAID) order by account.type.sortOrder, account.accountNumber, payment.dueDate

En algunas DB, debemos deshacernos del subselect correlacionado.


select account, payment from Account as account join account.holder.users as user left outer join account.payments as payment where :currentUser = user and PaymentStatus.UNPAID = isNull(payment.currentStatus.name, PaymentStatus.UNPAID) order by account.type.sortOrder, account.accountNumber, payment.dueDate

14.15. Actualizaciones y borrados en masa


HQL ahora soporta comandos update, delete e insert ... select .... Vea la Seccin 13.4, Operaciones del tipo "Lenguaje de Modificacion de Datos" (DML-style) para ms detalles.

14.16. Consejos y trucos


Se puede contar el nmero de resultados de una consulta sin necesidad de devolver todo el resultado:
( (Integer) session.createQuery("select count(*) from ....").iterate().next() ).intValue()

Para ordenar un resultado de acuerdo al tamao de las colecciones de hijos, use la consulta siguiente:
select usr.id, usr.name from User as usr left join usr.messages as msg group by usr.id, usr.name order by count(msg)

Si su base de datos soporta subselects, se puede poner una condicin en cuanto al tamao de la seleccin, en la clusula "where" de su consulta.
from User usr where size(usr.messages) >= 1

si su base de datos no soporta subconsultas, use la consulta siguiente:


select usr.id, usr.name from User usr.name join usr.messages msg group by usr.id, usr.name having count(msg) >= 1

Como esta solucin no puede devolver a un User que tenga 0 mensajes a causa del inner join, la siguiente forma tambin es til:
select usr.id, usr.name from User as usr left join usr.messages as msg group by usr.id, usr.name having count(msg) = 0

Se pueden asociar las propiedades de un JavaBean a parmetros nombrados de una consulta:


Query q = s.createQuery("from foo Foo as foo where foo.name=:name and foo.size=:size");

144 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

q.setProperties(fooBean); // fooBean has getName() and getSize() List foos = q.list();

Las colecciones se pueden volver paginables, usando la interfaz Query ms un filtro:


Query q = s.createFilter( collection, "" ); // el filtro trivial q.setMaxResults(PAGE_SIZE); q.setFirstResult(PAGE_SIZE * pageNumber); List page = q.list();

Los elementos de las colecciones pueden ser ordenados o agrupados usando un filtro de consultas:
Collection orderedCollection = s.filter( collection, "order by this.amount" ); Collection counts = s.filter( collection, "select this.type, count(this) group by this.type" );

Se puede averiguar el tamao de una coleccin sin inicializarla:


( (Integer) session.createQuery("select count(*) from ....").iterate().next() ).intValue();

14.17. Componentes
En HQL, se pueden usar componentes, casi en cualquiera de las mismas formas en que se puede usar "value types" simples. Pueden aparecer en la clusula "select":
select p.name from Person p select p.name.first from Person p

en donde la propiedad "name" de Person es un componente. Los componentes tambin pueden ser usados en clusulas "where":
from Person p where p.name = :name from Person p where p.name.first = :firstName

Los componentes tambin pueden ser usados en clusulas "order by":


from Person p order by p.name from Person p order by p.name.first

Otro uso comn de los componentes, es en los constructores de valor de fila.

14.18. Sintaxis del "Constructor de Valor de Fila" (row value constructor)


HQL soporta el uso de la sintaxis de Constructores de Valor de Fila (row value constructors), a veces tambin llamada sintaxis de "t-upla", incluso aunque la base de datos subyacente no soporte este concepto. Nos estamos refiriendo a a comparaciones multi-valores, tpicamente asociadas con componentes. Considrese una entidad "Person", que define un componente "name":
from Person p where p.name.first='John' and p.name.last='Jingleheimer-Schmidt'

Esta sintaxis es vlida, aunque un tanto locuaz. Sera bueno poder hacerla un poco ms concisa y usar la sintaxis de "constructor de valor de fila":
from Person p where p.name=('John', 'Jingleheimer-Schmidt')

Tambin sera til especificar esto en la clusula "select":


select p.name from Person p

145 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

Otro momento en que la sintaxis de constructor de valor de fila puede ser beneficiosa, es cuando se usen subconsultas que necesiten comparar contra valores mltiples:
from Cat as cat where not ( cat.name, cat.color ) in ( select cat.name, cat.color from DomesticCat cat )

Una cosa a considerar, al decidir si se quiere usar esta sintaxis, es que la consulta ser dependiente del orden de las sub-propiedades del componente en los metadatos.

Captulo 15. Consultas Criteria


Hibernate posee una API para consultas "criteria" (por criterios), intuitiva y extensible.

15.1. Crear una instancia de Criteria


La interfaz org.hibernate.Criteria representa una consulta contra una clase persistente en particular. La sesin acta como fbrica de instancias de Criteria.
Criteria crit = sess.createCriteria(Cat.class); crit.setMaxResults(50); List cats = crit.list();

15.2. Acotar el resultado


(N.del.T):en ingls, "criterio" se dice "criterion", y en plural, es "criteria". La interfaz, muy usada, de Hibernate que denomina a este tipo de consultas, se llama "Criteria". Una interfaz mucho menos conocida, "Criterion", en un paquete del mismo nombre, casi nunca son usados directamente por el programador, porque le son agregados a un "Criteria" ente bambalinas. Una "criterion" individual es una instancia de la interfaz org.hibernate.criterion.Criterion. La clase org.hibernate.criterion.Restrictions define mtodos "fbrica" para obtener ciertos tipos de Criterion que ya vienen incluidos.
List cats = sess.createCriteria(Cat.class) .add( Restrictions.like("name", "Fritz%") ) .add( Restrictions.between("weight", minWeight, maxWeight) ) .list();

Las "Restrictions" (restricciones) pueden ser agrupadas lgicamente.


List cats = sess.createCriteria(Cat.class) .add( Restrictions.like("name", "Fritz%") ) .add( Restrictions.or( Restrictions.eq( "age", new Integer(0) ), Restrictions.isNull("age") ) ) .list(); List cats = sess.createCriteria(Cat.class) .add( Restrictions.in( "name", new String[] { "Fritz", "Izi", "Pk" } ) ) .add( Restrictions.disjunction() .add( Restrictions.isNull("age") ) .add( Restrictions.eq("age", new Integer(0) ) ) .add( Restrictions.eq("age", new Integer(1) ) ) .add( Restrictions.eq("age", new Integer(2) ) ) ) ) .list();

Hay un buen rango de tipos de "criterion" que ya vienen incluidos (subclases de Restrictions), pero uno en especial permite especificar SQL directamente:

146 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

List cats = sess.createCriteria(Cat.class) .add( Restrictions.sqlRestriction("lower({alias}.name) like lower(?)", "Fritz%", Hibernate.STRI .list();

El comodn {alias} ser reemplazado con el alias de fila de la entidad consultada. Un camino alternativo para obtener un "criterion" es obtenerlo a partir de una instancia de Property. Se puede crear una Property invocando Property.forName().
Property age = Property.forName("age"); List cats = sess.createCriteria(Cat.class) .add( Restrictions.disjunction() .add( age.isNull() ) .add( age.eq( new Integer(0) ) ) .add( age.eq( new Integer(1) ) ) .add( age.eq( new Integer(2) ) ) ) ) .add( Property.forName("name").in( new String[] { "Fritz", "Izi", "Pk" } ) ) .list();

15.3. Ordenar el resultado


Se puede ordenar los resultados usando org.hibernate.criterion.Order.
List cats = sess.createCriteria(Cat.class) .add( Restrictions.like("name", "F%") .addOrder( Order.asc("name") ) .addOrder( Order.desc("age") ) .setMaxResults(50) .list(); List cats = sess.createCriteria(Cat.class) .add( Property.forName("name").like("F%") ) .addOrder( Property.forName("name").asc() ) .addOrder( Property.forName("age").desc() ) .setMaxResults(50) .list();

15.4. Asociaciones
Se puede especificar constraints en entidades relacionadas, navegando a travs de asociaciones usando createCriteria().
List cats = sess.createCriteria(Cat.class) .add( Restrictions.like("name", "F%") ) .createCriteria("kittens") .add( Restrictions.like("name", "F%") ) .list();

note que el segundo createCriteria() devuelve una instancia nueva de Criteria, la cual se refiere a los elementos de la coleccin kittens. La siguiente forma alternativa es til en ciertas circunstancias:
List cats = sess.createCriteria(Cat.class) .createAlias("kittens", "kt") .createAlias("mate", "mt") .add( Restrictions.eqProperty("kt.name", "mt.name") ) .list();

(createAlias() no crea una instancia nueva de Criteria.) Note que las colecciones de "kittens" (gatitos) contenidas en las instancias de Cat devueltas por las dos consultas anteriores, no estn pre-filtradas por el Criteria! Si desea obrener slo los "kittens" que cumplen con el Criteria, debe usar un ResultTransformer.
List cats = sess.createCriteria(Cat.class)

147 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

.createCriteria("kittens", "kt") .add( Restrictions.eq("name", "F%") ) .setResultTransformer(Criteria.ALIAS_TO_ENTITY_MAP) .list(); Iterator iter = cats.iterator(); while ( iter.hasNext() ) { Map map = (Map) iter.next(); Cat cat = (Cat) map.get(Criteria.ROOT_ALIAS); Cat kitten = (Cat) map.get("kt"); }

15.5. Captura dinmica de asociaciones


Se puede especificar semntica de asociaciones en tiempo de ejecucin, usando setFetchMode().
List cats = sess.createCriteria(Cat.class) .add( Restrictions.like("name", "Fritz%") ) .setFetchMode("mate", FetchMode.EAGER) .setFetchMode("kittens", FetchMode.EAGER) .list();

Esta consulta capturar tanto mate como kittens mediante un "outer join". Vea la Seccin 19.1, Estrategias de captura (fetch) para ms informacin.

15.6. Consultas "Example"


La clase org.hibernate.criterion.Example permite construir consultas "criterion" a partir de una instancia dada.
Cat cat = new Cat(); cat.setSex('F'); cat.setColor(Color.BLACK); List results = session.createCriteria(Cat.class) .add( Example.create(cat) ) .list();

Las propiedades versin, identificadores y asociaciones son ignoradas. Por defecto, las propiedades con valor nulo son excluidas. Se puede ajustar cmo el Example se aplica:
Example example = Example.create(cat) .excludeZeroes() //excluir las propiedades con valor cero .excludeProperty("color") //excluir una propiedad llamada "color" .ignoreCase() //efectuar comparaciones de cadenas sin importar maysculas/minscul .enableLike(); //usar "like' para las comparaciones de cadenas List results = session.createCriteria(Cat.class) .add(example) .list();

Se puede incluso usar Examples para ubicar criteria en objetos asociados:


List results = session.createCriteria(Cat.class) .add( Example.create(cat) ) .createCriteria("mate") .add( Example.create( cat.getMate() ) ) .list();

15.7. Proyecciones, agregado y agrupamiento


La clase org.hibernate.criterion.Projections (proyecciones) es una fbrica de instancias de la clase Projection. Le aplicamos una proyeccin a una consulta llamando a setProjection().
List results = session.createCriteria(Cat.class) .setProjection( Projections.rowCount() ) .add( Restrictions.eq("color", Color.BLACK) ) .list();

148 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

List results = session.createCriteria(Cat.class) .setProjection( Projections.projectionList() .add( Projections.rowCount() ) .add( Projections.avg("weight") ) .add( Projections.max("weight") ) .add( Projections.groupProperty("color") ) ) .list();

En una consulta de tipo Criteria, no es necesario que haya explcitamente "group by"s. Algunos tipos de proyeccin son las denominadas proyecciones agrupadoras (grouping projections) las cuales aparecen en el SQL como clusulas group by. Optativamente se le puede asignar un alias a la proyeccin, de manera que las Restrictions y los Orders se puedan referir a l. He aqu dos maneras de hacer esto:
List results = session.createCriteria(Cat.class) .setProjection( Projections.alias( Projections.groupProperty("color"), "colr" ) ) .addOrder( Order.asc("colr") ) .list(); List results = session.createCriteria(Cat.class) .setProjection( Projections.groupProperty("color").as("colr") ) .addOrder( Order.asc("colr") ) .list();

Los mtodos alias() y as() simplemente envuelven una instancia de Projection dentro de otra instancia de Projection con alias. Como atajo, se puede asignar un alias al agregar la proyeccin a una lista de proyecciones:
List results = session.createCriteria(Cat.class) .setProjection( Projections.projectionList() .add( Projections.rowCount(), "catCountByColor" ) .add( Projections.avg("weight"), "avgWeight" ) .add( Projections.max("weight"), "maxWeight" ) .add( Projections.groupProperty("color"), "color" ) ) .addOrder( Order.desc("catCountByColor") ) .addOrder( Order.desc("avgWeight") ) .list(); List results = session.createCriteria(Domestic.class, "cat") .createAlias("kittens", "kit") .setProjection( Projections.projectionList() .add( Projections.property("cat.name"), "catName" ) .add( Projections.property("kit.name"), "kitName" ) ) .addOrder( Order.asc("catName") ) .addOrder( Order.asc("kitName") ) .list();

Tambin se pueda usar Property.forName() para expresar proyecciones:


List results = session.createCriteria(Cat.class) .setProjection( Property.forName("name") ) .add( Property.forName("color").eq(Color.BLACK) ) .list(); List results = session.createCriteria(Cat.class) .setProjection( Projections.projectionList() .add( Projections.rowCount().as("catCountByColor") ) .add( Property.forName("weight").avg().as("avgWeight") ) .add( Property.forName("weight").max().as("maxWeight") ) .add( Property.forName("color").group().as("color" ) ) .addOrder( Order.desc("catCountByColor") ) .addOrder( Order.desc("avgWeight") ) .list();

15.8. Consultas y subconsultas desprendidas (detached)

149 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

La clase DetachedCriteria permite crear una consulta por fuera del alcance de una sesin, y ms tarde ejecutarla usando alguna sesin arbitraria.
DetachedCriteria query = DetachedCriteria.forClass(Cat.class) .add( Property.forName("sex").eq('F') ); Session session = ....; Transaction txn = session.beginTransaction(); List results = query.getExecutableCriteria(session).setMaxResults(100).list(); txn.commit(); session.close();

Una DetachedCriteria tambin puede usarse para expresar una subconsulta. Instancias de Criterion que involucren subconsultas pueden ser obtenidas via subconsultas o Property.
DetachedCriteria avgWeight = DetachedCriteria.forClass(Cat.class) .setProjection( Property.forName("weight").avg() ); session.createCriteria(Cat.class) .add( Property.forName("weight").gt(avgWeight) ) .list(); DetachedCriteria weights = DetachedCriteria.forClass(Cat.class) .setProjection( Property.forName("weight") ); session.createCriteria(Cat.class) .add( Subqueries.geAll("weight", weights) ) .list();

Incluso son posibles las subconsultas correlacionadas:


DetachedCriteria avgWeightForSex = DetachedCriteria.forClass(Cat.class, "cat2") .setProjection( Property.forName("weight").avg() ) .add( Property.forName("cat2.sex").eqProperty("cat.sex") ); session.createCriteria(Cat.class, "cat") .add( Property.forName("weight").gt(avgWeightForSex) ) .list();

15.9. Consultas por identificador natural


Para la mayora de las consultas, incluidas las consultas Criteria, el cach de consultas no es muy eficiente, porque la invalidacin del cach ocurre con demasiada frecuencia. Pero hay un tipo especial de consulta con la cual se puede optimizar el algoritmo de invalidacin: la bsqueda por clave natural constante. En algunas aplicaciones, este tipo de consulta ocurre frecuentemente. La API de Criteria posee disposiciones especiales para este caso de uso. Primero se debe mapear la clave natural de su entidad usando <natural-id>, y habilitando el cach de 2do nivel.
<class name="User"> <cache usage="read-write"/> <id name="id"> <generator class="increment"/> </id> <natural-id> <property name="name"/> <property name="org"/> </natural-id> <property name="password"/> </class>

Note que esta funcionalidad no ha sido concebida para usarse con entidades de clave natural mutable. A continuacin, hay que habilitar el cach de consultas de Hibernate. Finalmente, Restrictions.naturalId() permite hacer un uso ms eficiente del algoritmo de cach.
session.createCriteria(User.class) .add( Restrictions.naturalId() .set("name", "gavin")

150 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

.set("org", "hb") ).setCacheable(true) .uniqueResult();

Captulo 16. SQL nativo


Tambin se puede expresar consultas en el dialecto SQL nativo de su base de datos. Esto es til si se quiere utilizar caractersticas particulares de una base de datos, como "hints" en las consultas, o la palabra CONNECT en Oracle. Tambin provee un estadio de migracin claro desde una aplicacin basada en SQL/JDBC hacia Hibernate. Hibernate3 permite especificar SQL escrito a mano (incluyendo procedimientos almacenados o "stored procedures") para todas las operaciones de creacin, modificacin, borrado y carga.

16.1. Usar un SQLQuery


La ejecucin de SQL nativo se controla a travs de la interfaz SQLQuery, la cual se obtiene invocando Session.createSQLQuery(). A continuacin se describe cmo usar esta API para consultar:

16.1.1. Consultas escalares


La consulta SQL ms bsica consiste en obtener una lista de valores escalares.
sess.createSQLQuery("SELECT * FROM CATS").list(); sess.createSQLQuery("SELECT ID, NAME, BIRTHDATE FROM CATS").list();

Estas dos consultas devolvern una List de arrays de Objects (Object[]) con valores escalares para cada columna de la tabla CATS. Hibernate usar ResultSetMetadata para deducir el orden y tipo de los valores escalares devueltos. Para evitar el gasto extra de llamar ResultSetMetadata, o simplemente para se ms explcito acerca de qu se devuelve, se puede usar addScalar().
sess.createSQLQuery("SELECT * FROM CATS") .addScalar("ID", Hibernate.LONG) .addScalar("NAME", Hibernate.STRING) .addScalar("BIRTHDATE", Hibernate.DATE);

Esta consulta especific: la cadena SQL de la consulta las columnas y tipos a devolver Esto an devolver un array de Objetcs, pero ahora no usar ResultSetMetadata sino que obtendr explcitamente las columnas ID, NAME and BIRTHDATE como un Long, una String y un Short, respectivamente, a partir del resultado subyacente. Esto tamben significa que slo sern devueltas esas 3 columnas, incluso cuando la consulta est usando * y pueda devolver ms columnas que las 3 listadas. Es posible omitir la informacin de tipo para algunos o todos los escalares:
sess.createSQLQuery("SELECT * FROM CATS") .addScalar("ID", Hibernate.LONG) .addScalar("NAME") .addScalar("BIRTHDATE");

sta es esencialmente la misma consulta que antes, pero ahora se usa ResultSetMetaData par decidir el tipo de NAME Y BIRTHDATE, mientras que el tipo de ID se especifica explcitamente. Cmo los java.sql.Types devueltos del ResultSetMetaData se mapean a Hibernate, es controlado por el dialecto. Si un tipo en particular no est mapeado o no se resuelve en el tipo esperado, es posible modificarlo a medida, usando llamados a registerHibernateType en el dialecto.

16.1.2. Consultas con entidades

151 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

Las consultas precedentes consistan todas en devolver valores escalares, bsicamente devolviendo los valores "crudos" desede el resultset. A continuacin se muestra cmo obtener objetos de entidad desde una consulta nativa, a travs de addEntity().
sess.createSQLQuery("SELECT * FROM CATS").addEntity(Cat.class); sess.createSQLQuery("SELECT ID, NAME, BIRTHDATE FROM CATS").addEntity(Cat.class);

Esta consulta especific: la cadena SQL de la consulta la entidad devuelta por la consulta Suponiendo que Cat est mapeado como clase, con las columnas ID, NAME y BIRTHDATE, las 2 consultas precedentes devolvern una List en la cual cada elemento es una entidad Cat. Si la entidad est mapeada a otra entidad con una asociacin many-to-one (de-muchos-a-uno), es necesario devolver tambin eso al efectuar la consulta nativa, de otro modo ocurrir un error especfico de base de datos del tipo "columna no encontrada". Las columnas adicionales sern devueltas automticamente cuando se use la notacin *, pero se prefiere la forma explcita, como en el siguiente ejemplo en donde tenemos una relacin 'de-muchos-a-uno' con un Dog:
sess.createSQLQuery("SELECT ID, NAME, BIRTHDATE, DOG_ID FROM CATS").addEntity(Cat.class);

Esto permitir que cat.getDog() funcione correctamente.

16.1.3. Manipular colecciones y asociaciones


Es posible asociar Dog Dog en forma "ansiosa" a fin de evitar el posible viaje extra ida y vuelta a la base de datos para inicializar el proxy. Esto se hace usando el mtodo addJoin(), el cual permite efectuar el vnculo con asociaciones o colecciones.
sess.createSQLQuery("SELECT c.ID, NAME, BIRTHDATE, DOG_ID, D_ID, D_NAME FROM CATS c, DOGS d WHERE c .addEntity("cat", Cat.class) .addJoin("cat.dog");

En este ejemplo, los Cats devueltos tendrn su propiedad dog enteramente inicializada, sin necesitad de un viaje adicional de ida y vuelta a la BD. Note que hemos agregado un nombre de alias ("cat") para poder especificar la propiedad de destino del join. Es posible hacer este mismo tipo de join "vido" para colecciones, por ejemplo, si el Cat tuviera varios Dogs asociados de-uno-a-muchos.
sess.createSQLQuery("SELECT ID, NAME, BIRTHDATE, D_ID, D_NAME, CAT_ID FROM CATS c, DOGS d WHERE c.I .addEntity("cat", Cat.class) .addJoin("cat.dogs");

Llegados a este punto, casi hemos alcanzado el lmite de lo que se puede hacer con consultas nativas, antes de empezar a mejorar su SQL para que sean usables en Hibernate. El problema comienza cuando se devuelven mltiples entidades del mismo tipo, o cuando los alias/nombres de columna empleados por defecto no son suficientes.

16.1.4. Devolver mltiples entidades


En los ejemplos precedentes, se asume que los nombres de columna del resultado son los mismos que los nombres de columna especificados en el documento de mapeo. Esto puede ser problematico cuando las consultas SQL tiene "joins" entre varias tablas, dado que pueden aparecer los mismos nombres de columna en ms de una tabla. En el ejemplo siguiente (que muy probablemente fallar), se necesita inyectar el alias de columna:
sess.createSQLQuery("SELECT c.*, m.* .addEntity("cat", Cat.class) .addEntity("mother", Cat.class); FROM CATS c, CATS m WHERE c.MOTHER_ID = c.ID")

Lo que se intenta es que esta consulta devuelva dos instancias de Cat por fila: un gato y su madre. Esto fallar, dado que hay un conflicto de nombres, porque estn mapeados a los mismos nombres de columna, y, en algunas bases de datos, los alias de columna devueltos muy probablemente tendrn la forma "c.ID", "c.NAME", etc., lo cual no coincide con las

152 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

columnas especificadas en el mapeo ("ID" y "NAME"). La forma siguiente no es vulnerable a esta duplicacin del nombre de columna:
sess.createSQLQuery("SELECT {cat.*}, {mother.*} .addEntity("cat", Cat.class) .addEntity("mother", Cat.class); FROM CATS c, CATS m WHERE c.MOTHER_ID = c.ID")

Esta consulta especific: la cadena de la consulta SQL, con parmetros de sustitucin (placeholders) para que hibernate inyecte los alias de columna las entidades devueltas por la consulta La notacin con {cat.*} y {mother.*} usada anteriormente es taquigrafa por "todas las propiedades". Alternativamente, se puede listar las columnas explcitamente, pero incluso en ese caso dejamos que Hibernate inyecte los alias de columna SQL para cada propiedad. El parmetro de sustitucin para un alias de columna es simplemente el nombre de la propiedad calificado por el alias de la tabla. En el ejemplo siguiente, obtenemos los Cats (gatos) y sus madres desde una tabla diferente (cat_log) a la declarada en los metadatos de mapeo. Note que incluso se puede usar los alias de propiedad en la clusula "where" si se quiere.
String sql = "SELECT ID as {c.id}, NAME as {c.name}, " + "BIRTHDATE as {c.birthDate}, MOTHER_ID as {c.mother}, {mother.*} " + "FROM CAT_LOG c, CAT_LOG m WHERE {c.mother} = c.ID"; List loggedCats = sess.createSQLQuery(sql) .addEntity("cat", Cat.class) .addEntity("mother", Cat.class).list();

16.1.4.1. Alias y referencias a propiedades


Par la mayora de los casos, inyeccin de alias es todo lo que se necesita. Pero para consultas relacionadas con mapeos ms complejos, como discriminadores de herencia o propiedades compuestas, hay algunos alias especficos que Hibernate debe usar para preservar el correcto funcionamiento de la inyeccin de alias. La tabla siguiente muestra las diferentes posibilidades al usar inyeccin de alias. Nota: los nombres de alias en el resultado son ejemplos, cada alias tendr un nombre nico y probablemente diferente cuando se use. Tabla 16.1. Nombres de inyeccin de alias Descripcin Una propiedad simple Una propiedad compuesta El discriminador de una entidad Todas las propiedades de una entidad Una clave de coleccin El id de una coleccin El elemento de una coleccin Una propiedad de elemento en la coleccin Todas las propiedades del elemento en la coleccin Sintaxis
{[aliasname].[propertyname] {[aliasname].[componentname]. [propertyname]} {[aliasname].class}

Ejemplo
A_NAME as {item.name} CURRENCY as {item.amount.currency}, VALUE as {item.amount.value} DISC as {item.class}

{[aliasname].*} {[aliasname].key} {[aliasname].id} {[aliasname].element} {[aliasname].element. [propertyname]} {[aliasname].element.*}

{item.*} ORGID as {coll.key} EMPID as {coll.id} XID as {coll.element}

NAME as {coll.element.name}

{coll.element.*}

153 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

Descripcin Todas las propiedades de la coleccin

Sintaxis
{[aliasname].*} {coll.*}

Ejemplo

16.1.5. Devolver entidades no administradas


Es posible aplicarles un ResultTransformer a las consultas SQL nativas, permitiendo, por ejemplo, devolver entidades no-manejadas.
sess.createSQLQuery("SELECT NAME, BIRTHDATE FROM CATS") .setResultTransformer(Transformers.aliasToBean(CatDTO.class))

La consulta especific: la cadena SQL de la consulta un transformador de resultado (result transformer) La consulta precedente devolver una lista de CatDTO, la cual habr sido instanciada y habr inyectado los valores de NAME y BIRTHNAME en las propiedades o campos correspondientes.

16.1.6. Manejar herencia


Las consultas de SQL nativas que consulten entidades que estn mapeadas como parte de una herencia, deben incluir todas las propiedades para la clase base y las subclases.

16.1.7. Parmetros
Las consultas SQL nativas soportan parmetros tanto nombrados como posicionales:
Query query = sess.createSQLQuery("SELECT * FROM CATS WHERE NAME like ?").addEntity(Cat.class); List pusList = query.setString(0, "Pus%").list(); query = sess.createSQLQuery("SELECT * FROM CATS WHERE NAME like :name").addEntity(Cat.class); List pusList = query.setString("name", "Pus%").list();

16.2. Consultas SQL nombradas


Las consultas SQL nombradas (named SQL queries) pueden definirse en el documento de mapeo y ser invocadas exactamente en la misma forma que una consulta HQL nombrada. En este caso, no necesitamos invocar addEntity().
<sql-query name="persons"> <return alias="person" class="eg.Person"/> SELECT person.NAME AS {person.name}, person.AGE AS {person.age}, person.SEX AS {person.sex} FROM PERSON person WHERE person.NAME LIKE :namePattern </sql-query> List people = sess.getNamedQuery("persons") .setString("namePattern", namePattern) .setMaxResults(50) .list();

Los elementos <return-join> y <load-collection> se usan, respectivamente, para asociaciones de tipo "join", y para definir consultas que inicialicen colecciones.
<sql-query name="personsWith"> <return alias="person" class="eg.Person"/> <return-join alias="address" property="person.mailingAddress"/>

154 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

SELECT person.NAME AS {person.name}, person.AGE AS {person.age}, person.SEX AS {person.sex}, address.STREET AS {address.street}, address.CITY AS {address.city}, address.STATE AS {address.state}, address.ZIP AS {address.zip} FROM PERSON person JOIN ADDRESS address ON person.ID = address.PERSON_ID AND address.TYPE='MAILING' WHERE person.NAME LIKE :namePattern </sql-query>

Una consulta SQL nombrada puede devolver un valor escalar. Hya que declarar el alias de la columna y el tipo de Hibernate usando el elemento <return-scalar> element:
<sql-query name="mySqlQuery"> <return-scalar column="name" type="string"/> <return-scalar column="age" type="long"/> SELECT p.NAME AS name, p.AGE AS age, FROM PERSON p WHERE p.NAME LIKE 'Hiber%' </sql-query>

Se puede externalizar el resultado, mapeando informacin en un elemento <resultset> para reutilizarlo, ya sea en otras consultas nombradas, o a travs de la API setResultSetMapping().
<resultset name="personAddress"> <return alias="person" class="eg.Person"/> <return-join alias="address" property="person.mailingAddress"/> </resultset> <sql-query name="personsWith" resultset-ref="personAddress"> SELECT person.NAME AS {person.name}, person.AGE AS {person.age}, person.SEX AS {person.sex}, address.STREET AS {address.street}, address.CITY AS {address.city}, address.STATE AS {address.state}, address.ZIP AS {address.zip} FROM PERSON person JOIN ADDRESS address ON person.ID = address.PERSON_ID AND address.TYPE='MAILING' WHERE person.NAME LIKE :namePattern </sql-query>

Alternativamente, se puede usar la informacin de mapeo del resultset contenida en los archivos hbm, directamente en el cdigo Java.
List cats = sess.createSQLQuery( "select {cat.*}, {kitten.*} from cats cat, cats kitten where kitten.mother = cat.id" ) .setResultSetMapping("catAndKitten") .list();

16.2.1. Usar return-property para especificar nombres de columna/alias explcitamente


Con <return-property> se le puede deicr a Hibernate explcitamente qu alias de columna usar, en lugar de usar la sintaxis {} para dejar que Hibernate inyecte sus propios alias.
<sql-query name="mySqlQuery"> <return alias="person" class="eg.Person"> <return-property name="name" column="myName"/> <return-property name="age" column="myAge"/> <return-property name="sex" column="mySex"/> </return> SELECT person.NAME AS myName,

155 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

person.AGE AS myAge, person.SEX AS mySex, FROM PERSON person WHERE person.NAME LIKE :name </sql-query> <return-property> tambin funciona con mltiples columnas. Esto soluciona la limitacin de la sintaxis {}, la cual no permite un control tan minucioso de las propiedades multicolumna. <sql-query name="organizationCurrentEmployments"> <return alias="emp" class="Employment"> <return-property name="salary"> <return-column name="VALUE"/> <return-column name="CURRENCY"/> </return-property> <return-property name="endDate" column="myEndDate"/> </return> SELECT EMPLOYEE AS {emp.employee}, EMPLOYER AS {emp.employer}, STARTDATE AS {emp.startDate}, ENDDATE AS {emp.endDate}, REGIONCODE as {emp.regionCode}, EID AS {emp.id}, VALUE, CURRENCY FROM EMPLOYMENT WHERE EMPLOYER = :id AND ENDDATE IS NULL ORDER BY STARTDATE ASC </sql-query>

Note que en este ejemplo utilizamos <return-property> en combinacin con la sintaxis {} para inyectar, permitindole al usuario decidir cmo prefiere referirse a columnas y propiedades. Si su mapeo tiene un discriminador, debe usarse <return-discriminator> para especificar la columna discriminadora.

16.2.2. Usar procedimientos almacenados para efectuar consultas


Hibernate 3 introduce soporte para consultas va procedimientos almacenados (stored procedures) y funciones. La mayora de la documentacin que sigue es equivalente para ambos. El procedimiento/funcin debe devolver un conjunto resultado o "resultset" como primer parmetro de salida, a fin de poder trabajar con Hibernate. A continuacn, un ejemplo de funcin en Oracle 9 o superior:
CREATE OR REPLACE FUNCTION selectAllEmployments RETURN SYS_REFCURSOR AS st_cursor SYS_REFCURSOR; BEGIN OPEN st_cursor FOR SELECT EMPLOYEE, EMPLOYER, STARTDATE, ENDDATE, REGIONCODE, EID, VALUE, CURRENCY FROM EMPLOYMENT; RETURN st_cursor; END;

Para usar esta consulta en Hibernate, hay que mapearla con una consulta "nombrada".
<sql-query name="selectAllEmployees_SP" callable="true"> <return alias="emp" class="Employment"> <return-property name="employee" column="EMPLOYEE"/> <return-property <return-property <return-property <return-property <return-property <return-property name="employer" column="EMPLOYER"/> name="startDate" column="STARTDATE"/> name="endDate" column="ENDDATE"/> name="regionCode" column="REGIONCODE"/> name="id" column="EID"/> name="salary">

<return-column name="VALUE"/> <return-column name="CURRENCY"/> </return-property> </return> { ? = call selectAllEmployments() } </sql-query>

156 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

collection>

Note que los procedimientos almacenados actualmente slo devuelven escalares o entidades. <return-join> y <loadno se soportan.

16.2.2.1. Reglas y limitaciones en el uso de procedimientos almacenados


Para usar procedimientos almacenados con Hibernate, el procedimiento o funcin debe seguir ciertas reglas. Si no sigue esas reglas, es incompatible con Hibernate. Si an se desea usar estos procedimientos incompatibles, hay que ejecutarlos via session.connection(). Las reglas son diferentes para cada base de datos, dado que cada proveedor de base de datos tiene una semntica y una sintaxis distinta pars los procedimientos almacenados. Los procedimientos almacenados no pueden ser paginados con setFirstResult()/setMaxResults(). La invocacin recomendada es el estdar de SQL92: { ? = call functionName(<parameters>) } or { ? = call procedureName(<parameters>}. Los llamdos nativos no se soportan. Para Oracle, se aplican las siguientes reglas: Las funciones deben devolver un resultado "resultset". El primer parmetro de los procedimientos almacenados debe ser un parmeto de tipo "OUT" que devuelva un resultset. Esto se logra usando un tipo SYS_REFCURSOR en Oracle 9 o 10. En Oracle hay que definir un tipo REF CURSOR, consulte la literatura de Oracle. Para Sybase o MS SQL server se aplican las siguientes reglas: El procedimiento debe devolver un resultset. Note que, como estos servidores son capaces de devolver mltiples resultsets y contadores de actualizacin, Hibernate recorrer los resultados y tomar el primer resultado que sea resultset. El resto se descarta. Si usted puede habilitar SET NOCOUNT ON en su procedimiento, seguramente ste ser ms eficiente, pero esto no es obligatorio.

16.3. SQL a medida para crear, modificar o borrar


Hibernate3 puede usar comandos SQL a medida para operaciones de creacin, actualizacin y borrado. Los "persistores" de clases y colecciones en Hibernate ya contienen un conjunto de cadenas (insertsql, deletesql, updatesql etc.) generadas en tiempo de configuracin. Las tags de mapeo <sql-insert>, <sql-delete>, y <sql-update> suplantan easas cadenas
<class name="Person"> <id name="id"> <generator class="increment"/> </id> <property name="name" not-null="true"/> <sql-insert>INSERT INTO PERSON (NAME, ID) VALUES ( UPPER(?), ? )</sql-insert> <sql-update>UPDATE PERSON SET NAME=UPPER(?) WHERE ID=?</sql-update> <sql-delete>DELETE FROM PERSON WHERE ID=?</sql-delete> </class>

El SQL es ejecutado directamente en su base de datos, as que usted es libre de utilizar cualquier dialecto que desee. Por supuesto, usar SQL especfico de una base de datos reducir la "portabilidad" de su aplicacin. Los procedimientos almacenados se soportan, si se configura el atributo callable:
<class name="Person"> <id name="id"> <generator class="increment"/> </id> <property name="name" not-null="true"/> <sql-insert callable="true">{call createPerson (?, ?)}</sql-insert> <sql-delete callable="true">{? = call deletePerson (?)}</sql-delete> <sql-update callable="true">{? = call updatePerson (?, ?)}</sql-update> </class>

157 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

El orden de los parmetros posicionales es ahora esencial, dado que deben estar en la misma secuencia en que Hibernate los espera. Se puede ver el orden esperado, habilitando logueo a nivel "debug" en org.hibernate.persister.entity. Con esta categora habilitada,, Hibernate imprimir el SQL esttico que se usa para crear entidades, actualizarlas, borrarlas, etc. (Para ver la secuencia esperada, recuerde no incluir su SQL a medida en los archivos de mapeo, dado que ste suplantar al SQL esttico generado por Hibernate). En la mayora de los casos, es obligatorio (o ms bien, fuertemente recomendado) que los procedimientos almacenados devuelvan el nmero de filas insertadas/actualizadas/borradas, porque Hibernate realiza algunos chequeos en tiempo de ejecucin para verificar el xito del comando. Hibernate siempre registra el primer parmetro del "statement" como de salida y numrico, para las operaciones de ABM (alta-baja-modificacin):
CREATE OR REPLACE FUNCTION updatePerson (uid IN NUMBER, uname IN VARCHAR2) RETURN NUMBER IS BEGIN update PERSON set NAME = uname, where ID = uid; return SQL%ROWCOUNT; END updatePerson;

16.4. SQL a medida para cargar


Se puede tambin declarar comandos SQL (o HQL) a medida para cargar entidades:
<sql-query name="person"> <return alias="pers" class="Person" lock-mode="upgrade"/> SELECT NAME AS {pers.name}, ID AS {pers.id} FROM PERSON WHERE ID=? FOR UPDATE </sql-query>

Esta es, simplemente, una declaracin de una consulta nombrada (named query), como se discuti anteriormente. Se puede hacer referencia a esta consulta nombrada en el mapeo de clases:
<class name="Person"> <id name="id"> <generator class="increment"/> </id> <property name="name" not-null="true"/> <loader query-ref="person"/> </class>

Esto funciona incluso con procedimientos almacenados. Se puede incluso definir un a consulta para cargar la coleccin:
<set name="employments" inverse="true"> <key/> <one-to-many class="Employment"/> <loader query-ref="employments"/> </set> <sql-query name="employments"> <load-collection alias="emp" role="Person.employments"/> SELECT {emp.*} FROM EMPLOYMENT emp WHERE EMPLOYER = :id ORDER BY STARTDATE ASC, EMPLOYEE ASC </sql-query>

158 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

Hasta se puede definir un "cargador de entidades" que cargue una coleccn mediante captura con "join":
<sql-query name="person"> <return alias="pers" class="Person"/> <return-join alias="emp" property="pers.employments"/> SELECT NAME AS {pers.*}, {emp.*} FROM PERSON pers LEFT OUTER JOIN EMPLOYMENT emp ON pers.ID = emp.PERSON_ID WHERE ID=? </sql-query>

Captulo 17. Filtrar datos


Hibernate3 provee un enfoque innovador para manejar datos que tengan "reglas de visibilidad". Un filtro de Hibernate es un filtro global, nombrado y parametrizado, que puede estar habilitado o inhabilitado para una sesin en particular.

17.1. Filtros de Hibernate


Hibernate3 incorpora la capacidad de predefinir criterios de filtrado, y adjuntar esos filtros tanto a nivel de la clase como a nivel de la coleccin. Un cirterio de filtrado es la capacidad de definir una clusula de restriccin, muy similar al atributo "where" disponible en la clase y varios elementos de colecciones. Excepto que estas condiciones de filtrado pueden ser parametrizadas. La aplicacin puede, entoces, tomar decisiones en tiempo de ejecucin acerca de si un filtro debera estar habilitado, y cules deberan ser sus parmetros. Los filtros pueden ser usados como vistas (views) de la base de datos, pero parametrizados dentro de la aplicacin. Para usar filtros, primero tienen que ser definidos y adjuntados al elemento de mapeo correspondiente. Para definir un filtro, use el elemento <filter-def/> dentro de un elemento de <hibernate-mapping/>:
<filter-def name="myFilter"> <filter-param name="myFilterParam" type="string"/> </filter-def>

Luego, este filtro puede ser adosado a una clase:


<class name="myClass" ...> ... <filter name="myFilter" condition=":myFilterParam = MY_FILTERED_COLUMN"/> </class>

o a una coleccin:
<set ...> <filter name="myFilter" condition=":myFilterParam = MY_FILTERED_COLUMN"/> </set>

o incluso a ambas, o a varias de ambas, al mismo tiempo. Los mtodos en Session son: enableFilter(String filterName), getEnabledFilter(String filterName), y disableFilter(String filterName). Por defecto, los filtros no estn habilitados para una sesin dada; deben ser habilitados explcitamente mediante el uso del mtodo Session.enableFilter(), el cual devuelve una instancia de la interfaz Filter. Usando el filtro simple definido antes, esto se vera as:
session.enableFilter("myFilter").setParameter("myFilterParam", "some-value");

Note que hay mtodos en la interfaz org.hibernate.Filter que permiten el encadenamiento de filtros, muy comn en Hibernate. Un ejemplo completo, usando datos con el patrn de programacin conocido como "fecha efectiva" (effective date):
<filter-def name="effectiveDate"> <filter-param name="asOfDate" type="date"/>

159 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

</filter-def> <class name="Employee" ...> ... <many-to-one name="department" column="dept_id" class="Department"/> <property name="effectiveStartDate" type="date" column="eff_start_dt"/> <property name="effectiveEndDate" type="date" column="eff_end_dt"/> ... <!-Note que esto asume que los registros no-terminales tinenen una fecha de finalizacin efect a la cual se le asign el mximo valor de fecha posible en la BD, para simplificar. --> <filter name="effectiveDate" condition=":asOfDate BETWEEN eff_start_dt and eff_end_dt"/> </class> <class name="Department" ...> ... <set name="employees" lazy="true"> <key column="dept_id"/> <one-to-many class="Employee"/> <filter name="effectiveDate" condition=":asOfDate BETWEEN eff_start_dt and eff_end_dt"/> </set> </class>

Luego, para asegurarse de que siempre se obtiene el registro ms actual, simplemente habilite el filtro en la sesin, antes de capturar datos de empleados:
Session session = ...; session.enableFilter("effectiveDate").setParameter("asOfDate", new Date()); List results = session.createQuery("from Employee as e where e.salary > :targetSalary") .setLong("targetSalary", new Long(1000000)) .list();

En el HQL precedente, incluso si slo se mencion una condicin relativa al salario en los resultados, la consulta devolver los empleados que con un salario mayor a un milln y, a causa del filtro habilitado, que estn actualmente activos. Nota: si se planea usar filtros con "outer joins" (sea a travs de HQL o de estrategias de "fetch") tenga cuidado con la direccin de la expresin de condicin. Lo ms seguro es configurarlo como "left outer join"; en general, ponga el parmetro primero, seguido por el nombre o nombres de columna luego del operador. Luego de haber sido definido, un filtro puede ser adosado a entidades y/o colecciones, cada una con su propia condicin. Eso puede ser tedioso cuando las condiciones son las mismas en todos los casos. Por esto, <filter-def/> permite definir una condicin por defecto, sea como un atributo, o como CDATA:
<filter-def name="myFilter" condition="abc > xyz">...</filter-def> <filter-def name="myOtherFilter">abc=xyz</filter-def>

Entonces, esta condicin por defecto ser usada siempre que el filtro se adjunte a algo sin haber especificado una condicin. Note que esto significa que se puede dar una condicin especfica como parte de la adjuncin del filtro, que suplanta a la condicin por defecto para ese caso en particular.

Captulo 18. Mapeo XML


Note que sta es una caracterstica experimental en Hibernate 3.0, y se encuentra actualmente en muy activo desarrollo.

18.1. Trabajar con datos XML


Hibernate le permite trabajar con datos persistentes en XML de la misma forma en que lo hara con POJOs. Un rbol XML vlido puede ser concebido como sencillamente otra forma de representar los datos relacionales a nivel de objetos, en lugar de los POJOs. Hibernate soporta la API dom4j para manipular los rboles XML. Se puede escribir consultas que obtengan rboles dom4j

160 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

desde la base de datos, y lograr que cualquier modificacin practicada al XML se sincronice automticamente a la base de datos. Incluso se puede tomar un documento XML, analizarlo usando dom4j, y escribirlo en la base de datos con cualquiera de las operaciones bsicas de Hibernate: persist(), saveOrUpdate(), merge(), delete(), replicate() (merge an no se soporta). Esta habilidad tiene muchos usos, incluyendo: importacin/exportacin de datos, externalizacin de entidades via JMS o SOAP, y produccin de reportes basada en XSLT. Un solo mapeo puede ser usado para mapear simultneamente las propiedades de una clase y los nodos de un documento XML a la base de datos, o, si no hay ninguna clase para mapear, slo el documento XML.

18.1.1. Especificar el mapeo XML y el mapeo de la clase al mismo tiempo


He aqu un ejemplo de mapeo de un POJO y XML simultneamente:
<class name="Account" table="ACCOUNTS" node="account"> <id name="accountId" column="ACCOUNT_ID" node="@id"/> <many-to-one name="customer" column="CUSTOMER_ID" node="customer/@id" embed-xml="false"/> <property name="balance" column="BALANCE" node="balance"/> ... </class>

18.1.2. Especificar slo un mapeo XML


He aqu un ejemplo en el cual no hay clase POJO:
<class entity-name="Account" table="ACCOUNTS" node="account"> <id name="id" column="ACCOUNT_ID" node="@id" type="string"/> <many-to-one name="customerId" column="CUSTOMER_ID" node="customer/@id" embed-xml="false" entity-name="Customer"/> <property name="balance" column="BALANCE" node="balance" type="big_decimal"/> ... </class>

Este mapeo permite acceder a los datos como si fueran un rbol dom4j, o una representacin en forma de pares nombre/valor (Maps de Java). Los nombres de las propiedades son construcciones puramente lgicas, a las que se puede hacer referencia en consultas HQL.

18.2. Metadatos de mapeo XML


Muchos elementos de mapeo de Hibernate aceptan el atributo node (nodo). Esto permite especificar el nombre de un atributo o elemento XML que contenga la propiedad o dato de entidad. El formato del atributo node debe ser uno de los siguientes:
"element-name": mapea

al elemento XML especificado al atributo XML especificado.

"@attribute-name": mapea ".": mapea

al elemento padre. al elemento especificado del atributo especificado.

"element-name/@attribute-name": mapea

Para asociaciones y asociaciones a valores simples, hay un atributo embed-xml adicional. Si se especifica embedes el valor por defecto, el rbol XML para la entidad asociada (la de tipo coleccin o "value type") ser incrustada directamente en el rbol XML de la entidad que posee la asociacin. En caso contrario, si embedxml="false", entonces slo el valor del identificador al que se hace referencia aparecer en el XML (para asociaciones
xml="true", lo cua

161 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

de "value type"s) y para las colecciones no aparecer nada. Debera tenerse cuidado de no asignarles embed-xml="true" a demasiadas asociaciones, dado que XML no sabe lidiar muy bien con recursividad!
<class name="Customer" table="CUSTOMER" node="customer"> <id name="id" column="CUST_ID" node="@id"/> <map name="accounts" node="." embed-xml="true"> <key column="CUSTOMER_ID" not-null="true"/> <map-key column="SHORT_DESC" node="@short-desc" type="string"/> <one-to-many entity-name="Account" embed-xml="false" node="account"/> </map> <component name="name" node="name"> <property name="firstName" node="first-name"/> <property name="initial" node="initial"/> <property name="lastName" node="last-name"/> </component> ... </class>

en este caso, hemos decidido incrustar una coleccin de ids de cuentas (accounts), pero no los datos de las cuentas propiamente dichas. La siguiente consulta HQL:
from Customer c left join fetch c.accounts where c.lastName like :lastName

Devolvera datos como stos:


<customer id="123456789"> <account short-desc="Savings">987632567</account> <account short-desc="Credit Card">985612323</account> <name> <first-name>Gavin</first-name> <initial>A</initial> <last-name>King</last-name> </name> ... </customer>

Si se asigna embed-xml="true" en el mapeo <one-to-many>, los datos se veran as:


<customer id="123456789"> <account id="987632567" short-desc="Savings"> <customer id="123456789"/> <balance>100.29</balance> </account> <account id="985612323" short-desc="Credit Card"> <customer id="123456789"/> <balance>-2370.34</balance> </account> <name> <first-name>Gavin</first-name> <initial>A</initial> <last-name>King</last-name> </name> ... </customer>

18.3. Manipular datos XML

162 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

Vamos a leer y actualizar documentos XML en la aplicacin. Lo hacemos obteniendo una sesin dom4j:
Document doc = ....; Session session = factory.openSession(); Session dom4jSession = session.getSession(EntityMode.DOM4J); Transaction tx = session.beginTransaction(); List results = dom4jSession .createQuery("from Customer c left join fetch c.accounts where c.lastName like :lastName") .list(); for ( int i=0; i<results.size(); i++ ) { //le agrega los datos del cliente (customer) al documento XML Element customer = (Element) results.get(i); doc.add(customer); } tx.commit(); session.close(); Session session = factory.openSession(); Session dom4jSession = session.getSession(EntityMode.DOM4J); Transaction tx = session.beginTransaction(); Element cust = (Element) dom4jSession.get("Customer", customerId); for ( int i=0; i<results.size(); i++ ) { Element customer = (Element) results.get(i); //cambia el nombre del cliente en el XML y en la BD Element name = customer.element("name"); name.element("first-name").setText(firstName); name.element("initial").setText(initial); name.element("last-name").setText(lastName); } tx.commit(); session.close();

Combinar esta funcionalidad con la operacin replicate() es extremadamente til para implementar la importacin/exportacin de datos basados en XML:

Captulo 19. Mejorar la performance 19.1. Estrategias de captura (fetch)


Una estrategia de captura es la estrategia que Hibernate usar para obtener los objetos asociados, cuando Hibernate necesite navegar una asociacin. Las estrategias de captura pueden ser declaradase en los metadatos de mapeo, o bien ser sustituidas para una consulta HQL o Criteria en particular. Hibernate3 define las siguientes estategias de captura: captura por Join Hibernate obtiene la instancia o coleccin asociada, agregndole un OUTER JOIN al SELECT mismo. captura por Select: se usa un segundo SELECT para obtener la entidad o coleccin asociada. A menos que se inhabilite la captura haragana (lazy fetching) especificando lazy="false", este segundo SELECT slo se ejecutar cuando realmente se acceda a la asociacin. captura poe Subselect: se usa un segundo SELECT para obtener todas las entidades o colecciones asociadas, que se haban obtenido en el SELECT anterior. A menos que se inhabilite la captura haragana (lazy fetching) especificando lazy="false", este segundo SELECT slo se ejecutar cuando realmente se acceda a la asociacin. captura por lotes (batch fetching): es una estrategia de optimizacin de la captura por Select; Hibernate obtiene no una, sino un lote (batch) de instancias de entidad o coleccin en un solo SELECT, especificando no una, sino una lista de claves primarias o forneas. Hibernate tambin distingue entre: captura inmediata: la asociacin. coleccin o atributo son capturados inmediatamente, cuando el dueo es cargado.

163 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

captura haragana de colecciones: una coleccin es capturada slo cuando la aplicacn invoca alguna operacin en esa coleccin (ste es el comportamiento por defecto para las colecciones). captura "sper-haragana" de colecciones (extra-lazy collection fetching): se accede a elementos individuales de la coleccin desde la base de datos, slo en la medida en que se necesita. Hibernate no intenta capturar toda la coleccin en memoria, a menos que sea absolutamente necesario (esto es lo adecuado para colecciones muy extensas). captura por Proxy: una asociacin de un solo valor se captura cuando se invoca sobre ste cualquier otro mtodo que no sea su getter/setter. captura sin proxy: una asociacin de un solo valor se captura cuando se accede a la variable de instancia . En comparacin con la captura por proxy, este abordaje es menos haragn (se accede a la asociacin incluso si slo se usa el identificador), pero ms transparente, dado que no hay ningn proxy visible para la aplicacn. Este abordaje requiere instrumentacin bytecode de tiempo de compilacin, y slo raramente es necesario. captura haragana de atributos: un atributo o asociacin de valor simple, se capturan cuando se accede a la instancia o asociacin. Este abordaje requiere instrumentacin bytecode de tiempo de compilacin, y slo raramente es necesario. Aqu tenemos dos nociones ortogonales: cundo la asociacin se captura, y cmo se captura (qu SQL se usa). A no confundir una con la otra! Se usa la palabra fetch para ajustar la eprformance. Se puede usar la palabra lazy para definir un contrato sobre qu estar disponible y qu estar desprendido para una clase en particular.

19.1.1. Trabajar con asociaciones haraganas


Hibernate3 usa por defecto "select haragn" para las colecciones, y "captura haragana por proxy" para las asociaciones de valor simple. Estos valores por defecto tienen sentido casi siempre, y para casi todas las asociaciones. Nota: si se inicializa la variable de configuracin hibernate.default_batch_fetch_size, Hibernate usar la optimizacin de captura por lotes para las capturas haraganas. Esta optimizacin puede tambin ser habilitada a un nivel ms granular. De todos modos, la captura haragana plantea un problema del cual hay que ser consciente: acceder a asociaciones haraganas por fuera del contexto de una sesin abierta de Hibernate, resultar en una excepcin. Por ejemplo.
s = sessions.openSession(); Transaction tx = s.beginTransaction(); User u = (User) s.createQuery("from User u where u.name=:userName") .setString("userName", userName).uniqueResult(); Map permissions = u.getPermissions(); tx.commit(); s.close(); Integer accessLevel = (Integer) permissions.get("accounts"); // Error!

Como la coleccin "permissions" no estaba inicializada cuando la sesin fue cerrada, la coleccin ser incapaz de cargar su estado. Hibernate no soporta la inicializacin haragana de objetos desprendidos. La solucin es mover el cdigo que lee de la coleccin a justo antes de que la transaccin invoque "commit". Alternativamente, podramos usar una coleccin o asociacin no haragana, especificando lazy="false" para el mapeo de la asociacin. De todos modos, se espera que se use inicializacin haragana en casi todos los casos. Si se definen demasiadas asociaciones no haraganas, Hibernate terminar cargando toda la base de datos en memoria para cada transaccin! Por otra parte, a menudo querremos elegir captura por join (la cual que es naturalmente no haragana) en lugar de captura por select, para una transaccin en particular. Ahora veremos cmo disear una estrategia de captura a medida. En Hibernate3, los mecanismos para elegir una estrategia de captura son idnticos para las asociaciones de valor simple y para las colecciones.

19.1.2. Ajustar las estrategias de captura


La captura por select (el comportamiento por defecto) es extremadamente vulnerable a los problemas de N+1 SELECTS.

164 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

As que tal vez querramos habilitar la captura por join en el documento de mapeo.
<set name="permissions" fetch="join"> <key column="userId"/> <one-to-many class="Permission"/> </set <many-to-one name="mother" class="Cat" fetch="join"/>

La estrategia de captura (fetch) definida en el documentod e mapeo afecta a: la obtencin de datos via get() o load() la obtencin de datos que ocurre implcitamente cuando se navega la asociacin las consultas Criteria las consultas HQL (si se usa la captura por subselect ) Sin importar qu estrategia de captura se use, se garantiza que el rbol "no haragn" definido se cargar en memoria. Note que esto puede resultar en que se usen varios SELECTs inmediatamente para ejecutar una consulta HQL en particular. Normalmente no usaremos el documento de mapeo para ajustar el tipo de captura. En cambio, mentendremos el comportamiento por defecto, y lo sustituiremos para una transaccin en particular, usando left join fetch en HQL. Esto le dice a Hibernate que capture la asociacn en forma ansiosa, en el primer SELECT, usando un outer join. En la API de consultas Criteria, se usara setFetchMode(FetchMode.JOIN).
Criteria, por

Si se deseare cambiar la estrategia de captura usada por get() or load(), simplemente habra que usar una consulta ejemplo:
User user = (User) session.createCriteria(User.class) .setFetchMode("permissions", FetchMode.JOIN) .add( Restrictions.idEq(userId) ) .uniqueResult();

(ste es el equivalente en Hibernate de lo que algunas soluciones ORM llaman un plan de captura o "fetch plan"). Una forma completamente distinta de evitar los problemas con N+1 selects es usar el cach de 2do nivel.

19.1.3. Proxies de asociaciones de un solo extremo


La captura haragana para colecciones se implementa usando la implementacin para colecciones persistentes de Hibernate mismo. Sin embargo, se necesita un mecanismo diferente para el comportamiento haragn en las asociaciones de extremo simple. A la entidad blanco de la asociacin se le debe crear un "proxy". Hibernate implementa los proxies de inicializacin haragana para objetos persistentes usando "mejora de bytecode en tiempo de ejecucin" (a travs de la excelente biblioteca CGLIB). Hibernate3 genera proxies por defecto (durante el arranque) para todas las clases persistentes, y los usa para habilitar la captura haragana de asociaciones 'de-muchos-a-uno' (many-to-one) y de-uno-a-uno (one-to-one). El archivo de mapeo puede declarar una interfaz para ser usada como la "interfaz de proxy" para una clase determinada, con el atributo proxy. Hibernate usa por defecto una subclase de la clase. Tenga en cuenta que la clase a la cual se le crea el proxy debe implementar un constructor por defecto (sin parmetros), con visibilidad por defecto o "package" por lo menos. Recomendamos este constructor para todas las clases persistentes! Hay algunas dificultades muy comunes, de las cuales conviene estar al tanto a la hora de extender este enfoque a clases polimrficas; por ejemplo:
<class name="Cat" proxy="Cat"> ...... <subclass name="DomesticCat"> ..... </subclass> </class>

165 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

Primero que nada, las instancias de la clase Cat jams podrn ser convertidas con "cast" a DomesticCat, incluso cuando la instancia subyacente s es una instancia de DomesticCat:
Cat cat = (Cat) session.load(Cat.class, id); if ( cat.isDomesticCat() ) { DomesticCat dc = (DomesticCat) cat; .... } // instancia un proxy (no llama a la base de datos) // llama a la base de datos para inicializar el proxy // Error!

En segundo lugar, es posible romper el operador ==.de proxies.


Cat cat = (Cat) session.load(Cat.class, id); DomesticCat dc = (DomesticCat) session.load(DomesticCat.class, id); System.out.println(cat==dc); // instancia un proxy de Cat // adquiere un nuevo proxy par // falso

Sin embargo, esta situacin no es tan mala como parece. Incluso si ahora tenemos dos referencias a objetos "proxy" diferentes, la instancia subyacente an es el mismo objeto:
cat.setWeight(11.0); // llama a la base de datos para inicializar el proxy System.out.println( dc.getWeight() ); // 11.0

En tercer lugar, no se puede usar un proxy CGLIB para clases final ni para clases que tengan mtodos final. Por ltimo, si su clase persistente adquiere recursos durante la inicializacin (por ejemplo, en inicializadores o constructores por defecto), entonces dichos recursos sern tambin adquiridos por el proxy. La clase proxy es una verdadera subclase de la clase persistente. Estos problemas se deben todos a limitaciones fundamentales del modelo de herencia nica de Java. Si usted quiere evitar estos problemas, cada una de sus clases persistentes debe implementar una interfaz que declare sus mtodos de negocio. Y usted debe especificar estas interfaces en el documento de mapeo. Por ejemplo:
<class name="CatImpl" proxy="Cat"> ... <subclass name="DomesticCatImpl" proxy="DomesticCat"> ... </subclass> </class>

en donde CatImpl implementa la interfaz Cat y DomesticCatImpl implementa la interfaz DomesticCat. As, los proxies para instancias de Cat y DomesticCat pueden ser devueltos por load() o por iterate(). (Note que list() normalmente no devuelve proxies.)
Cat cat = (Cat) session.load(CatImpl.class, catid); Iterator iter = session.createQuery("from CatImpl as cat where cat.name='fritz'").iterate(); Cat fritz = (Cat) iter.next();

Las relaciones tambin son incializadas en forma haragana. Esto significa que toda propiedad debe ser declarada como de tipo Cat, no CatImpl. Ciertas operaciones no requieren inicializacin de proxies:
equals(),

si la clase persistente no sustituye equals() si la clase persistente no sustituye hashCode()

hashCode(),

el getter del mtodo identificador Hibernate detectar las clases persistentes que sustituyan (override) equals() o hashCode(). Eligiendo lazy="no-proxy" en lugar del lazy="proxy" que viene por defecto, podemos evitar los problemas asociados con la conversin ("cast") entre tipos. Sin embargo, necesitaremos instrumentacin de bytecode en tiempo de compilacin, y todas las operaciones resultarn en una inicializacin de proxy inmediata.

19.1.4. Inicializar proxies y colecciones

166 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

Si se trata de acceder a una coleccin o proxy no inicializados fuera del alcance de una sesin, Hibernate emitir una LazyInitializationException. Es decir, cuando la entidad que posea la coleccin o que tienga una referencia al proxy est en un estado desprendido. A veces necesitamos asegurarnos de que un proxy o coleccin sean inicializados antes de cerrar la sesin. Por supuesto, siempre podemos forzar la inicializacin invocando cat.getSex() o cat.getKittens().size(), por ejemplo. Pero esto sera confuso para quien leyere el cdigo, e inconveniente para cualquier cdigo que intentare ser genrico. Los mtodos estticos Hibernate.initialize() e Hibernate.isInitialized() le proveen a la aplicacin una forma conveniente de trabajar con colecciones o proxies que hayan sido inicializados en forma haragana. Hibernate.initialize(cat) forzar la inicializacin del proxy, cat, siempre y cuando su sesin est an abierta. Hibernate.initialize( cat.getKittens() ) tiene un efecto similar para la coleccin de kittens (gatitos). Otra opcin es mantener la sesin abierta hasta que todas las colecciones y proxies necesarios hayan sido cargados. En la arquitectura de algunas aplicaciones, particularmente en donde el cdigo que accede a Hibernate y el cdigo que lo usa estn en distinas capas, o en distintos procesos fsicos, asegurarse de que una nica sesin se mantenga abierta cuando una coleccin se inicialice puede llegar a ser un problema. Hay bsicamente dos maneras de lidiar con esto: En una aplicacin de web, se puede usar un filtro de servlet para cerrar la sesin slo cuando realmente se llegue al final de la request, una vez que la presentacin de la interfaz de usuario (view) ha sido completada (el patrn de programacin Open Session in View ). Por supuesto, esto crea una pesada responsabilidad en cuando a la correccin del manejo de excepciones por parte de la infraestructura de la aplicacin. Es de vital importancia que la sesin sea cerrada y la transaccin concluida antes de retornar el control al usuario, incluso cuando ocurriere una excepcin mientras se presentare la interfaz de usuario. Vea la wiki de Hibernate para ejemplos de este patrn "Open Session in View". En aplicaciones que tengan una capa de negocios separada, la lgica de negocio debe "preparar" todas las colecciones que vayan a ser necesitadas por la capa de web, antes de retornar. Esto significa que la capa de negocios debera cargar todos los datos que hagan falta para un caso en particular, y devolvrselos a la capa de interfaz de usuario/web. Normalmente, la aplicacin llama a Hibernate.initialize() para cada coleccin que vaya a ser necesaria en la capa de web (este llamado ocurre antes de que la sesin se cierre), u obtiene la coleccin en forma ansiosa usando una consulta de Hibernate con clusula FETCH o con un FetchMode.JOIN en el Criteria. Esto es normalmente ms fcil si se adopta el patrn de programacin Command en lugar del patrn Session Faade. Tambin se puede adjuntar un objeto previamente cargado a una nueva sesin, con merge() o lock() antes de acceder a colecciones (u otros proxies) no inicializados. No, Hibernate no debera hacer esto automticamente, puesto que ello introducira una semntica de transaccion ad hoc! A veces usted no querr inicializar toda una coleccin muy extensa, pero s necesitar un poco de informacin acerca de ella (por ejemplo, su tamao), o un subconjunto de sus datos. Se puede usar un filtro de coleccin para obtener el tamao de una coleccin sin inicializarla:
( (Integer) s.createFilter( collection, "select count(*)" ).list().get(0) ).intValue()

El mtodo createFilter() se usa tambin para obtener eficientemente subconjuntos de una coleccin sin necesidad de inicializarla toda.
s.createFilter( lazyCollection, "").setFirstResult(0).setMaxResults(10).list();

19.1.5. Usar la captura por lotes


Hibernate puede hace un uso eficiente de la captura por lotes, es decir que puede cargar varios "proxies" no inicializados cuando se accede a uno. (O colecciones. La captura por lotes es una optimizacin del tipo de captura por "SELECT haragn"). Hay dos maneras de ajustar la captura por lotes: en la clase, o a nivel de la coleccin. La captura por lotes a nivel de la clase es ms fcil de entender. Imagnese que tiene la siguiente situacin en tiempo de ejecucin: Hay 25 instancias de Cat cargadas en la sesin; cada Cat tiene una referencia a su dueo, una instancia de Person. La clase Person est mapeada con un proxy, lazy="true". Si se itera a travs de todos los gatos (cats) y se invoca getOwner() en cada uno de ellos, Hibernate por defecto ejecutar 26 comandos SELECT, para obtener los proxies de los dueos. Se puede ajustar este comportamiento especificando un batch-size (tamo de lote) en el mapeo de Person:

167 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

<class name="Person" batch-size="10">...</class>

Hibernate ahora ejecutar slo 3 consultas: el patrn es 10, 10, 5. Tambin se puede habilitar la captura en lotes de colecciones. Por ejemplo, si cada Person tiene un coleccin haragana de Cats, y en un momento hay 10 personas cargadas en la sesin, iterar a travs de todas esas personas generara 10 SELECTs, uno por cada llamado a getCats(). Si se habilita la captura por lotes para las colecciones de cats en el mapeo de Person, Hibernate pre-capturar las colecciones:
<class name="Person"> <set name="cats" batch-size="3"> ... </set> </class>

Con un a batch-size igual a 3, Hibernate cargar 3, 3, 3, 1 colecciones en 4 SELECTs. De nuevo, el valor del atributo depender del nmero esperado de colecciones no inicializadas para una sesin en particular. La captura por lotes es particularmente til si se tiene un rbol anidado de items, por ejemplo, la tpica "Lista de Materiales" necesarios para construir una pieza (bill of Materials o BOM, por sus siglas en ingls). (Aunque para rboles de "mayormente lectura" un set anidado o un "path materialziado" seran mejores opciones) .

19.1.6. Usar la captura por subselect


Si una coleccin o proxy de valor simple haraganes tienen que ser capturados, Hibernate los carga todos, volviendo a ejecutar la consulta original en un subselect. Esto funciona de la misma manera que la captura por lotes, pero sin la carga "parte por parte".

19.1.7. Usar la captura de propiedades haragana


Hibernate3 soporta la captura haragana de propiedades individuales. Esta tcnica de optimizacin tambin se conoce como grupos de captura (en ingls "fetch groups"). Por favor, dese cuenta de que esto es un extra ms publicitario que funcional, dado que, en la prctica, optmizar las lecturas de filas es mucho ms importante que optimizar las lecturas de columna. De todos modos, leer slo algunas propiedades de una clase puede ser til en algunos casos extremos, en donde tablas anticuadas/heredadas tengan cientos de columnas y el modelo de datos no pueda ser mejorado. Para habilitar la carga haragana de propiedades, configure el atributo lazy en mapeos de propiedad especficos:
<class name="Document"> <id name="id"> <generator class="native"/> </id> <property name="name" not-null="true" length="50"/> <property name="summary" not-null="true" length="200" lazy="true"/> <property name="text" not-null="true" length="2000" lazy="true"/> </class>

La captura haragana de propiedades requiere instrumentacin bytecode de tiempo de compilacin! Si sus clases persistentes han sido mejoradas, Hibernate ignorar silenciosamente la configuracin de propiedades a "lazy", y se resignar a usar la captura inmediata usual. Para la instrumentacin bytecode, use la siguiente tarea de Ant:
<target name="instrument" depends="compile"> <taskdef name="instrument" classname="org.hibernate.tool.instrument.InstrumentTask"> <classpath path="${jar.path}"/> <classpath path="${classes.dir}"/> <classpath refid="lib.class.path"/> </taskdef> <instrument verbose="true"> <fileset dir="${testclasses.dir}/org/hibernate/auction/model"> <include name="*.class"/>

168 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

</fileset> </instrument> </target>

Una manera diferente (y tal vez mejor) de evitar lecturas de columa innecesarias, al menos en transacciones de slo-lectura, es usar las capacidades de proyeccin (Projections) que tienen las consultas HQL y Criteria. Esto evita la necesidad del bytecode de tiempo de compiacin, y es ciertamente una solucin preferible. Se puede forzar la captura ansiosa usual de propiedades, usando fetch all properties en HQL.

19.2. El cach de 2do nivel


Una sesin (Session) de Hibernate, es un cach de datos persistentes a nivel de la transaccin. Es posible configurar un cach a nivel de cluster, o a nivel de la JVM (a nivel de la SessionFactory o fbrica de sesiones), que se aplique a una o ms clases en particular, y/o a una o ms colecciones en particular. Se puede incluso "enchufar" un cach en cluster. Hay que tener cuidado, porque los cachs nunca estn al tanto de los cambios que le hayan sido hechos al repositorio de datos persistente por otra aplicacin (aunque s pueden ser configurados para que sus datos cacheados expiren regularmente luego de un cierto tiempo). Existe la opcin de decirle a Hibernate qu implementacin de cacheo usar, especificando el nombre de una clase que implemente org.hibernate.cache.CacheProvider, usando la propiedad hibernate.cache.provider_class. Hibernate trae incorporada una buena cantidad de integraciones con proveedores de cachs open-source, (listados a continuacin); adems, se puede implementar un cach propio y enchufarlo como se indic anteriormente. Nota: las versiones hasta 3.2 exclusive usaban EhCache como su proveedor por defecto. ste ya no es el caso a partir de 3.2. Table 19.1. Prveedores de Cach Soporta el Seguro para cach de usar en consultas clusters (Query)

Cach

Clase del proveedor

Tipo

Hashtable (no se espera org.hibernate.cache.HashtableCacheProvider que sea usado en produccin) EHCache OSCache
org.hibernate.cache.EhCacheProvider org.hibernate.cache.OSCacheProvider

memoria

memoria, disco memoria, disco en s cluster(multicast (invalidacin de ip) de cluster) en cluster (multicast de ip), transaccional

s s

SwarmCache org.hibernate.cache.SwarmCacheProvider

JBoss Cache org.hibernate.cache.TreeCacheProvider 1.x

s (requiere s sincronizacin (replicacin) de relojes) s s (requiere (replicacin sincronizacin o de relojes) invalidacin)

en cluster JBoss Cache (multicast de org.hibernate.cache.jbc2.JBossCacheRegionFactory 2 ip), transaccional

19.2.1. Mapeos de cach


El elemento <cache> del mapeo de una clase o coleccin tiene la forma siguiente:
<cache usage="transactional|read-write|nonstrict-read-write|read-only" region="RegionName" include="all|non-lazy"

(1) (2) (3)

169 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

/>

(1)
usage (obligatorio) especifica read-only

la estrategia de cacheo transactional, read-write, nonstrict-read-write or

(2) cach de 2 (3)


include (optativo, por defecto, all) non-lazy especifica que las propiedades de la entidad mapeadas con lazy="true" no deben ser mapeadas cuando est habilitada la captura haragana a nivel de cada atributo. region (optativo, por defecto, do

el nombre de rol de la clase o coleccin): especifica el nombre de la regin del

nivel.

Alternativamente (y tal vez preferiblemente) se puede especificar elementos <class-cache> y <collection-cache> en el archivo hibernate.cfg.xml. EL atributo usage especifica una estrategia de concurrencia de cach.

19.2.2. Estrategia de slo-lectura


Si su aplicacin necesita leer pero nunca modificar las instancias de una clase persistente, se puede usar un cach read-only. Esta es la estrategia ms simple y la de mejor performance. Tambin es perfectamente segura de utilizar en un cluster.
<class name="eg.Immutable" mutable="false"> <cache usage="read-only"/> .... </class>

19.2.3. Estrategia de lecto-escritura


Si la aplicacin necesita actualizar datos, puede ser apropiado usar una cach de lecto-escritura (read-write). Esta estrategia de cacheo nunca debera ser usada si se requiere aislamiento de transacciones serializables. Si el cach se usa en un entorno JTA, se debe especificar la propiedad hibernate.transaction.manager_lookup_class, especificando una estrategia para obtener la propiedad TransactionManager de JTA. En otros entornos, hay que asegurarse de que la transaccin est completa para cuando ocurran Session.close() o Session.disconnect(). Si se quiere usar esta estrategia en un cluster, hay que asegurarse de que la implementacin subyacente de cach soporta "locking". Los proveedores de cach que vienen ya incorporados no lo soportan.
<class name="eg.Cat" .... > <cache usage="read-write"/> .... <set name="kittens" ... > <cache usage="read-write"/> .... </set> </class>

19.2.4. Estrategia de lecto-escritura no estricta


Si la aplicacin necesita actualizar datos, pero slo ocasionalmente (es decir, si es improbable que dos transacciones traten de actualizar el mismo tem simultneamente), y no se requiere un aislamiento de transacciones estricto, puede ser apropiado un cach "de lecto-escritura no estricta" (nonstrict-read-write). Si el cach se usa en un entorno JTA, se debe especificar hibernate.transaction.manager_lookup_class. En otros entornos, hay que asegurarse de que la transaccin est completa para cuando ocurran Session.close() o Session.disconnect().

19.2.5. Estrategia transaccional

170 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

La estrategia transaccional (transactional) provee soporte para proveedores de cach enteramente transaccionales, como JBoss TreeCache. Tales cachs slo pueden ser usados en un entorno JTA, y se debe especificar hibernate.transaction.manager_lookup_class.

19.2.6. Compatibilidad entre el proveedor de cach y la estrategia de concurrencia Importante


Ninguno de los proveedores de cach soporta todas las estrategias de concurrencia. La siguiente table muestra qu proveedores son compatibles con qu estrategias de concurrencia. Tabla 19.2. Soporte de estrategias de concurrencia de cach Cach Hashtable (no concebida para uso en produccin) EHCache OSCache SwarmCache JBoss Cache 1.x JBoss Cache 2 slo-lectura s s s s s s lecto-escritura no estricta s s s s s s lectoescritura s s s transaccional

19.3. Admninistrar los cachs


Siempre que un objeto se le pase a save(), update() o saveOrUpdate(), y cada vez que se obtenga un objeto usando load(), get(), list(), iterate() o scroll(), dicho objeto se agrega al cach interno de la sesin. Cuando a continuacin se invoca flush(), el estado de dicho objeto ser sincronizado con la base de datos. Si no se quiere que esta sincronizacin ocurra, o si se est procesando una cantidad inmensa de objetos que haga necesario manejar la memoria eficientemente, se puede usar el mtodo evict() para quitar objetos y sus colecciones del cach de primer nivel.
ScrollableResult cats = sess.createQuery("from Cat as cat").scroll(); //un resultset inmenso while ( cats.next() ) { Cat cat = (Cat) cats.get(0); doSomethingWithACat(cat); sess.evict(cat); }

La Session tambin provee un mtodo contains() para determinar si una instancia ya pertenece al cach de sesin. Para desalojar a todos los objetos del cach de sesin, llame Session.clear() Para el cach de 2do nivel, hay mtodos definidos en SessionFactory para desalojar el estado cacheado de una instancia, de toda una clase, de la instancia de una coleccin, o de un rol de coleccin completo.
sessionFactory.evict(Cat.class, catId); //desaloja una instancia de Cat en particular sessionFactory.evict(Cat.class); //desaloja todos los Cats sessionFactory.evictCollection("Cat.kittens", catId); //desaloja un coleccin de kittens en particu sessionFactory.evictCollection("Cat.kittens"); //desaloja todas lsa colecciones de kittens

El argumento CacheMode controla cmo una sesin en particular interacta con el cach de 2do nivel.
CacheMode.NORMAL: lee

y escribe items en el cach de 2do nivel

171 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

CacheMode.GET: lee

items del cach de 2do nivel, pero no escribe en el cach de 2do nivel excepto cuando se items en el cach de 2do nivel, pero no lee.

actualicen datos.
CacheMode.PUT:escribe

items en el cach de 2do nivel, pero lee del cach de 2do nivel, elude los efectos de do hibernate.cache.use_minimal_puts, forzando un refresco del cach de 2 nivel para todos los items ledos de la base de datos.
CacheMode.REFRESH: escribe

Para navegar por ls contenidos del cach de 2do nivel, o de una regin de cacheo de consultas, use la API de Statistics:
Map cacheEntries = sessionFactory.getStatistics() .getSecondLevelCacheStatistics(regionName) .getEntries();

Necesitar habilitar estadsticas, y, optativamente, forzar a Hibernate a que escriba las entradas de cach en un formato ms legible por seres humanos:
hibernate.generate_statistics true hibernate.cache.use_structured_entries true

19.4. El cach de consultas (query cache)


Los resultados de las consultas tambin pueden ser cacheados. Esto slo estil para consultas que son ejecutadas frecuentemente, y con los mismos parmetros. Para usar el cach de consutas, primero hay que habilitarlo:
hibernate.cache.use_query_cache true

Esta configuracin provoca la creacin de dos nuevas regiones de cach: una que contendr los resultados cacheados de las consultas (org.hibernate.cache.StandardQueryCache), y la otra conteniendo la fecha y hora de las actualizaciones ms recientes hechas en las tablas "consultables" (org.hibernate.cache.UpdateTimestampsCache). Note que el cach de consultas no cachea el estado de las entidades mismas contenidas en el resultado; cachea solamente los valores de los identificadores, y los resultados de tipo "value type". As que el cach de consultas siempre debera ser usado en conjuncin con el cach de 2do nivel. A la mayora de las consultas no les representa ninguna ventaja el ser cacheadas, as que las consultas no se cachean por defecto. Par habilitar el cacheo, invoque Query.setCacheable(true). Este llamado permite que la consulta, al ser ejecutada, busque resultados ya existentes, o agregue sus resultados al cach. Si se require un control ms granular sobre las polticas de expiracin de los cachs, se puede especificar una regin de cach para una consulta en particular, invocando Query.setCacheRegion().
List blogs = sess.createQuery("from Blog blog where blog.blogger = :blogger") .setEntity("blogger", blogger) .setMaxResults(15) .setCacheable(true) .setCacheRegion("frontpages") .list();

Si la consulta forzare un refresco de esta regin de cach en particular, habra que invocar Query.setCacheMode(CacheMode.REFRESH). Esto es particularmente til para los casos en donde los datos subyacentes pudieren haber sido actualizados por un proceso separado (por ejemplo, no por Hibernate), y le permite a la aplicacin refrescar selectivamente un resultado en particular. Esto es ms eficiente que el desalojo de toda una regin de cachs via SessionFactory.evictQueries().

19.5. Comprender la performance de las colecciones


Ya hemos invertido bastante tiempo en hablar sobre las colecciones. En esta seccin, enfatizaremos un par de asuntos ms, referentes a cmo se comportan las colecciones en tiempo de ejecucin.

172 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

19.5.1. Taxonoma
Hibernate define tres tipos bsicos de coleccin: coleccin de valores asociaciones de-uno-a-muchos asociaciones de-muchos-a-muchos Esta clasificacin distingue entre las varias relaciones de tablas y claves forneas, pero en realidad no nos dice todo lo que necesitamos saber acerca del modelo relacional. Para comprender cabalmente la estructura relacional y las caractersticas de performance, debemos considerar tambin la estructura de la clave primaria que es usada por Hibernate para actualizar o borrar colecciones de filas. Esto a su vez sugiere la siguiente clasificacin: colecciones indexadas sets bags Todas las colecciones indexadas (maps, lists, arrays), tienen una clave primaria que consiste en las columnas de <key> e <index>. En este caso, las actualizaciones a la coleccin son extremadamente eficientes: la clave primaria puede ser indexada eficientemente y una fila en particular puede ser localizada eficientemente cuando Hibernate trate de actualizarla o borrarla. Los sets tienen una clave primaria que consiste en una <key> y columnas elemento. Esto puede ser menos eficiente para algunos tipos de elemento de coleccin, particularmente los elementos compuestos, o grandes campos de texto o binarios; la base de datos puede no ser capaz de indexar tan eficientemente una clave primaria compleja. Por otra parte, para asociaciones de-uno-a-muchos o de-muchos-a-muchos, particularmente cuando se usen identificadores sintticos, es muy probable que sea igual de eficiente. (Nota aparte: si se quiere que SchemaExport realmente cree por s solo la clave primaria de un <set>, debe declararse not-null="true" para todas las columnas). los mapeos <idbag> definen una clave sustituta, as que son muy eficientes de actualizar. De hecho, son el mejor caso. Las bags son el peor caso. Como una bag permite valores de elemento duplicados y no tiene columnas ndice, no se puede definir ninguna clave primaria. Hibernate no tiene forma de distinguir entre filas duplicadas. Hibernate resuelve este problema borrando completamente la coleccin (con un simple DELETE) y recrendola cada vez que algo cambia. Esto puede llegar a ser muy ineficiente. Note que para una asociacin de-uno-a-muchos, la "clave primaria" piede no ser la clave primiaria fsica de la tabla en la base de datos. Pero incluso en este caso, la clasificacin recin descripta es an til (an refleja cmo es que Hibernate "localiza" filas individuales de una coleccin).

19.5.2. Las lists, maps, idbags y sets son las colecciones ms eficientes de actualizar
Basndose en la discusin precedente, debera quedar claro que las colecciones indexadas y (normalmente) los sets permiten el desempeo ms eficiente en trminos de agregar, quitar, o actualizar elementos. Podra decirse las colecciones indexadas tienen una ventaja ms sobre los sets en las asociaciones de-muchos-a-muchos o colecciones de valores: a causa de la estructura de un Set, Hibernate nunca efecta un UPDATE de una fila cuando un elemento se "cambia". Los cambios en un Set siempre requieren INSERT(s) y DELETE(s) de filas individuales. Esta consideracin, de nuevo, no se aplica a las asociaciones de-uno-a-muchos. Tras observar que los arrays no pueden ser haraganes, concluiramos que las listas, mapas e idbags son los tipos (no inversos) de coleccin con mejor performance, seguidos de cerca por los sets. Los sets son el tipo ms comn de coleccin en Hibernate, porque la semntica de un set es la ms natural para un modelo relacional. Sin embargo, en un modelo de dominio Hibernate bien diseado, usualmente vemos que la mayra de las coleccioes son en realidad asociaciones de-uno-a-muchos con inverse="true". Para estas asociaciones, el UPDATE es manejado por el extremo 'de-muchos-a-uno' de la asociacin, as que estas disquisiciones sobre la performance al actualizar colecciones simplemente no son relevantes.

173 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

19.5.3. Las bags y lists son las colecciones inversas ms eficientes


No descarte a las bags para siempre, todava. Hay un caso en particular en el cual las bags (y tambin las lists) tienen mucha mejor performance que los sets. Para una coleccin con inverse="true" (la relacin bidireccional estndar estndar de-uno-a-muchos, por ejemplo, podemos agregar un elemento a una bag o list sin necesidad de inicializar (mediate una captura) los elementos de la bag! Esto se debe a que Collection.add() y Collection.addAll() siempre tienen que devolver "true" para una bag o list, al contrario de lo que ocurre con un Set. Esto puede volver el cdigo siguiente mucho ms rpido:
Parent p = (Parent) sess.load(Parent.class, id); Child c = new Child(); c.setParent(p); p.getChildren().add(c); // no es necesario capturar toda la coleccin! sess.flush();

19.5.4. Borrado en una pasada


Ocasionalmente, borrar elementos de una coleccin puede volverse extremadamente ineficiente. Hibernate no es completamente estpido, as que sabe que no lo tiene que hacer en el caso de una coleccin nueva y vaca, si uno invoca list.clear(), por ejemplo. En este caso, Hibernate emite un solo DELETE, y listo. Supongamos que se agrega un simple elemento a una coleccin de tamao 20, y luego se quitan 2 elementos. Hibernate emitir un comando INSERT y dos DELETEs (a menos que la coleccin sea una bag). Esto es deseable. Sin embargo, suponga que quitamos 18 elementos, dejando 2, y luego agregamos el nuevo elemento. Aqu hay dos maneras de proceder: borrar 18 filas una por una, y luego insertar 3 filas borrar toda la coleccin (usando un solo DELETE) e insertar todos los 5 elementos actuales, uno por uno. Hibernate no es lo suficientemente astuto como para darse cuenta de que la segunda opcin probablemente sea ms rpida.(Y probablemente sea mejor as, tal comportamiento podra confundir a los triggers de la BD, etc). Afortunadamente, podemos forzar este comportamiento (la estrategia nmero 2) en cualquier momento, descartando (es decir des-referenciando) la coleccin original, y devolviendo una coleccin recientemente instanciada con todos los elementos activos. Esto puede ser muy til y poderoso a veces. Por supuesto, los borrados en una pasada no son relevantes cuando tratamos con colecciones mapeadas con inverse="true".

19.6. Monitorear la performance


Optimizar no es muy til sin monitoreo y acceso a medidas concretas de performance. Hibernate provee un rango muy completo de valores numricos acerca de sus operaciones internas. Las estadsticas en Hibernate son accesibles por cada SessionFactory.

19.6.1. Monitorear una SessionFactory


Se puede acceder a mediciones de la SessionFactory de dos maneras: La primera opcin es llamar a sessionFactory.getStatistics() y leer o mostrar la Statistics usted mismo. Hibernate tambin puese usar JMX para publicar mediciones, si se habilita el MBean StatisticsService MBean. Se puede habilitar un solo MBean para todas las SessionFactorys, o uno para cada una. Vea el siguiente cdigo para ejemplos mnimos de configuracin:
// servicio de registro de MBean para una SessionFactory especfica Hashtable tb = new Hashtable(); tb.put("type", "statistics"); tb.put("sessionFactory", "myFinancialApp"); ObjectName on = new ObjectName("hibernate", tb); // nombre del objeto MBean

174 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

StatisticsService stats = new StatisticsService(); // implementacin del MBean stats.setSessionFactory(sessionFactory); // liga las estadsticas a la SessionFactory server.registerMBean(stats, on); // registra el Mbean em el servidor // servicio de registro de MBean para todas las SessionFactorys Hashtable tb = new Hashtable(); tb.put("type", "statistics"); tb.put("sessionFactory", "all"); ObjectName on = new ObjectName("hibernate", tb); // nombre del objeto MBean StatisticsService stats = new StatisticsService(); // implementacin del MBean server.registerMBean(stats, on); // Registra el MBean en el servidor

A hacer: esto no tiene sentido. En el primer caso, obtenemos y usamos el MBean dorectamente. En el segundo, debemos dar el nombre JNDI en el cual la fbrica de sesiones est contenida antes de usarla. Usar
hibernateStatsBean.setSessionFactoryJNDIName("my/JNDI/Name")

Se puede activar/desactivar el monitoreo para una SessionFactory: en tiempo de configuracin, asgnesele a hibernate.generate_statistics el valor false en tiempo de ejecucin, sf.getStatistics().setStatisticsEnabled(true) ohibernateStatsBean.setStatisticsEnabled(true) Las estadsticas pueden ser reinicializadas en forma programtica, usando el mtodo clear(). Se puede mandar un sumario al log (a nivel info). usando el mtodo logSummary().

19.6.2. Mediciones
Hibernate provee un buen nmero de mediciones, desde muy bsicas, hasta informacin especializada que slo es relevante en ciertos escenarios. Todos los contadores relevantes estn descriptos en la API de Statistics, en tres categoras: Las mediciones relacionadas con el uso de la sesin en general, tales como el nmero de desiones abiertas, el nmero de conexiones JDBC obtenidas, etc. Mediciones relacionadas con las entidades, colecciones, consultas y cachs como un todo (es decir, mediciones globales). Mediciones detalladas relacionadas con una entidad, coleccin, consulta o regin de cach en particular. Por ejemplo, se puede chequear la proporcin de veces en que se da en el blanco, no se da en el blanco, o se inserta en el cach (en ingls: hit, miss and put ratio), para las entidades, las colecciones y las consultas, y el tiempo que, en promedio, necesita una consulta. Tenga en cuenta que el nmero de milisegundos es slo una aproximacin en Java. Hibernate est atado a la precisin de la JVM, y en algunas plataformas sta tiene solo un grado de exactitud de 10 segundos. Para acceder a las mediciones globales (es decir, no atadas a una entidad, cach, etc en particular) se usan simples mtodos "getter". Se puede acceder a las mediciones de una entidad, coleccin o regin de cach en particular a travs del nombre, y a travs de su representacin en HQL o en SQL para las consultas. Por favor refirase a los JavaDocs de las APIs de Statistics, EntityStatistics, CollectionStatistics, SecondLevelCacheStatistics, y QueryStatistics para ms informacin. El siguiente cdigo muestra un ejemplo simple:
Statistics stats = HibernateUtil.sessionFactory.getStatistics(); double queryCacheHitCount = stats.getQueryCacheHitCount(); double queryCacheMissCount = stats.getQueryCacheMissCount(); double queryCacheHitRatio = queryCacheHitCount / (queryCacheHitCount + queryCacheMissCount); log.info("Query Hit ratio:" + queryCacheHitRatio); EntityStatistics entityStats = stats.getEntityStatistics( Cat.class.getName() ); long changes = entityStats.getInsertCount() + entityStats.getUpdateCount() + entityStats.getDeleteCount(); log.info(Cat.class.getName() + " changed " + changes + "times"

);

175 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

Para trabajar en todas las entidades, colecciones, consultas y regiones de cach, se pued obtener la lista de nombres de entidades, colecciones, consultas y regiones con los siguientes mtodos: getQueries(), getEntityNames(), getCollectionRoleNames(), y getSecondLevelCacheRegionNames().

Captulo 20. Gua de las herramientas (Toolset)


Hay un conjunto de plugins de Eclipse, tasks de Ant y herramientas de consola, que permiten uar Hibernate para practicar ingeniera reversa, y tambin "de ida" (roundtrip engineering). Las Herramientas de Hibernate (Hibernate Tools) actualmente incluyen plugins para el entorno ECLIPSE, as como herramientas de Ant para efectuar ingeniera reversa de base de datos existentes. Editor de mapeo: Un editor de archivos XML de mapeo de Hibernate, que soporta auto-complecin y resaltado de sintaxis. Tambin soporta auto-complecin semntica para los nombres de las clases y para los nombres de campos y propiedades, hacindolo mucho ms verstil que un editor de XML comn. Consola: La consola es una bueva vista (view) de Eclipse. Adems de una visin jarrquica general de la configuracin de la consola, tambin permite la ejecucin de consultas HQL contra la base de datos, y nevegar los resultados directamente en Eclipse. Wizards para desarrollo: Con las herramientas de Hibernate Eclipse se proveen varios "wizards". (N.del T): se les suele llamar "wizards" o hechiceros a los programas que van nagevando de una pantalla a la otra de manera secuencial, para permitirle al usuario realizar una operacin compleja guindolo a travs de unas pocas opciones simples por vez. Se puede usar un "wizard" para generar rpidamente archivos de configuracin de Hibernate, o se se le puede hacer una ingeniera reversa completa a un esquema de DB existente, convirtindolo en archivos fuente tipo POJO y archivos de mapeo de Hibernate. El wizard para ingeniera reversa soporta patrones (templates) configurables a medida. Tareas (tasks) de Ant: Por favor refirase al paquete Hibernate Tools y a su documentacin para ms informacin. Por otra parte, el paquete principal de Hibernate ya trae incluida una herramienta (que puede hasta puede ser usada instantneamente desde dentro de Hibernate): SchemaExport, tambin llamada hbm2ddl.

20.1. Generacin automtica del esquema de base de datos


El lenguaje de definicin de datos (o DDL por su siglas en ingls) puede ser generado por una utilidad de Hibernate a partir de los archivos de mapeo. El esquema generado incluye las constraints de integridad referencial (claves primarias y forneas) para las tablas de entidades y colecciones. Tambin se crean tablas y secuencias para los generadores de identificadores. Se debe especificar el dialecto SQL (Dialect) a travs de la propiedad hibernate.dialect cuando se use esta herramienta, dado que el DDL es altamente dependiente del proveedor de DB. Primero, retoque sus archivos de mapeo para mejorar el esquema a generar.

20.1.1. Retocar el esquema de base de datos


Muchos elementos de mapeo de Hibernate definen atributos opcionales llamados length, precision y scale. Se puede configurar el largo, precisin y escala respectivamente de una columna con estos atributos.
<property name="zip" length="5"/> <property name="balance" precision="12" scale="2"/>

Algunas tags tambin aceptan un atributo not-null (para generar una constraint NOT NULL en las columnas de la tabla), y un atributo unique (para generar constraints de unicidad en las columnas de la tabla).
<many-to-one name="bar" column="barId" not-null="true"/>

176 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

<element column="serialNumber" type="long" not-null="true" unique="true"/>

Se puede usar un atributo unique-key para agrupar columnas en una simple constraint de unicidad. Al presente, el valor especificado del atributo unique-key no es usado para nombrar la constraint en el DDL generado, solamente para agrupar a las columnas en el archivo de mapeo.
<many-to-one name="org" column="orgId" unique-key="OrgEmployeeId"/> <property name="employeeId" unique-key="OrgEmployee"/>

Un atributo index especifica el nombre de un ndice a crear utilizando la columna o columnas mapeadas. Se puede agrupar mltiples columnas en en mismo ndice, simplemente especificando el mismo nombre de ndice.
<property name="lastName" index="CustName"/> <property name="firstName" index="CustName"/>

Un atributo foreign-key puede ser usado para sustituir el nombre generado de cualquier constraint de clave fornea.
<many-to-one name="bar" column="barId" foreign-key="FKFooBar"/>

Muvhos elementos de mapeo tambin aceptan un elemento <column> hijo. Esto es particularmente til al mapear tipos multicolumna:
<property name="name" type="my.customtypes.Name"/> <column name="last" not-null="true" index="bar_idx" length="30"/> <column name="first" not-null="true" index="bar_idx" length="20"/> <column name="initial"/> </property>

El atributo default permite especificar un valor por defecto pra la columna (debera asignrsele el mismo valor a la propiedad mapeada antes de grabar una nueva instancia de la clase mapeada).
<property name="credits" type="integer" insert="false"> <column name="credits" default="10"/> </property> <version name="version" type="integer" insert="false"> <column name="version" default="0"/> </property>

El atributo sql-type le permite al usuario sustituir el mapeo por defecto de un tipo de dato Hibernate a un tipo de dato SQL.
<property name="balance" type="float"> <column name="balance" sql-type="decimal(13,3)"/> </property>

El atributo check permite especificar una constraint de chequeo.


<property name="foo" type="integer"> <column name="foo" check="foo > 10"/> </property> <class name="Foo" table="foos" check="bar < 100.0"> ... <property name="bar" type="float"/> </class>

Tabla 20.1. Sumario Atributo


largo precision scale

Valores numricos numricos numrico largo de la columna precisin decimal de la columna escala decimal de la columna

Interpretacin

177 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

Atributo
not-null unique index unique-key

Valores
true|false true|false index_name unique_key_name

Interpretacin especifica que la columna debera ser no anulable especifica que la columna debera tener una constraint de unicidad especifica el nombre de un ndice multicolumna especifica el nombre de una constraint de unicidad multicolumna especifica el nombre de una constraint de clave fornea generada para una asociacin, para un elemento de mapeo <one-to-one>, <many-to-one>, <key>, o <many-to-many>. Note que los extremos con inverse="true" sern ignorados por el SchemaExport. sustituye el tipo de columna por defecto (atributo del elemento <column> solamente) especifica un valor por defecto para la columna crea una constraint de chequeo, sea para la tabla o para la columna

foreign-key foreign_key_name

sql-type default check

tipo SQL de la columna

expresin SQL expresin SQL

El elemento <comment> permite especificar comentarios en el esquema generado.


<class name="Customer" table="CurCust"> <comment>Current customers only</comment> ... </class> <property name="balance"> <column name="bal"> <comment>Balance in USD</comment> </column> </property>

Esto resulta en comandos comment on table o comment on column en el DDL generado, cuando esto se soportada.

20.1.2. Ejecutar la herramienta


La herramienta SchemaExport imprime un script DDL en la salida estndar y/o ejecuta los comandos DDL.
java -cp

hibernate_classpaths org.hibernate.tool.hbm2ddl.SchemaExport options mapping_files

Table 20.2. Opciones de lnea de comandos para SchemaExport Opcin


--quiet --drop --create --text --output=my_schema.ddl --naming=eg.MyNamingStrategy --config=hibernate.cfg.xml --properties=hibernate.properties --format --delimiter=;

Descripcin no imprima el script en la salida estndar slo elimine (drop) las tablas slo cree las tablas n exporte a la base de datos escriba el script DDL en un archivo seleccione una NamingStrategy (estrategia de nombrado) lea la configuracin de Hibernate de una archivo XML lea las propiedades de la BD de un archivo formatee prolijamente el SQL generado en el script agrguele un delimitador de fin de lnea al script

Tambin se puede incrustar un SchemaExport dentro de la aplicacin

178 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

Configuration cfg = ....; new SchemaExport(cfg).create(false, true);

20.1.3. Propiedades
Se puede especificar propiedades de base de datos: como propiedades de sistema con -D<propiedad> en hibernate.properties en un archivo nombrado, con --properties Las propiedades que se necesitan son: Tabla 20.3. Porpiedades de conexin de SchemaExport Nombre de la propiedad
hibernate.connection.driver_class hibernate.connection.url hibernate.connection.username hibernate.connection.password hibernate.dialect

Descripcin clase del driver jdbc URL jdbc usuario de la base de datos database user clave del usuario dialecto

20.1.4. Usar Ant


Se puede llamar al SchemaExport desde un script de Ant
<target name="schemaexport"> <taskdef name="schemaexport" classname="org.hibernate.tool.hbm2ddl.SchemaExportTask" classpathr <schemaexport properties="hibernate.properties" quiet="no" text="no" drop="no" delimiter=";" output="schema-export.sql"> <fileset dir="src"> <include name="**/*.hbm.xml"/> </fileset> </schemaexport> </target>

20.1.5. Actualizaciones incrementales del esquema de base de datos


La herramienta SchemaUpdate actualizar un esquema de base de datos existente con cambios "incrementales". Note que SchemaUpdate depende grandemente de la API de metadatos de JDBC, as que no funcionar con todos los drivers de JDBC.
java -cp

hibernate_classpaths org.hibernate.tool.hbm2ddl.SchemaUpdate options mapping_files

Table 20.4. SchemaUpdate Command Line Options Opcin


--quiet --text --naming=eg.MyNamingStrategy

Descripcin no imprima el script en la salida estndar no exporte el script a la base de datos seleccione una NamingStrategy

179 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

Opcin
--properties=hibernate.properties --config=hibernate.cfg.xml

Descripcin lea las propiedades de base de datos de un archivo especifique un archivo .cfg.xml

Se puede incrustar un SchemaUpdate en la aplicacin


Configuration cfg = ....; new SchemaUpdate(cfg).execute(false);

20.1.6. Utilizar Ant para las actualizaciones incrementales del esquema de base de datos
Se puede invocar a SchemaUpdate desde el script de Ant:
<target name="schemaupdate"> <taskdef name="schemaupdate" classname="org.hibernate.tool.hbm2ddl.SchemaUpdateTask" classpathr <schemaupdate properties="hibernate.properties" quiet="no"> <fileset dir="src"> <include name="**/*.hbm.xml"/> </fileset> </schemaupdate> </target>

20.1.7. Validacin del esquema de base de datos


La herramienta SchemaValidator validar si el esquema de BD existente "corresponde" con los archivos de mapeo. Note que el SchemaValidator depende grandemente de la API de metadatos de JDB, as que no funcionar con todos los drivers JDBC, Esta herramienta es extremadamente til para tests.
java -cp

hibernate_classpaths org.hibernate.tool.hbm2ddl.SchemaValidator options mapping_files

Tabla 20.5. Opciones de lnea de comando para SchemaValidator Opcin


--naming=eg.MyNamingStrategy --properties=hibernate.properties --config=hibernate.cfg.xml

Descripcin selecciona una NamingStrategy lee las propiedades de base de datos de una archivo especifica un archivo .cfg.xml

Se puede incrustar un archivo SchemaValidator en la aplicacin


Configuration cfg = ....; new SchemaValidator(cfg).validate();

20.1.8. Usar Ant para la validacin de un esquema de base de datos


Se puede llamar al SchemaValidator desde el script de Ant:
<target name="schemavalidate"> <taskdef name="schemavalidator" classname="org.hibernate.tool.hbm2ddl.SchemaValidatorTask" clas <schemavalidator properties="hibernate.properties"> <fileset dir="src"> <include name="**/*.hbm.xml"/> </fileset> </schemavalidator> </target>

Captulo 21. Ejemplo: Padre/Hijo

180 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

Una de las primeras cosas que los nuevos usuarios tratan de hacer con Hibernate, es modelar una relacin del tipo padre/hijo (en ingls, "parent" y "child" respectivamente). Hay dos abordajes diferentes para esto. Por varias razones, el abordaje ms conveniente, especialmente para usuarios nuevos, es modelar tanto Padre como Hijo como clases de entidad, con una asociacin de-uno-a-muchos (<one-to-many>) del Padre al Hijo. (El enfoque alternativo es declarar el Hijo como un elemento compuesto ( <composite-element>). Ahora bien, ocurre que la semntica por defecto de una asociacin de-uno-a-muchos (en Hibernate), es mucho ms parecida a la semntica usual de una relacin padre/hijo, que a la semntica del mapeo de un elemento compuesto. Explicaremos cmo usar una asociacin 'de-uno-a-muchos bidireccional con propagacin en cascada' para modelar una relacin padre/hijo eficiente y elegantemente. No es nada difcil!

21.1. Nota sobre las colecciones


Las colecciones de Hibernate se consideran como una parte lgica de la entidad que las posee, nunca de las entidades contenidas. Esta distincin es crucial! Y tiene las siguientes consecuencias: Cuando quitamos/agregamos un objeto de una coleccin, el nmero de versin del dueo de la coleccin se incrementa. Si un objeto quitado de una coleccin es una instancia de un "value type" (es decir, de un elemento compuesto), dicho objeto dejar de ser persistente y su estado ser completamente borrado de la base de datos. Del mismo modo, agregarle una instancia de "value type" a la coleccin causar que su estado se vuelva inmediatamente persistente. Por otra parte, si es una entidad lo que se quita de una coleccin (en una asociacin de-uno-a-muchos o de-muchosa-muchos), sta no ser borrada por defecto. Este comportamiento es completamente consistente: un cambio en el estado interno de una entidad no debera causar que la entidad asociada se esfume! Del mismo modo, agregarle una entidad a una coleccin no provoca por defecto que la entidad se vuelva persitente. En cambio, el comportamiento por defecto es que, agregarle una entidad a una coleccin, simplemente crea un vnculo entre las dos entidades, y quitrsela borra dicho vnculo. Esto es muy apropiado para todos los casos, excepto para el caso en que la vida de un hijo dependa del ciclo de vida del padre.

21.2. de-uno-a-muchos bidireccional


Supongamos que se empieza con una simple asociacin de-uno-a-muchos de padre a hijo.
<set name="children"> <key column="parent_id"/> <one-to-many class="Child"/> </set>

If we were to execute the following code


Parent p = .....; Child c = new Child(); p.getChildren().add(c); session.save(c); session.flush();

Hibernate emitir los siguientes comandos SQL: un INSERT para crear el registro para c un UPDATE para crear el vnculo de p a c Esto es no solamente ineficiente, sino que viola cualquier constraint NOT NULL que pudiere haber en la columna parent_id column. Podemos areglar la violacin de la constraint de nulabilidad especificando not-null="true" en el mapeo de la coleccin:
<set name="children"> <key column="parent_id" not-null="true"/> <one-to-many class="Child"/> </set>

181 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

De todos modos, sta no es la solucin que se recomienda. La causa subyacente de este comportamiento es que el vnculo (la clave fornea parent_id) de p a c no se considera como parte del estado del objeto Child y por lo tanto no es creado durante el INSERT. As que la solucin es volver al vnculo que es parte del mapeo del objeto Child.
<many-to-one name="parent" column="parent_id" not-null="true"/>

(Tambin es necesario agragar la propiedad parent a la clase Child). Ahora que la entidad Child est manejando el estado del vnculo, le indicamos a la coleccin que no actualice el vnculo ella. Para esto se usa el atributo inverse.
<set name="children" inverse="true"> <key column="parent_id"/> <one-to-many class="Child"/> </set>

El cdigo siguiente sera usado para agregar un nuevo Child:


Parent p = (Parent) session.load(Parent.class, pid); Child c = new Child(); c.setParent(p); p.getChildren().add(c); session.save(c); session.flush();

Y ahora, slo se emite un comando INSERT! Para afinar las cosas un poco ms, podramos crear un mtodo addChild() en la clase Parent.
public void addChild(Child c) { c.setParent(this); children.add(c); }

y ahora, el cfigo para agregar un Child se ve as:


Parent p = (Parent) session.load(Parent.class, pid); Child c = new Child(); p.addChild(c); session.save(c); session.flush();

21.3. Ciclo de vida de la propagacin en cascada


El llamado explcito a save() an es molesto. Nos ocuparemos de esto usando la propagacin en cascada.
<set name="children" inverse="true" cascade="all"> <key column="parent_id"/> <one-to-many class="Child"/> </set>

Esto simplifica el cdigo anterior a


Parent p = (Parent) session.load(Parent.class, pid); Child c = new Child(); p.addChild(c); session.flush();

En forma similar, no necesitamos iterar a travs de los hijos al grabar o borrar un Parent. Lo siguiente borra a p y a todos sus hijos de la base de datos:
Parent p = (Parent) session.load(Parent.class, pid); session.delete(p); session.flush();

182 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

Sin embargo, este cdigo


Parent p = (Parent) session.load(Parent.class, pid); Child c = (Child) p.getChildren().iterator().next(); p.getChildren().remove(c); c.setParent(null); session.flush();

no borrar a c de la base de datos; slo quitar el vnculo con p (y causar en este caso una violacin de constraint NOT NULL). Hay que borrar al (con delete()) explcitamente al Child.
Parent p = (Parent) session.load(Parent.class, pid); Child c = (Child) p.getChildren().iterator().next(); p.getChildren().remove(c); session.delete(c); session.flush();

Ahora, en este caso, un Child no puede realmente existir sin su padre. Entonces, si quitamos un Child de una coleccin, realmente queremos que sea borrado. Para ello debemos usar cascade="all-delete-orphan".
<set name="children" inverse="true" cascade="all-delete-orphan"> <key column="parent_id"/> <one-to-many class="Child"/> </set>

Nota: an cuando el mapeo de la coleccin especifica inverse="true", ls propagaciones en cascada s se procesan iterando a travs de los elementos de la coleccin. As que si se necesita que una coleccin sea grabada, borrada o actualizada en cascada, se debe agregar el atributo "cascade" a la coleccin. No basta con invocar setParent().

21.4. Las propagaciones en cascada y unsaved-value


Supngase que cargamos un Parent en una sesin, hacemos algunos cambios en la interfaz de usuario, y deseamos persistir dichos cambios en una nueva sesin, invocando update(). El Parent contendr una coleccin de hijos, y como la propagacin en cascada para "update" est habilitada, Hibernate necesita saber cules de los hijos han sido recientemente instanciados, y cules representan filas ya existentes en la base de datos. Asumamos que tanto Parent como Child tienen identificadores generados del tipo Long. Hibernate Hibernate usar el identificador y los valores de propiedad de version/timestamp para determinar cules de los hijos son nuevos (Vea Seccin 10.7, Deteccin automtica de estado). En Hibernate3, ya no es necesario especificar un unsaved-value explcitamente. El siguiente cdigo actualizar tanto al padre como al hijo, e insertar un nuevo hijo (newChild).
//tanto el padre como el hijo fueron cargados en una sesin anterior parent.addChild(child); Child newChild = new Child(); parent.addChild(newChild); session.update(parent); session.flush();

Todo esto est muy bien en el caso de un identificador autogenerado, pero qu pasas con los identificadores asignados, o con los identificadores compuestos? Esto es ms difcil, dado que Hibernate no puede usar la propiedad identificadora para distinguir entre un objeto recientemente instanciado (con un identificador asignado por el usuario) y un objeto cargado en una sesin previa. En este caso, Hibernate usar o bien las propiedades version/timestamp, o bien consultar el cach de 2do nivel, o, en el peor de los casos, la base de datos, para verificar si la fila existe.

21.5. Conclusin
Esto es bastante para digerir de una vez, y puede parecer confuso la primera vez. Pero en la prctica todo se acomoda y funciona en una forma muy linda. La mayora de las aplicaciones Hibernate utilizan el patrn padre/hijo en muchos lugares. En el primer prrafo mencionbamos una alternativa. En el caso de los mapeos con <composite-element> no existe ninguno de estos problemas, que tienen exactamente la semntica de una relacin padre/hijo. Desafortunadamente, existen dos grandes limitaciones al trabajar con clases de elementos compuestos: un elemento compuesto no puede contener colecciones, y ellos mismos slo pueden ser hijos de una nica entidad padre.

183 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

Captulo 22. Ejemplo: la aplicacin Weblog 22.1. Clases persistentes


Las clases pesistentes representan: un weblog (bitcora de web), y un item publicado en el weblog. Tienen que ser modeladas segn una relacin padre/hijo estndar, pero utulizaremos una bag ordenada, en lugar de un set.
package eg; import java.util.List; public class Blog { private Long _id; private String _name; private List _items; public Long getId() { return _id; } public List getItems() { return _items; } public String getName() { return _name; } public void setId(Long long1) { _id = long1; } public void setItems(List list) { _items = list; } public void setName(String string) { _name = string; } } package eg; import java.text.DateFormat; import java.util.Calendar; public class BlogItem { private Long _id; private Calendar _datetime; private String _text; private String _title; private Blog _blog; public Blog getBlog() { return _blog; } public Calendar getDatetime() { return _datetime; } public Long getId() { return _id; } public String getText() { return _text; } public String getTitle() { return _title; } public void setBlog(Blog blog) { _blog = blog; } public void setDatetime(Calendar calendar) { _datetime = calendar; } public void setId(Long long1) { _id = long1; } public void setText(String string) { _text = string;

184 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

} public void setTitle(String string) { _title = string; } }

22.2. Mapeos de Hibernate


Los mapeos de XML deberan resultar bastante sencillos.
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="eg"> <class name="Blog" table="BLOGS"> <id name="id" column="BLOG_ID"> <generator class="native"/> </id> <property name="name" column="NAME" not-null="true" unique="true"/>

<bag name="items" inverse="true" order-by="DATE_TIME" cascade="all"> <key column="BLOG_ID"/> <one-to-many class="BlogItem"/> </bag> </class> </hibernate-mapping> <?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping package="eg"> <class name="BlogItem" table="BLOG_ITEMS" dynamic-update="true"> <id name="id" column="BLOG_ITEM_ID"> <generator class="native"/> </id> <property name="title" column="TITLE" not-null="true"/> <property name="text" column="TEXT" not-null="true"/> <property name="datetime" column="DATE_TIME" not-null="true"/> <many-to-one name="blog" column="BLOG_ID" not-null="true"/> </class> </hibernate-mapping>

22.3. Cdigo Hibernate


La clase siguiente demuestra algunas de las cosas que se puede hacer con estas clases, usando Hibernate.
package eg; import import import import java.util.ArrayList; java.util.Calendar; java.util.Iterator; java.util.List;

import org.hibernate.HibernateException; import org.hibernate.Query;

185 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

import import import import import

org.hibernate.Session; org.hibernate.SessionFactory; org.hibernate.Transaction; org.hibernate.cfg.Configuration; org.hibernate.tool.hbm2ddl.SchemaExport;

public class BlogMain { private SessionFactory _sessions; public void configure() throws HibernateException { _sessions = new Configuration() .addClass(Blog.class) .addClass(BlogItem.class) .buildSessionFactory(); } public void exportTables() throws HibernateException { Configuration cfg = new Configuration() .addClass(Blog.class) .addClass(BlogItem.class); new SchemaExport(cfg).create(true, true); } public Blog createBlog(String name) throws HibernateException { Blog blog = new Blog(); blog.setName(name); blog.setItems( new ArrayList() ); Session session = _sessions.openSession(); Transaction tx = null; try { tx = session.beginTransaction(); session.persist(blog); tx.commit(); } catch (HibernateException he) { if (tx!=null) tx.rollback(); throw he; } finally { session.close(); } return blog; } public BlogItem createBlogItem(Blog blog, String title, String text) throws HibernateException BlogItem item = new BlogItem(); item.setTitle(title); item.setText(text); item.setBlog(blog); item.setDatetime( Calendar.getInstance() ); blog.getItems().add(item); Session session = _sessions.openSession(); Transaction tx = null; try { tx = session.beginTransaction(); session.update(blog); tx.commit(); } catch (HibernateException he) { if (tx!=null) tx.rollback(); throw he; } finally { session.close(); } return item; } public BlogItem createBlogItem(Long blogid, String title, String text) throws HibernateExceptio BlogItem item = new BlogItem(); item.setTitle(title); item.setText(text); item.setDatetime( Calendar.getInstance() );

186 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

Session session = _sessions.openSession(); Transaction tx = null; try { tx = session.beginTransaction(); Blog blog = (Blog) session.load(Blog.class, blogid); item.setBlog(blog); blog.getItems().add(item); tx.commit(); } catch (HibernateException he) { if (tx!=null) tx.rollback(); throw he; } finally { session.close(); } return item; } public void updateBlogItem(BlogItem item, String text) throws HibernateException { item.setText(text); Session session = _sessions.openSession(); Transaction tx = null; try { tx = session.beginTransaction(); session.update(item); tx.commit(); } catch (HibernateException he) { if (tx!=null) tx.rollback(); throw he; } finally { session.close(); } } public void updateBlogItem(Long itemid, String text) throws HibernateException { Session session = _sessions.openSession(); Transaction tx = null; try { tx = session.beginTransaction(); BlogItem item = (BlogItem) session.load(BlogItem.class, itemid); item.setText(text); tx.commit(); } catch (HibernateException he) { if (tx!=null) tx.rollback(); throw he; } finally { session.close(); } } public List listAllBlogNamesAndItemCounts(int max) throws HibernateException { Session session = _sessions.openSession(); Transaction tx = null; List result = null; try { tx = session.beginTransaction(); Query q = session.createQuery( "select blog.id, blog.name, count(blogItem) " + "from Blog as blog " + "left outer join blog.items as blogItem " + "group by blog.name, blog.id " + "order by max(blogItem.datetime)" ); q.setMaxResults(max); result = q.list(); tx.commit(); } catch (HibernateException he) { if (tx!=null) tx.rollback(); throw he; }

187 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

finally { session.close(); } return result; } public Blog getBlogAndAllItems(Long blogid) throws HibernateException { Session session = _sessions.openSession(); Transaction tx = null; Blog blog = null; try { tx = session.beginTransaction(); Query q = session.createQuery( "from Blog as blog " + "left outer join fetch blog.items " + "where blog.id = :blogid" ); q.setParameter("blogid", blogid); blog = (Blog) q.uniqueResult(); tx.commit(); } catch (HibernateException he) { if (tx!=null) tx.rollback(); throw he; } finally { session.close(); } return blog; } public List listBlogsAndRecentItems() throws HibernateException { Session session = _sessions.openSession(); Transaction tx = null; List result = null; try { tx = session.beginTransaction(); Query q = session.createQuery( "from Blog as blog " + "inner join blog.items as blogItem " + "where blogItem.datetime > :minDate" ); Calendar cal = Calendar.getInstance(); cal.roll(Calendar.MONTH, false); q.setCalendar("minDate", cal); result = q.list(); tx.commit(); } catch (HibernateException he) { if (tx!=null) tx.rollback(); throw he; } finally { session.close(); } return result; } }

Captulo 23. Ejemplo: Mapeos varios


Estos captulos exponen algunos mapeos de asociacin ms complejos.

23.1. Empleador/Empleado
El modelo siguiente de la relacin entre empleador y empleado (Employer y Employee) usa una verdadera clase de entidad, Employment (empleo) para representar la asociacn. Esto se hace porque puede haber msde un perodo de empleo para las mismas dos partes involucradas. Para modelar valores monetarios y nombres de empleados se usan componentes.

188 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

He aqu un documento de mapeo posible:


<hibernate-mapping> <class name="Employer" table="employers"> <id name="id"> <generator class="sequence"> <param name="sequence">employer_id_seq</param> </generator> </id> <property name="name"/> </class> <class name="Employment" table="employment_periods"> <id name="id"> <generator class="sequence"> <param name="sequence">employment_id_seq</param> </generator> </id> <property name="startDate" column="start_date"/> <property name="endDate" column="end_date"/> <component name="hourlyRate" class="MonetaryAmount"> <property name="amount"> <column name="hourly_rate" sql-type="NUMERIC(12, 2)"/> </property> <property name="currency" length="12"/> </component> <many-to-one name="employer" column="employer_id" not-null="true"/> <many-to-one name="employee" column="employee_id" not-null="true"/> </class> <class name="Employee" table="employees"> <id name="id"> <generator class="sequence"> <param name="sequence">employee_id_seq</param> </generator> </id> <property name="taxfileNumber"/> <component name="name" class="Name"> <property name="firstName"/> <property name="initial"/> <property name="lastName"/> </component> </class> </hibernate-mapping>

Y ste es el esquema de tablas generado por SchemaExport.


create table employers (

189 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

id BIGINT not null, name VARCHAR(255), primary key (id) ) create table employment_periods ( id BIGINT not null, hourly_rate NUMERIC(12, 2), currency VARCHAR(12), employee_id BIGINT not null, employer_id BIGINT not null, end_date TIMESTAMP, start_date TIMESTAMP, primary key (id) ) create table employees ( id BIGINT not null, firstName VARCHAR(255), initial CHAR(1), lastName VARCHAR(255), taxfileNumber VARCHAR(255), primary key (id) ) alter table employment_periods add constraint employment_periodsFK0 foreign key (employer_id) refer alter table employment_periods add constraint employment_periodsFK1 foreign key (employee_id) refer create sequence employee_id_seq create sequence employment_id_seq create sequence employer_id_seq

23.2. Autor/Obra
Considrese el modelo siguiente de la relacin entre obra, autor y persona (Work, Author y Person respectivamente). Representamos la relacin entre Work y Author como un asociacin de-muchos-a-muchos. Elegimos representar la asociacin entre Author y Person como de-uno-a-uno. Otra posibilidad sera hacer que Author extendiere Person.

El siguiente documento de mapeo representa estas relaciones correctamente:


<hibernate-mapping> <class name="Work" table="works" discriminator-value="W"> <id name="id" column="id"> <generator class="native"/> </id>

190 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

<discriminator column="type" type="character"/> <property name="title"/> <set name="authors" table="author_work"> <key column name="work_id"/> <many-to-many class="Author" column name="author_id"/> </set> <subclass name="Book" discriminator-value="B"> <property name="text"/> </subclass> <subclass name="Song" discriminator-value="S"> <property name="tempo"/> <property name="genre"/> </subclass> </class> <class name="Author" table="authors"> <id name="id" column="id"> <!-- el Autor tiene que tener el mismo identificador que la Persona --> <generator class="assigned"/> </id> <property name="alias"/> <one-to-one name="person" constrained="true"/> <set name="works" table="author_work" inverse="true"> <key column="author_id"/> <many-to-many class="Work" column="work_id"/> </set> </class> <class name="Person" table="persons"> <id name="id" column="id"> <generator class="native"/> </id> <property name="name"/> </class> </hibernate-mapping>

En este mapeo hay 4 tablas. works, authors y persons contienen las obras, autores y personas respectivamente. author_work es una tabla de asociacin que vincula a los autores con sus obras. Aqu est el esquema de tablas, tal cual es generado por SchemaExport.
create table works ( id BIGINT not null generated by default as identity, tempo FLOAT, genre VARCHAR(255), text INTEGER, title VARCHAR(255), type CHAR(1) not null, primary key (id) ) create table author_work ( author_id BIGINT not null, work_id BIGINT not null, primary key (work_id, author_id) ) create table authors ( id BIGINT not null generated by default as identity, alias VARCHAR(255), primary key (id) ) create table persons ( id BIGINT not null generated by default as identity, name VARCHAR(255), primary key (id) ) alter table authors add constraint authorsFK0 foreign key (id) references persons

191 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

alter table author_work add constraint author_workFK0 foreign key (author_id) references authors alter table author_work add constraint author_workFK1 foreign key (work_id) references works

23.3. Cliente/Orden/Producto
Ahora consideremos un modelo de las relaciones entre cliente, orden, tem (es decir, lnea de la orden) y producto (Customer, Order, LineItem y Product respectivamente). Hay una asociacin de-uno-a-muchos entre Customer y Order, pero cmo deberamos representar Order / LineItem / Product? Elijo mapear LineItem como una clase de asociacin que representa la asociacin de-muchos-a-muchos entre Order y Product. En Hibernate, esto se denomina un "elemento compuesto" (composite element).

El documento de mapeo:
<hibernate-mapping> <class name="Customer" table="customers"> <id name="id"> <generator class="native"/> </id> <property name="name"/> <set name="orders" inverse="true"> <key column="customer_id"/> <one-to-many class="Order"/> </set> </class> <class name="Order" table="orders"> <id name="id"> <generator class="native"/> </id> <property name="date"/> <many-to-one name="customer" column="customer_id"/> <list name="lineItems" table="line_items"> <key column="order_id"/> <list-index column="line_number"/> <composite-element class="LineItem"> <property name="quantity"/> <many-to-one name="product" column="product_id"/> </composite-element> </list> </class> <class name="Product" table="products"> <id name="id"> <generator class="native"/> </id> <property name="serialNumber"/> </class> </hibernate-mapping> customers, orders, line_items y products contienen los datos de clientes, rdenes, items de las rdenes y productos, respectivamente. line_items tambin acta como una tabla de asociacin que vincula rdenes con productos. create table customers ( id BIGINT not null generated by default as identity, name VARCHAR(255),

192 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

primary key (id) ) create table orders ( id BIGINT not null generated by default as identity, customer_id BIGINT, date TIMESTAMP, primary key (id) ) create table line_items ( line_number INTEGER not null, order_id BIGINT not null, product_id BIGINT, quantity INTEGER, primary key (order_id, line_number) ) create table products ( id BIGINT not null generated by default as identity, serialNumber VARCHAR(255), primary key (id) ) alter table orders add constraint ordersFK0 foreign key (customer_id) references customers alter table line_items add constraint line_itemsFK0 foreign key (product_id) references products alter table line_items add constraint line_itemsFK1 foreign key (order_id) references orders

23.4. Ejemplos miscelneos de asociacin


Estos ejemplos han sido extrados todos ellos de la suite de tests de Hibernate. All pueden encontrarse muchos otros ejemplos tiles. Busque en el directorio test de la distribucin de Hibernate. A HACER: revestir esto con palabras

23.4.1. Asociacin de-uno-a-uno "con tipo"


<class name="Person"> <id name="name"/> <one-to-one name="address" cascade="all"> <formula>name</formula> <formula>'HOME'</formula> </one-to-one> <one-to-one name="mailingAddress" cascade="all"> <formula>name</formula> <formula>'MAILING'</formula> </one-to-one> </class> <class name="Address" batch-size="2" check="addressType in ('MAILING', 'HOME', 'BUSINESS')"> <composite-id> <key-many-to-one name="person" column="personName"/> <key-property name="type" column="addressType"/> </composite-id> <property name="street" type="text"/> <property name="state"/> <property name="zip"/> </class>

23.4.2. Ejemplo de clave compuesta


<class name="Customer"> <id name="customerId" length="10"> <generator class="assigned"/> </id> <property name="name" not-null="true" length="100"/> <property name="address" not-null="true" length="200"/> <list name="orders" inverse="true" cascade="save-update">

193 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

<key column="customerId"/> <index column="orderNumber"/> <one-to-many class="Order"/> </list> </class> <class name="Order" table="CustomerOrder" lazy="true"> <synchronize table="LineItem"/> <synchronize table="Product"/> <composite-id name="id" class="Order$Id"> <key-property name="customerId" length="10"/> <key-property name="orderNumber"/> </composite-id> <property name="orderDate" type="calendar_date" not-null="true"/> <property name="total"> <formula> ( select sum(li.quantity*p.price) from LineItem li, Product p where li.productId = p.productId and li.customerId = customerId and li.orderNumber = orderNumber ) </formula> </property> <many-to-one name="customer" column="customerId" insert="false" update="false" not-null="true"/> <bag name="lineItems" fetch="join" inverse="true" cascade="save-update"> <key> <column name="customerId"/> <column name="orderNumber"/> </key> <one-to-many class="LineItem"/> </bag> </class> <class name="LineItem"> <composite-id name="id" class="LineItem$Id"> <key-property name="customerId" length="10"/> <key-property name="orderNumber"/> <key-property name="productId" length="10"/> </composite-id> <property name="quantity"/> <many-to-one name="order" insert="false" update="false" not-null="true"> <column name="customerId"/> <column name="orderNumber"/> </many-to-one> <many-to-one name="product" insert="false" update="false" not-null="true" column="productId"/> </class> <class name="Product"> <synchronize table="LineItem"/> <id name="productId" length="10"> <generator class="assigned"/> </id> <property name="description" not-null="true" length="200"/> <property name="price" length="3"/> <property name="numberAvailable"/> <property name="numberOrdered"> <formula> ( select sum(li.quantity)

194 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

from LineItem li where li.productId = productId ) </formula> </property>

</class>

23.4.3. de-muchos-a-muchos con atributo compartido de clave compuesta


<class name="User" table="`User`"> <composite-id> <key-property name="name"/> <key-property name="org"/> </composite-id> <set name="groups" table="UserGroup"> <key> <column name="userName"/> <column name="org"/> </key> <many-to-many class="Group"> <column name="groupName"/> <formula>org</formula> </many-to-many> </set> </class> <class name="Group" table="`Group`"> <composite-id> <key-property name="name"/> <key-property name="org"/> </composite-id> <property name="description"/> <set name="users" table="UserGroup" inverse="true"> <key> <column name="groupName"/> <column name="org"/> </key> <many-to-many class="User"> <column name="userName"/> <formula>org</formula> </many-to-many> </set> </class>

23.4.4. Discriminacin basada en el contenido


<class name="Person" discriminator-value="P"> <id name="id" column="person_id" unsaved-value="0"> <generator class="native"/> </id>

<discriminator type="character"> <formula> case when title is not null then 'E' when salesperson is not null then 'C' else 'P' end </formula> </discriminator> <property name="name" not-null="true" length="80"/> <property name="sex" not-null="true" update="false"/> <component name="address"> <property name="address"/> <property name="zip"/> <property name="country"/> </component>

195 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

<subclass name="Employee" discriminator-value="E"> <property name="title" length="20"/> <property name="salary"/> <many-to-one name="manager"/> </subclass>

<subclass name="Customer" discriminator-value="C"> <property name="comments"/> <many-to-one name="salesperson"/> </subclass> </class>

23.4.5. Asociaciones en claves alternativas


<class name="Person">

<id name="id"> <generator class="hilo"/> </id> <property name="name" length="100"/> <one-to-one name="address" property-ref="person" cascade="all" fetch="join"/> <set name="accounts" inverse="true"> <key column="userId" property-ref="userId"/> <one-to-many class="Account"/> </set> <property name="userId" length="8"/> </class> <class name="Address"> <id name="id"> <generator class="hilo"/> </id> <property name="address" length="300"/> <property name="zip" length="5"/> <property name="country" length="25"/> <many-to-one name="person" unique="true" not-null="true"/> </class> <class name="Account"> <id name="accountId" length="32"> <generator class="uuid"/> </id> <many-to-one name="user" column="userId" property-ref="userId"/> <property name="type" not-null="true"/> </class>

Captulo 24. Prcticas recomendadas


Escriba clases con gran nivel de detalle, y mapelas usando <component>. Use una clase Direccion para encapsular calle, barrio, provincia, CodigoPostal. Esto alienta la reutilizacin de cdigo y simplifica la reingeniera. Declare propiedades identificadoras en las clases persistentes. Hibernate hace que las propiedades identificadoras sean opcionales, pero existe todo tipo de razones por las cuales habra que usarlos siempre. Recomendamos que estos identificadores sean "sintticos" (generados, sin ningn

196 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

significado de negcocios). Identifique claves naturales. Identifique claves naturales para todas las entidades, y mapelas usando <natural-id>. Implemente equals() y hashCode() para comparar las propiedades que componen la clave natural. Ubique cada mapeo de clase en su propio archivo. No use un nico documento de mapeo monoltico. Mapee com.eg.Foo en el archivo com/eg/Foo.hbm.xml. Esto tiene sentido, particularmente en un entorno de programacin en equipo. Cargue los archivos de mapeo como recursos. Despliegue los mapeos junto con las clases que mapean. Considere externalizar las cadenas SQL de las consultas. sta es una buena prctica si sus consultas utilizan funciones SQL que no sean estndar de ANSI. Externalizarlas volver la aplicacin ms porttil. Use variables de vnculo. Como en JDBC, siempre reemplace valores no constantes con "?". Nunca use manipulacin de cadenas para unir un valor no-constante a una consulta! Mejor an, considere usar parmetros nombrados en las consultas. No maneje sus propias conexiones JDBC. Hibernate le permite a la aplicacin manejar sus conexiones JDBC, pero esto debe considerarse como un ltmo recurso. Si no puede usar los proveedores de conexiones que ya vienen incluidos, considere proveer su propia implementacin de org.hibernate.connection.ConnectionProvider. Considere usar un tipo a medida. Suponga que tiene un tipo Java, digamos de una biblioteca, que necesita ser persistido, pero no provee los mtodos de acceso necesarios para mapearlo como un componente. Usted debera considerar implementar org.hibernate.UserType. Esta estrategia libera al cdigo de la aplicacin de implementar transformaciones desde o hacia un tipo Hibernate. En cuellos de botella, use JDBC manual. En reas de performance crticas de un sistema, algunos tipos de operacin podran beneficiarse al usar JDBC directamente. Pero por favor, espere hasta estar seguro de que algo constituye un cuello de botella. Y no asuma que JDBC es necesariamente ms rpida. Si necesita utilizar JDBC directamente, puede valer la pena abrir una sesin y usar esa conexin JDBC. De este modo, usted an puede aprovechar la estrategia de transacciones y el proveedor de conexiones subyacente. Comprenda el "flush" de sesin De tanto en tanto, la sesin sincroniza su estado persistente con la base de datos. La performance se resentir si este proceso ocurre demasiado seguido. A veces se puede disminuir la cantidad de "flush" innecesarios inhabilitando el "flushing" automtico, o incluso cambiando el orden de las consultas u otras operaciones dentro de una transaccin en particular. En una arquitectura de tres capas, considere usar objetos desprendidos. Cuando se usa una arquitectura de servlet/session bean, se pueden pasar objetos persistentes cargados en el session bean desde y hacia la capa de servlets/JSP. Use una nueva sesin para servir a cada solicitud (request). Use Session.merge() o Session.saveOrUpdate() para sincronizar objetos con la base de datos. En una arquitectura de dos capas, considere usar contextos largos de persistencia. Las transacciones de DB tienen que ser lo ms cortas posible, para que la aplicacin sea escalable. Sin embargo, a veces es necesario implementar transacciones "de aplicacin" de largo aliento, una unidad de trabajo nica desde el punto de vista del usuario. Una "transaccin de aplicacin" puede extenderse por varios ciclos solicitud/respuesta del cliente. Es comn usar objetos desprendidos para implementar transacciones de aplicacin. Una alternativa,

197 de 198

17/02/2009 09:25 a.m.

HIBERNATE - Persistencia Relacional para Java Idiomtico

http://www.hibernar.org/documentacion_es/castellano.html

extremadamente apropiada en arquitecturas de dos capas, es mantener un nico contacto de persistencia abierto (una sesin) para todo el ciclo de vida de la "transaccin de aplicacin", y simplemente desconectarse de la conexin JDBC al final de cada slicitud, reconectndose al comenzar la solicitud siguiente. Nunca comparta una misma sesin a travs de ms de una "transaccin de aplicacin" o estar trabajando con datos rancios. No trate las excepciones como si fueran recuperables. Esto una prctica necesaria ms que una "prctica recomendada". Cuando ocurra una excepcin, invoque un rollback de la transaccin, y cierre la sesin. Si no lo hace, Hibernate no puede garantizar que el estado en memoria represente correctamente el estado persistente. Como corolario de esto, no use Session.load() para determinar si una instancia con un identificador dado existe en la base de datos. En lugar de eso, use Session.get() o una consulta. Prefiera la captura haragana (lazy fetching) para las asociaciones. Use la captura ansiosa (eager fetching) con mesura. Use proxies y colecciones haraganas para la mayora de las asociaciones a clases que no es probable que sean retenidas en el cach de 2do nivel. Para asociaciones a clases cacheadas, en donde exista una probabilidad extremadamante alta de ubicarla en el cach, inhabilite explcitamente la captura haragana usando lazy="false". Cuando, para un caso de uso en particular, sea apropiado usar una captura por join, use una consulta con left join fetch. use el patrn open session in view, o una fase de ensamble (assembly phase) disciplinada para evitar problemas con datos no capturados. Hibernate libera al programador de la tediosa tarea de escribir objetos de transferencia de datos (DTO por sus siglas en ingls). En una arquitectura EJB tradicional, los DTOs tienen un doble propsito: uno, sortear el problema de que los entity beans no son serializables; el otro, que implcitamente definen una fase de ensamble en donde todos los datos usados por la interfaz de usuario o "view" tiene que ser capturados y puestos en orden en DTOs, antes de que el control le sea devuelto a la capa de presentacin. Hibernate elimina el primer propsito, pero an se necesita una fase de ensamble (imagnese a los mtodos de negocio como si tuvieran un estricto contrato con la capa de presentacin acerca de qu datos hay disponibles en los objetos desprendidos), a menos que se est dispuesto a mantener la sesin abierta a travs de la capa de presentacin. Esto no es una limitacin de Hibernate, sino un requerimiento fundamental para un acceso seguro a datos transaccionales. Considere abstraer su lgica de negocios, separndola de Hibernate. Oculte el cdigo (Hibernate) de acceso a datos detrs de una interfaz. Combine los partrones DAO y Sesin Thread Local. Se puede hacer incluso que algunas clases sean persistidas por JDBC escrita a mano, y asociadas a Hibernate por medio de un UserType. (Este consejo se aplica slo a aplicaciones "lo suficientemente largas", no es adecuado para una aplicacin con 5 tablas!) No use mapeos de asociacin exticos. Los casos de uso bien definidos, que involucren verdaderas asociaciones de-muchos-a-muchos, son raros. En general se necesita que la "tabla de vnculo" almacene informacin adicional. En ese caso, es mucho mejor usar dos asociaciones de-uno-a-muchos a una clase de vnculo intermedia. De hecho, creemos que la mayora de las asociaciones son de-uno-a-muchos y de-uno-a-uno. Hay que tener cuidado al usar cualquier otro estilo de asociacin, y preguntarse si es verdaderamente necesario. Prefiera las asociaciones bidireccionales. Las asociaciones unidireccionales son ms difciles de consultar. En aplicaciones grandes, casi todas las asociaciones deben ser navegables por consultas en ambas direcciones.

198 de 198

17/02/2009 09:25 a.m.

You might also like