HIBERNATE - Persistencia Relacional para Java Idiomático

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

HIBERNATE - Persistencia relacional para Java Idiomático
Documentación de Referencia de Hibernate
3.3.1 Traductor: Gonzalo Díaz Copyright © 2004 Red Hat Middleware, LLC. Prefacio 1. Introducción a Hibernate 1.1. Prefacio 1.2. Parte 1 - La Primera Aplicación Hibernate 1.2.1. La primera clase 1.2.2. El archivo de mapeo 1.2.3. Configuración 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 asociación unidireccional basada en un Set 1.3.3. Trabajar con la asociación 1.3.4. Colección de valores 1.3.5. Asociaciones bidireccionales 1.3.6. Trabajar con vínculos bidireccionales 1.4. Parte 3 - La aplicación de web "Event Manager" 1.4.1. Escribir el servlet básico 1.4.2. Procesamiento y presentación 1.4.3. Despliegue (deploy) y test 1.5. Sumario 2. Arquitectura 2.1. Generalidades 2.2. Estados de una instancia 2.3. Integración con JMX 2.4. Soporte de JCA 2.5. Sesiones contextuales 3. Configuración 3.1. Configuración programática 3.2. Obtener una SessionFactory 3.3. Conexiones JDBC 3.4. Propiedades optativas de configuración 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. Estadísticas de Hibernate 3.5. Logueo (logging, bitácora) 3.6. Implementando una NamingStrategy 3.7. Archivo de configuración XML 3.8. Integración con los Servidores de Aplicación J2EE 3.8.1. Configuración de una estrategia transaccional 3.8.2. SessionFactory ligada a JNDI 3.8.3. Manejo del contexto actual de la sesión 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 Idiomático

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 métodos de acceso y "mutadores" (accessors, mutators) para los campos persistentes. 4.2. Implementar herencia 4.3. Implementar equals() y hashCode() 4.4. Modelos dinámicos 4.5. T-uplizadores 4.6. Extensiones 5. Mapeo O/R básico 5.1. Declaración 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. Optimización 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" básicos 5.2.3. "Value types" hechos a medida 5.3. Mapear una misma clase más 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 foráneas de las colecciones 6.2.2. Elementos de la colección 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 colección avanzados 6.3.1. Colecciones ordenadas

2 de 198

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

HIBERNATE - Persistencia Relacional para Java Idiomático

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. Introducción 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 unión 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 unión 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 más 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 dinámicos 9. Mapeo de herencia 9.1. Las tres estrategias 9.1.1. Una tabla por jerarquía 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 jerarquía 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 implícito 9.1.7. Mezclar polimorfismo implícito 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. Parámetros vinculados 10.4.1.5. Paginación 10.4.1.6. Iteración 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. Detección automática de estado 10.8. Borrar objetos persistentes 10.9. Replicar un objeto entre dos repositorios de datos distintos 10.10. "Flush" de la sesión 10.11. Persistencia transitiva

3 de 198

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

Acotar el resultado 15.6.15. Interceptores y eventos 12. La interfaz StatelessSession 13.9.6. Sistema de eventos 12.2.2. Asociaciones 15. Entornos no administrados 11.3.1.2.1.2. Usar JTA 11. Expresiones 14.1. Conversaciones largas 11.1.4. Actualizaciones y borrados en masa 14.Persistencia Relacional para Java Idiomático http://www.1.2.2.html 10. HQL: El lenguaje de consultas de Hibernate 14.3.3. Sintaxis del "Constructor de Valor de Fila" (row value constructor) 15.8.1. Usar metadatos 11.18.8.3. La cláusua "where" 14. Consultas polimórficas 14.3.12. Crear una instancia de Criteria 15.3.1.hibernar.1. Seguridad declarativa de Hibernate 13.1. Demarcación de las transacciones de base de datos 11.1.16. Problemas comunes 11.2.HIBERNATE . Consultas "Criteria" 15.5. Transacciones y concurrencia 11.17.m. Consultas con entidades 16. Chequeo de versión hecho por la aplicación 11.1. La cláusula "select" 14. Proyecciones. Asociaciones y "joins" 14. Ordenar el resultado 15. agregado y agrupamiento 15.1.4. Relevancia de mayúsculas y minúsculas 14.4.1.2. Unidad de trabajo 11.1.7.5. "Lock" pesimista 11. Manipular colecciones y asociaciones 16. Funciones agregadas 14.12.3.9.2.4. Consultas "Example" 15.3.2.2. Subconsultas 14. La sesión y el alcance (scope) de las transacciones 11. Operaciones del tipo "Lenguaje de Modificacion de Datos" (DML-style) 14. SQL nativo 16.4. Consultas escalares 16. Inserciones en lotes 13.13.3. La cláusula "group by" 14.1.14. Captura dinámica de asociaciones 15.Considerar la identidad de los objetos 11.org/documentacion_es/castellano.4. Control optimista de concurrencia 11.3. Ejemplos de HQL 14.1.11. Referirse a la propiedad identificadora 14. Expiración de transacciones 11. Consejos y trucos 14. Componentes 14. Devolver múltiples entidades 4 de 198 17/02/2009 09:25 a. Consultas por identificador natural 16. Procesamiento en lotes 13.7. Modos de liberación de conecciones 12.5. Crear un método a medida para el versionado automático 11. Consultas y subconsultas desprendidas 15.4. Objetos desprendidos y versionado automático 11. . Actualizaciones en lotes 13. La cláusula "order by" 14.1. La cláusula "from" 14. Interceptores 12.3.4.1. Sesión extendida y versionado automático 11.2.10. Manejo de excepciones 11.3.3. Usar un SQLQuery 16. Formas de la sintaxis de los "joins" 14.2.

6.1. Utilizar Ant para las actualizaciones incrementales del esquema de base de datos 20.2.1. Ciclo de vida de las propagaciones en cascada 21. Monitorear la performance 19.1.5. Devolver entidades no administradas 16. Ejemplo: Padre/Hijo 21. Usar la captura por lotes 19.3. Mapeo XML 18. idbags y sets son las colecciones más eficientes de actualizar 19.4.1.1. Propiedades 20. Propagaciones en cascada y unsaved-value 21. Nota sobre las colecciones 21.4.1.1.5. Taxonomía 19. El caché de 2do nivel 19.3. Alias y referencias a propiedades 16. Manipulación de los datos XML 19.2.1. Admninistrar los cachés 19.3.1. SQL a medida para cargar 17. Trabajar con datos XML 18.8.2.2.4. Borrado en una pasada 19. Metadatos del mapeo XML 18.org/documentacion_es/castellano.2.6. Estrategia de lecto/escritura no estricta 19.2. Usar la captura de propiedades haragana 19. Usar return-property para especificar nombres de columna/alias explícitamente 16. El caché de consultas (query cache) 19. Clases persistentes 22.5.1.4.4. Usar procedimientos almacenados (stored procedures) para efectuar consultas 16. Filtros de Hibernate 18.1.2.7. Inicializar colecciones y proxies 19.2.3.1.1.2.1.5. Las lists. Conclusión 22. Generación automática del esquema de base de datos 20. Estrategia de lecto/escritura 19.1. Retocar el esquema de base de datos 20.1. Estrategia de sólo lectura 19.1. Estrategias de captura (fetch) 19.1.1.5. Mapeos de Hibernate 5 de 198 17/02/2009 09:25 a.6. 19.1. Estrategia transaccional 19.2. Las bags y lists son las colecciones inversas más eficientes 19. Ejemplo: La aplicación Weblog 22. Mejorar la performance 19.6. Usar Ant para la validación del esquema de base de datos 21.1.2.2. Ejecutar la herramienta 20.3.2.1. Usar Ant 20. Especificar el mapeo XML y el mapeo de la clase al mismo tiempo 18.1. Manejar herencia 16.6.5.2.1.2.7. Parámetros 16.html 16. SQL a medida para crear.1. Proxies de las asociaciones de un solo extremo 19. Trabajar con asociaciones haraganas 19.1. . maps.2.6.2.1.3. Ajustar las estrategias de captura 19.m. Actualizaciones incrementales del esquema de base de datos 20.1.6. Comprender la performance de las colecciones 19.2.1. Monitorear una SessionFactory 19.5.4.1.1. almacenar y borrar 16. Especificar sólo un mapeo XML 18. Guía de las herramientas (Toolset) 20.1.2.2.1. Mediciones 20.1.2.5. Usar la captura mediante subselects 19.HIBERNATE .3.3.1.Persistencia Relacional para Java Idiomático http://www. de-uno-a-muchos bidireccional 21.hibernar. Filtrar datos 17. Consultas SQL nombradas 16.5. Reglas y limitaciones en el uso de procedimientos almacenados 16.1. Validación del esquema de base de datos 20.7.5.4.4. Mepeos de caché. Compatibilidad entre el proveedor de caché y la estrategia de concurrencia 19.2.

y puede reducir considerablemente el tiempo que. puede ser embarazoso y demandar mucho tiempo. Use esta documentación de referencia como su fuente primaria de información.Persistencia Relacional para Java Idiomático http://www. son contestadas en el sitio de web de Hibernate. En el sitio de web de Hibernate hay vínculos a demostraciones de terceros. por favor siga los siguientes pasos: Lea el siguiente instructivo: Capítulo 1. Si usted es nuevo en Hibernate y en lo que respecta al Mapeo objeto/relacional. Asociaciones en claves alternativas 24. con un esquema de base de datos basado en SQL.4. . en el directorio doc/reference/tutorial/ Lea Capítulo 2. tipee ant eg (usando Ant). póngase en contacto con nosotros en la lista de correo de programación. Discriminación basada en el contenido 23. El código fuente del instructivo está incluido en la distribución descargable. EJB.4.3.hibernate.properties. y ayudará en la tarea usual de traducir desde una representación tabular a un gráfico de objetos. es más útil con modelos orientados a objetos cuya lógica de negocio reside en la capa intermedia. Arquitectura para entender en qué entornos Hibernate puede ser usado.HIBERNATE . Introducción a Hibernate. Autor/Obra 23.org/documentacion_es/castellano. únase a la lista de correo de programación de Hibernate. Sin embargo. sino que también provee utilidades para consulta y captura de datos. Si a usted le interesa la programación de Hibernate. o desde Windows.1. Cliente/Orden/Producto 23. Échele un vistazo al directorio eg/ en la distribución de Hibernate. para reportes de defectos (bugs) y pedidos de mejoras. Si le interesa traducir este documento. Ejemplo de clave compuesta 23.4.4. o incluso nuevo en Java.4. en los entornos corporativos actuales. Contiene una simple aplicación autosuficiente. Probablemente. etc). Código Hibernate 23. utilice el foro en el sitio de Hibernate. Empleador/Empleado 23. habría que invertir con el manejo manual de datos mediante SQL y JDBC. Considere leer Java Persistence with Hibernate (http://www. Struts. tipee build eg. El Área Comunitaria del sitio de web de Hibernate es un buen recurso acerca de patrones de diseño y varias soluciones de integración (Tomcat.2. Copie su driver de JDBC al directorio lib/ y edite etc/hibernate. 6 de 198 17/02/2009 09:25 a. Las preguntas frecuentes (FAQ.html 22.3. Hibernate no sea la mejor solución para aplicaciones data-céntricas que tengan casi toda su lógica de negocios en procedimientos almacenados (stored procedures) en la base de datos.4.4. El término "mapeo objeto/relacional" (ORM por sus siglas en inglés) se refiere a esta técnica de "mapear" la representación de los datos desde un modelo de objetos hacia un modelo de datos relacional.manning. de-muchos-a-muchos con atributo compartido de clave compuesta 23. ejemplos e instructivos. el cual es una especie de manual con instrucciones paso a paso. Hibernate no sólo 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).1. de otra manera. situado en el directorio de distribución.m.3.hibernar. Hibernate puede ayudarlo a encapsular o eliminar código SQL que sea específico de un proveedor de BD.2. También visite http://caveatemptor. Hibernate es una herramienta de mapeo objeto/relacional para ambientes Java. especificando valores correctos para su base de datos.com/bauer2) si necesita más ayuda con el diseño de aplicaciones o si prefiere un instructivo paso a paso. Asociación de-uno-a-uno "con tipo" 23. También proveemos un sistema JIRA de seguimiento de problemas. por sus siglas en inglés). Si tiene preguntas. Desde la consola.5. Prácticas recomendadas Prefacio Trabajar con software orientado a objetos y bases de datos relacionales. La meta de Hibernate es aliviar al programador del 95% de las tareas más comunes relacionadas con persistencia. Ejemplos misceláneos de asociación 23.org y descargue la aplicación de ejemplo para Persistencia de Java con Hibernate. Ejemplo: Mapeos varios 23. JBoss AS.

hibernar.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven. Lo primero que tenemos que hacer es montar nuestro entorno de desarrollo.1.0" xmlns:xsi="http://www. Introducción a Hibernate 1. entre otras cosas. (véase http://www. Hibernate se construye usando Maven. por sus siglas en inglés).La primera aplicación Hibernate Supongamos que tenemos una pequeña aplicación de base de datos que puede almacenar eventos a los que queremos asistir.HIBERNATE . y entrenamiento para Hibernate.org/POM/4. . el cual.. Empezamos con una simple aplicación que usa una base de datos residente en memoria.0.apache. destinado a usuarios nuevos de Hibernate. las cuales se convierten en "transitivas".m. . Más aún: provee un manejo transitivo de dependencias. llamada HSQLDB. con el tono de un instructivo. y. Todo el código está contenido en el directorio tutorials/web del código fuente del proyecto. Este instructivo se basa en otro anterior. le recomendamos que comience con una buena introducción a estas tecnologías.0. Siéntase en libertad de usar cualquier base de datos con la que esté familiarizado. también necesitamos una dependencia a la API de se <dependency> <groupId>javax. antes de adentrarse en Hibernate. 1. o no se maneja bien ellos. <dependencies> <dependency> <groupId>${groupId}</groupId> <artifactId>hibernate-core</artifactId> </dependency> <!-. y como tal no depende de un contenedor de servlets para poder ser ejecutado. Capítulo 1. le ahorrará tiempo y esfuerzo.apache.2. Nota Hay otra aplicación a modo de ejemplo/instructivo en el directorio del código fuente /tutorials/eg. Prefacio Este capítulo es una introducción a Hibernate. <project xmlns="http://maven.apache.Como ésta es una aplicación de web. escrito por Michael Gloegl. así como otras bibliotecas (libraries). Importante Este instructivo sobreentiende que el usuario ya tiene conocimiento de Java y de SQL. . específicamente.w3. fáciles de comprender. El montaje (setup) básico es el mismo que para las instrucciones a continuación. instalar todas las dependencias que Hibernate necesita.hibernate.org/POM/4.org/xsd/maven-4. A la larga.servlet</groupId> <artifactId>servlet-api</artifactId> </dependency> </dependencies> </project> 7 de 198 17/02/2009 09:25 a.0 http://maven. Si cualquiera de ambos es nuevo para usted. para evitar describir la instalación y configuración de cualquier base de datos en particular.org/documentacion_es/castellano. Parte 1 .org/SupportTraining/). lo cual simplemente significa que para usar Hibernate podemos definir nuestras dependencias dentro de él: Hibernate mismo define las dependencias que necesita.. Construimos la aplicación de a pasos pequeños. Hibernate es un componente vital del paquete de productos conocido como "Sistema Empresarial JBoss de Middleware" (JEMS. hay disponible soporte para desarrollo comercial y de producción. Dicho ejemplo se basa en línea de comandos (consola). provee manejo de dependencias. Vamos a usar una base de datos residente en memoria.html A través de JBoss Inc. e información acerca del anfitrión (o anfitriones) de dichos eventos.Persistencia Relacional para Java Idiomático http://www.

private. De hecho.html Nota Básicamente. ya necesitan distinguir objetos por id.util. para poder instanciar el objeto mediante reflexión.hibernar.title = title. 8 de 198 17/02/2009 09:25 a. la mayoría de las aplicaciones (especialmente aplicaciones de web). la ventaja de los métodos de acceso es proveer mayor solidez a la hora de refinar ("refactoring") el código. La primera clase Nuestra primera clase persistente es un simple JavaBean con algunas propiedades. La propiedad identificadora o id contiene un identificador único para un evento en particular.xml. Luego creamos una clase que representa el evento que queremos almacenar en la base de datos.m. public class Event { private Long id.tutorial. import java. } public void setDate(Date date) { this. Todas las clases de entidad persistentes (las hay menos importantes también) necesitarán dicho id. } private void setId(Long id) { this. más que una limitación. private String title. si queremos usar a pleno las capacides de Hibernate.pero no es obligatorio. etc) directamente.id = id. public. 1.2.org/documentacion_es/castellano.date = date. Consejo Aunque no es estrictamente necesario. usualmente no manipulamos directamente la identidad de un objeto. Vea el sitio de Maven para más información.HIBERNATE . y automáticamente generar el proyecto por usted (lo cual puede ahorrar mucho tiempo y esfuerzo). private Date date.domain.hibernate. public Event() {} public Long getId() { return id. El constructor sin argumentos sí es obligatorio. } public Date getDate() { return date. respectivamente).Persistencia Relacional para Java Idiomático http://www. } public void setTitle(String title) { this. . Este diseño es el recomendado . muchos entornos visuales de progrmación (IDEs) ya cuentan con integración con Maven para leer estos archivos POM. cuando el objeto es grabado. Hibernate puede aceder a los campos directamente. así que el método "setter" del id debería ser privado.1. De todos modos. aquí estamos describiendo el archivo /tutorials/web/pom. así que esta característica debería considerarse una ventaja. package org. } public String getTitle() { return title. Hibernate puede acceder a métodos en cualquier nivel de acceso (protected. Sólo Hibernate asigna ids. según el diseño de su aplicación. } } Se puede ver que esta clase usa la convención estándar de JavBeans para nombrar a sus métodos "setter" y "getter" (escritura y lectura de propiedades.Date. La opción de qué nivel de acceso utilizar es suya.

<hibernate-mapping> <class name="events. Por supuesto. omitiremos la declaración de la DTD. El archivo de mapeo Hibernate necesita saber cómo cargar y almacenar objetos de la clase persistente. Sepa que Hibernate no buscará la DTD en la red. Todas las clases de entidad persistente (de nuevo: hay clases dependientes. cada instancia representando un registro de la tabla. La estructura básica del archivo de mapeo se ve así: <?xml version="1.org/documentacion_es/castellano.hibernar. Aquí es donde entra en juego el archivo de mapeo. La puede usar para autocompletar elementos de mapeo y atributos de XML en su indetfaz gráfica (IDE). También puede abrir la el archivo de la DTD en su procesador de texto .Event" table="EVENTS"> </class> </hibernate-mapping> Hasta el momento. ésta no es optativa. le vamos a informar a Hibernate acerca de esta clase persistente.HIBERNATE .. La DTD está incluida en el archivo. sino en el classpath. Éste le dice a Hibernate a qué tabla en qué base de datos tiene que acceder.2. El directorio debería verse así: . Ponga este archivo de código fuente Java en un directorio llamado src en el directorio de desarrollo..Persistencia Relacional para Java Idiomático http://www. le hemos dicho a Hibernate cómo persistir y cargar un objeto de la clase Event en la tabla EVENTS. y de ver los valores por defecto.dtd"> <hibernate-mapping> [. y para la captura de datos sin la construcción de bytecode. a una tabla en la base de datos SQL. Ahora continuamos con el mapeo del identificador único a la clave primaria de la tabla.sourceforge.2.html El constructor sin argumentos es obligatorio para todas las clases persistentes.Event" table="EVENTS"> <id name="id" column="EVENT_ID"> <generator class="native"/> </id> </class> 9 de 198 17/02/2009 09:25 a.0//EN" "http://hibernate.m. 1.] </hibernate-mapping> Nótese que la DTD de Hibernate es bastante sofisticada. para poder generar "proxies" en tiempo de ejecución. El constructor puede ser privado.net/hibernate-mapping-3.java En el paso siguiente. que no son entidades de primer nivel) necesitan dicho mapeo. y qué columnas de dicha tabla tiene que utilizar.es la forma más fácil de tener una visión general de todos los elementos.0. como veremos luego. . incluya un elemento class. como no queremos preocuparnos por manipular dicho identificador. sin embargo. Por añadidura. En los ejemplos sucesivos. configuramos una "estrategia de generación de identificador" de Hibernate para que use una clave primaria "sustituta" (surrogate key). se requiere al menos el nivel de acceso "package" o por defecto. +lib <bibliotecas de Hibernate y de terceros> +src +events Event. hibernate3. por brevedad.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3. Entre las dos tags hibernate-mapping.jar. y dentro del paquete correspondiente. <hibernate-mapping> <class name="events. Hibernate tiene que crear los objetos para usted utilizando Java Reflection. junto con algunos comentatios. así como en el directorio src/ de la distribución de Hibernate.

Coloque este archivo en el directorio lib/ del directorio de desarrollo. ninguna de las propiedades de la clase se considera persistente. usted sólo necesita hsqldb. Hibernate tratará de determinar la conversión adecuada e incluso el tipo mismo.2. esta detección automática (que usa Java Reflection) puede no generar el valor por defecto que usted esperaba o necesita. si el atributo type no se especifica en el mapeo. Usted podrá ver que arranca y está ligada a un socket TPC/IP.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. así que mejor la mapeamos con un nombre diferente. justo en el mismo directorio que el archivo Java de la clase Event.org/). haga arrancar la base de datos ejecutando: java -classpath . De nuevo.Server en este directorio de datos.jar de dicha descarga. pero los sufijos hbm. Hibernate no puede saber si la propiedad.java Event. puede ser descargada del sitio de web de HSQL DB (http://hsqldb. pero el title no? A falta del atributo column. En este caso. usamos native. Si quiere comenzar con una base de datos nueva en el transcurso de este instructivo.org/documentacion_es/castellano.Persistencia Relacional para Java Idiomático http://www. El atributo "column" le dice a Hibernate qué columna de la tabla EVENTS usamos como clave primaria.jar org. Ahí es donde nuestra aplicacíón se conectará luego.Hibernate usará los métodos getter y setter para acceder a ella.m.html </hibernate-mapping> El elemento id es la declaracuión de la propiedad indentificadora.xml Continuamos con la configuración principal de Hibernate 1.xml. Ahora la estructura de directorios debería verse así: . El nombre de los archivos de mapeo puede ser arbitrario. que es del tipo java. Finalmente.hbm. Antes de hacerlo. Hibernate buscará getDate()/setDate().. Los tipos que usamos en los archivos de mapeo no son. Hibernate soporta tanto identificadores generados por la base de datos. el atributo name del elemento property le dice a Hibernate qué métodos getter y setter usar. Configuración de Hibernate Ahora tenemos ubicados una clase persistente y su archivo de mapeo. es que el mapeo title también carece del atributo type. Ése es el caso con la propiedad date. En ralidad. <hibernate-mapping> <class name="events. borre todos los archivos en el 10 de 198 17/02/2009 09:25 a. como es de esperarse. debería ser mapeada a una columna timestamp. +lib <bibliotecase de Hibernate y de terceros> +src +events Event. tipos Java. En algunos casos. Así que. Por defecto. o a una columna time.hbm. Es el momento de configurar Hibernate mismo. como globalmente únicos. El elemento anidado generator especifica la estrategia para la generación de identificador. incluimos declaraciones para las propiedades persistentes en el archivo de mapeo. Otra cosa interesante.xml son una convención en la comunidad de programadores de Hibernate. Tampoco son tipos SQL. . Pero date es una palabra reservada en la mayoría de las base de datoss. cierre la base de datos HSQL DB pulsando CTRL + C en la ventana. A estos tipos se los llama Tipos de mapeo de Hibernate. así como getTitle()/setTitle(). o asignados por la aplicación (o generados por cualquier estrategia para la cual usted haya escrito una extensión). en este caso. En este caso.util.es ahí en donde HSQL DB almacenará sus archivos de datos. necesitamos una base de datos. Ahora.3.hibernar. Este achivo de mapeo debería ser grabado como Event.hsqldb. la cual elige la mejor estrategia dependiendo de la BD y dialecto configurados. mantengamos la información completa (de día y hora) mapeando la propiedad al conversor timestamp. Esto funciona para title. Cree un directorio llamado data en la raíz del directorio de desarrollo . Hibernate por defecto usa el nombre de la propiedad como nombre de columna.Date. ¿Por qué el mapeo de la propiedad date incluye el atributo column. HSQLBD es una base de datos basada en Java. El atributo name="id" declara el nombre de la propiedad Java . conversores que podemos traducir de tipos Java a SQL y viceversa.HIBERNATE ./lib/hsqldb.

provider_class">org. La mayoría prefiera el archivo de configuración XML.html subdirectorio data/. La distribución de Hibernate contiene varias herramientas de código abierto (open source) que generan pool de conexiones .url">jdbc:hsqldb:hsql://localhost</property> <property name="connection. con la ayuda de la tarea de Ant SchemaExport. Construir con Ant 11 de 198 17/02/2009 09:25 a.net/hibernate-configuration-3.properties.pool_size">1</property> <!-.inhabilita el caché de 2do nivel --> <property name="cache.xml un tanto más sofisticado. o incluso una configuración totalmente programática. Dése cuenta de que.sourceforge.m. podemos usar un simple archvo hibernate. Hibernate es la capa de su aplicación que se conecta con esta base de datos.dialecto SQL --> <property name="dialect">org. .cfg.2. Fnalmente.dtd"> <hibernate-configuration> <session-factory> <!-.auto activa la generación automática de esquemas directamente en la BD.auto">create</property> <mapping resource="events/Event. Esto por supuesto puede ser desactivado (quitando esta opción) o ser redirigido a un archivo.xml en la raíz del classpath. el cual también tenemos que configurar.cache.Persistencia Relacional para Java Idiomático http://www.driver_class">org. de manera que quede en la raíz del classpath.hbm.borra y recrea la BD en cada arranque --> <property name="hbm2ddl. use varias configuraciones de <session-factory> por lo común en otros tantos archivos de configuración (para un arranque más fácil).0.datos de conexión de la BD --> <property name="connection.cfg. Las conexiones se hacen mediante un pool de conexiones JDBC.hibernate.username">sa</property> <property name="connection.4.hsqldb. Copie este archivo en el directorio de fuentes (src). Para la configuración de Hibernate. Configuramos la SessionFactory de Hibernate una fabrica global responsable de una base de datos en particular.pool de conexiones JDBC (usamos el que ya viene incorporado) --> <property name="connection.jdbcDriver</property> <property name="connection.0' encoding='utf-8'?> <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3. La propiedad "dialect" especifica la variante de SQL en particular que Hibernate genera.hibernate.HIBERNATE . un archivo hibernate. y arranque HSQL DB nuevamente.hibernar.habilita el manejo automátio de contexto de sesión por parte de Hibernate --> <property name="current_session_context_class">thread</property> <!-.dialect. El manejo automático de sesiones por contextos de persistencia será muy útil. 1. pero para este instructivo usaremos el pool que ya viene incorporado en Hibernate.imprime todo el SQL ejecutado en la salida estándar <property name="show_sql">true</property> <!-. deberá copiar las bibliotecas que hagan falta en el classpath. Los primeros 4 elementos property contienen la configuración necesaria para la conexíón JDBC. y usar propiedades de conexión diferentes.password"></property> <!-.HSQLDialect</property> <!-.xml"/> </session-factory> </hibernate-configuration> --> Fíjese en que este archivo de configuración XML usa una DTD distinta. al arrancar. así que necesita información de conexión. agregamos el o los archivo de mapeo para las clases persistentes a la configuración. como pronto veremos. La opción hbm2ddl. Si tiene varias base de datos. si quiere usar un pool de conexiones JDBC de mayor calidad (para aplicaciones ya instaladas en producción) hecho por terceros.0//EN" "http://hibernate.org/documentacion_es/castellano. Hibernate busca automáticamente un arhivo llamado hibernate. <?xml version='1.NoCacheProvider</property> <!-.

. Cada objeto Session representa una "unidad de trabajo" de un solo Thread.jar al classpath que usemos para la compilación.xml.jar"/> </fileset> </path> <target name="clean"> <delete dir="${targetdir}"/> <mkdir dir="${targetdir}"/> </target> <target name="compile" depends="clean. Un archivo de construcción Ant básico 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="*. Dicho arranque incluye construir un objeto SessionFactory global. Aquí no vamos a discutir cómo instalar Ant. y estará situado directamente en el directorio de desarrollo.obténgalo de la Página de descarga de Ant. copy-resources"> <javac srcdir="${sourcedir}" destdir="${targetdir}" classpathref="libraries"/> </target> <target name="copy-resources"> <copy todir="${targetdir}"> <fileset dir="${sourcedir}"> <exclude name="**/*.org/documentacion_es/castellano.m. Tenemos que hacer arrancar Hibernate. . Una SessionFactory puede abrir nuevos objetos Session. El código de SessionFactory es thread-safe.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. que se encargará del arranque y hará que el acceso a SessionFactory sea más conveniente.html Ahora vamos a construir (build) esta aplicación instructiva usando Ant.Persistencia Relacional para Java Idiomático http://www.*. los archivos de configuración y mapeo.pero primero debemos completar la instalación (setup) con algo de código "infraestructural".hibernar. Vamos a crear una clase de ayuda llamada HibernateUtil. Deberá tener Ant ya instalado . import org. Después de haber instalado Ant.hibernate. También copiará todos los archivos fuente no-Java al directorio de destino (target).5. debería obtener la siguiente salida: C:\hibernateTutorial\>ant Buildfile: build. y es instanciado sólo una vez.java"/> </fileset> </copy> </target> </project> Esto le dice a Ant que agregue todos los archivos del el directorio lib que terminen en . Veamos cómo implementarla: package util. que se llamará build.2. Arranque y ayudantes Es hora de cargar y grabar algunos objetos Event.HIBERNATE . y almacenarlo en algún lugar de fácil acceso para el código de la aplicación. 12 de 198 17/02/2009 09:25 a. por ejemplo. podemos crear el archivo de construcción de Ant (build file). Si ejecuta Ant ahora. Por favor refiérase al Manual de Ant.

Para omitir este código completamente. . y cambie los valores si desea una salida más locuaz.2.*. import org. Ahora estamos listos para efectuar verdadero trabajo con Hibernate.6.Session. public class EventManager { public static void main(String[] args) { 13 de 198 17/02/2009 09:25 a.java en el directorio de código fuente. sólo los mensajes de arranque de Hibernate se muestran en la salida estándar. al lado de hibernate. sino que oculta el hecho de que se emplea un singleton estático.cfg.xml. . 1. static { try { // Cree la SessionFactory para hibernate.xml +util HibernateUtil. Coloque HibernateUtil.HIBERNATE .println("Initial SessionFactory creation failed.cfg. Copie log4j.Persistencia Relacional para Java Idiomático http://www.java Event.Hibernate usa commons logging y le deja a usted la opción entre log4j y el logging específico de Java. } } public static SessionFactory getSessionFactory() { return sessionFactory. Cargar y almacenar objetos Finalmente podemos usar Hibernate para cargar y grabar objetos .cfg.html import org. dado que puede ser "tragada" System. Por defecto. import util.HibernateUtil. Si usted le da un nombre a la SessionFactory en su archivo de configuración.properties de la distribución de Hibernate (está en el directorio etc/) a su directorio src.hibernar..org/documentacion_es/castellano.err. en un paquete al lado de events: . public class HibernateUtil { private static final SessionFactory sessionFactory.cfg. import java. Dele un vistazo a la configuración de ejemplo. La mayoría de los programadores prefiere Log4j.java hibernate. Escribimos una clase EventManager con un método main(). } } Esta clase no sólo produce la SessionFactory global.xml sessionFactory = new Configuration(). por ejemplo.xml +data build. package events. Finalmente. logging) . Estas opciones avanzadas se discuten en la documentación de referencia de Hibernate. } catch (Throwable ex) { // Asegúrese de loguear la excepción. +lib <Hibernate y las bibliotecas de terceros> +src +events Event. Hibernate en realidad intentará vincularla a JNDI tras haber sido creada.m.hbm.buildSessionFactory(). usted también podría usar "despliegue JMX" y dejar que el un contenedor habilitado para JMX instancie y construya un HibernateService en la JNDI." + ex).Date. en un inicializador estático (invocado una sola vez por la JVM cuando la clase se carga). La parte infraestructural del instructivo ha finalizado. necesitamos configurar un sistema de logueo (bitácora. Podría haber estado buscando la SessionFactory en el JNDI de un servidor de aplicaciones.hibernate.util.xml Esto debería poder compilarse sin problemas.hibernate.configure(). throw new ExceptionInInitializerError(ex).

Una sesión comienza cuando se la necesita por primera vez. Una aplicación real (de web) se analiza más adelante en este instructivo. usamos la API para transacciones que está disponible en la clase Session. Para ejecutar esta primera rutina. cuando se hace la primera llamada a getCurrentSession().getSessionFactory(). obtiene una nueva sesión y comienza una nueva unidad de trabajo. considere la práctica de "una sesión por operación" como algo a evitar (un "anti-pattern").org/documentacion_es/castellano. Si usted llama getCurrentSession() de nuevo.save(theEvent).equals("store")) { mgr. Entonces. o varias? El ejemplo precedente usa una sesión para una operación. El modo de programación "ligado a threads" (thread-bound). En relación al alcance de la unidad de trabajo: Una sesión ¿debería usarse para ejecutar una sola operación de base de datos. Ahora Hibernate se encarga del SQL. Transacciones y Concurrencia acerca del manejo de transacciones y su delimitación. tenemos que agregar una "target" invocable al archivo de construcción de Ant. session. pero nunca se debe designar una aplicación de maneera que utilice una sesión para cada operación de base de datos. y se los pasamos a Hibernate.html EventManager mgr = new EventManager(). } HibernateUtil. new Date()).commit(). sólo JDBC. session. También hemos salteado cualquier manejo de errores en el ejemplo precedente.HIBERNATE . Así que. Event theEvent = new Event(). la unidad actual de trabajo está ligada al thread de Java que se esté ejecutando en ese momento en su aplicación. pero podría haber sido JTA).m. session. } } Creamos un objeto Event. Hibernate desliga la sesión del thread. es la forma más difundida de usar Hibernate. theEvent. Cuando la transacción termina. Usa sesión (Session) es una unidad de trabajo.beginTransaction(). El alcance de una sesión de Hibernate es flexible. ésta no es toda la historia: también hay que considerar el alcance (scope). 14 de 198 17/02/2009 09:25 a. Echémosle un vistazo a la sesión. gracias a la HibernateUtil). y al código de manejo de transacciones antes de ejecutarlo. Para "escudar" nuestro codigo respecto del sistema subyacente de transacciones (en este caso.cfg. a este método se lo puede llamar desde dondequiera.getSessionFactory(). theEvent.createAndStoreEvent("My Event".getCurrentSession()? Primero. es ligada al thread actual por Hibernate. como veremos más adelante. De todos modos. una vez que obtenemos una SessionFactory. Date theDate) { Session session = HibernateUtil. dado que permite una distribución en capas muy flexible: el código de delimitación de transacciones puede separarse del código de acceso a datos. ¿Recuerda que configuramos una opción con valor "thread" en hibernate. (fácilmente. <target name="run" depends="compile"> <java fork="true" classname="events. cuándo una unidad de trabajo empieza y cuándo termina. y ejecuta INSERTs en la base de datos. incluso si usted lo ve en algunos pocos de los ejemplos siguientes.close(). Por ahora mantendremos todo simple y asumiremos una correspondencia uno-a-uno entre una sesión de Hibernate y una transacción de BD. . Échele un vistazo al capítulo Capítulo 11. El código getCurrentSession() siempre devuelve la unidad "actual" de trabajo.hibernar. ¿Qué hace sessionFactory.Persistencia Relacional para Java Idiomático http://www. y la cierra por usted.getTransaction().getCurrentSession().xml? Debido a esto.setDate(theDate). el ejemplo no es lo suficientemente complejo como para demostrar ningún otro enfoque. if (args[0].EventManager" classpathref="libraries"> <classpath path="${targetdir}"/> <arg value="${action}"/> </java> </target> El valor del argumento "action" se asigna en la línea de comandos cuando esta target se invoca. } private void createAndStoreEvent(String title. y cuantas veces se desee. Esto es simple casualidad.setTitle(title).

List result = session. por supuesto.getTitle() + " Time: " + theEvent. (el valor de hbm2ddl="create" se traduce como "haga un DROP de todas las tablas del esquema. para previamente generar el esquema de base de datos mediante hbm2ddl. agreguemos algunas asociaciones de 15 de 198 17/02/2009 09:25 a.equals("list")) { List events = mgr. System. Nota: A esta altura.out.hibernar.listEvents(). } } También agregamos un nuevo método listEvents() method: private List listEvents() { Session session = HibernateUtil. Parte 2 . querríamos tanbién listar los eventos almacenados. un montón de salida de logueo.commit().getTransaction(). Hibernate generará el código SQL que haga falta.Persistencia Relacional para Java Idiomático http://www. si usted sigue los pasos que acabamos de describir cuidadosamente. dejarla habilitada borraría todo lo que usted haya almacenado hasta ese momento. lo enviará la base de datos. puede también invocar la acción store un par de veces más.properties.org/documentacion_es/castellano. y poblará los objetos Event con los datos que sean devueltos. y recree todas las tablas cuando la SessionFactory sea construida") Si usted ahora invocara Ant con -Daction=list.m. es usar el lenguaje de consultas de Hibernate (HQL. Ahora. así que agregamos una opción el el método principal: if (args[0]. De todos modos. } Lo que hicimos aquí. revise su archivo log4j. y. debería ver los eventos que haya almacenado hasta ese moento. siga estos pasos: Ejecute ant run -Daction=store para almacenar algo en la base de datos y.createQuery("from Event"). y las veces subsiguientes en que la aplicación recomienza utilizan dicho esquema.html C:\hibernateTutorial\>ant run -Daction=store Después de la compilación. partiendo de esta base. ?) Ése es el código INSERT ejecutado por Hibernate. Por lo general. session.xml. ?.getCurrentSession(). y aparecen seguido mensajes del tipo Table not found . por supuesto.HIBERNATE .cfg.size(). EVENT_ID) values (?. Ahora. dependiendo de su configuración. . session. Para ver los valores de dichos parámetros. Se pueden crear consultas SQL mucho más complejas con HQL.println("Event: " + theEvent. Ahora inhabilite hbm2ddl (convirtiendo la propiedad en un comentario) en el archivo hibernate. } else if (args[0]. Ahora. la mayoría de los usuarios de Hibernate experimenta problemas. for (int i = 0. por sus siglas en inglés) para cargar todos los objetos Event que existen en la base de datos.list(). 1. Al final encontrará la siguiente línea: [java] Hibernate: insert into EVENTS (EVENT_DATE. Si usted en algún momento cambia algo del mapeo o del esquema. Los signos de interrogación representan parámetros JDBC ligados.getDate()). usted debería ver que que Hibernate arracna. i++) { Event theEvent = (Event) events. Por supuesto.beginTransaction(). sólo se la deja habilitada cuando se efectúa un "unit testing continuo". no tendrá este problema. new Date()).Mapear asociaciones Hemos mapeado una clase persistente a una tabla. ya que hbm2ddl crea el esquema de base de datos la primera vez. pero en este caso.get(i).equals("store")) { mgr. return result. para ejecutar y chequear todo esto. title. i < events.getSessionFactory(). debe rehabilitar hbm2dll nuevamente para recrear la BD. o para reducir la locuacidad del archivo de log.3.createAndStoreEvent("My Event".

} 16 de 198 17/02/2009 09:25 a.hbm. public class Person { private private private private Long id.xml (y no olvide la referencia a la DTD en la parte superior): <hibernate-mapping> <class name="events.hbm. simplemente llamando aPerson. direccionalidad. 1.HIBERNATE . public class Person { private Set events = new HashSet(). public Person() {} // métodos "getter" y "setter" de acceso. Mapear la clase Person El primer bosquejo de la clase Person es simple: package events.hbm.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. Obviamente.events = events. public Set getEvents() { return events. Necesitamos una asociación unidireccional y de varios valores. y comportamiento de las colecciones.xml"/> <mapping resource="events/Person. .1. De este modo podremos navegar cómodamente los eventos para una determinada persona sin tener que ejecutar una consulta explícita. y luego mapeémoslas. Escribamos el código para esto en las clases de Java.3. y almacenaremos una lista de eventos en los cuales participan.xml"/> Y ahora crearemos una asociación entre estas dos entidades. } public void setEvents(Set events) { this.html clase. porque esta colección no contendrá elementos duplicados.3. Usamos una colección de Java. un Set. agreguemos el nuevo archivo de mapeo a la configuración de Hibernate.2. Primero. y los eventos tienen participantes. que pueda ser implementada con un Set.org/documentacion_es/castellano.hibernar.Persistencia Relacional para Java Idiomático http://www. 1.getEvents(). Una asociación unidireccional basada en un Set Agregaremos una colección de eventos a la clase Person. Las cuestiones de diseño con las que tenemos que lidiar son: multiplicidad. las personas pueden participar en eventos.m. <mapping resource="events/Event. int age. y setter privado para 'id' } Cree un nuevo archivo de mapeo llamado Person. agregaremos algunas personas a nuestra aplicación. String firstname. y el orden no es relevante para nosotros. String lastname.

se necesita una tabla de asociación. El esquema de base de datos para este esquema es.getCurrentSession(). session.add(anEvent). no hay llamados explícitos a update() o a save(). desde un punto de vista funcional. el nombre de la columna por el lado de los eventos. es decir. Event anEvent = (Event) session. Esto se llama "dirty checking automático".load(Event. Cada registro de esta tabla simboliza un vínculo entre una persona y un evento. Claramente. simplemente modifique la colección usando los métodos normales de las colecciones.Event"/> </set> </class> Hibernate soporta todo tipo de mapeos de coleccíón. Para una asociación "many-to-many".html } Antes de mapear esta asociación.m. se define con el elemento <key>. podríamos crear otra colección en la clase Event.commit().getTransaction().beginTransaction().load(Person. piense en el otro lado (los eventos). pero lo que sacamos en limpio de esta discusión. Person aPerson = (Person) session. ligados a una sesión de Hibernate. <class name="events.hibernar. en un nuevo método de EventManager: private void addPersonToEvent(Long personId. Usted también debe decirle a Hibernate la clase de objetos de su colección. entonces: _____________ __________________ | | | | _____________ | EVENTS | | PERSON_EVENT | | | |_____________| |__________________| | PERSON | | | | | |_____________| | *EVENT_ID | <--> | *EVENT_ID | | | | EVENT_DATE | | *PERSON_ID | <--> | *PERSON_ID | | TITLE | |__________________| | AGE | |_____________| | FIRSTNAME | | LASTNAME | |_____________| 1. Como puede usted ver. con el atributo column del <many-to-many>. La columna indentificadora por el lado de las personas. } Después de cargar una Person y un Event.HIBERNATE .3.class. A esto se lo llama una asociación "de-muchos-a-muchos" (many-to-many).getSessionFactory(). aPerson. siendo el "set" el más común. Por esto. es la multiplicidad de la asociación: hay "muchos valores" desde ambos lados. Esta es una opción de diseño que le dejamos a usted. anEvent. Hibernate detecta automáticamente que la colección ha sido modificada y necesita ser actualizada.org/documentacion_es/castellano. usamos el mapeo many-to-many de Hibernate. personId). si deseamos navegar en forma bidireccional. Trabajar con asociaciones Juntemos a alguna gente con sus eventos. por haber sido cargados o 17 de 198 17/02/2009 09:25 a. Long eventId) { Session session = HibernateUtil. Esto no es estrictamente necesario.3. El nombre de esta tabla se configura con el atributo table del elemento set. session.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. .getParticipants().getEvents(). o relación entre entidades. eventId). podemos simplemente mantener esta asociación unidireccional. O si no. siempre se puede ejecutar una consulta explícita para obtener los participamntes de un determinado evento.class. 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.Persistencia Relacional para Java Idiomático http://www.

que usted puede aplicar al diseño de su propia aplicación.getSessionFactory().out.createQuery("select p from Person p left join fetch p.events where p. Incluso una colección se puede modificar estando en este estado desprendido. por supuesto. incluso si son tocayos). Algunos.beginTransaction(). Las instancias de estos tipos no tienen su propia identidad. Colección de valores 18 de 198 17/02/2009 09:25 a. el método save() los devuelve (tal vez usted deba modificar alguno de los métodos previos. y sus instancias dependen de una entidad en particular. session2. cuando no está en estado persistente (si lo estuvo anteriormente.load(Event. Hibernate monitoreará cualquier cambio y ejecutará SQL entre bambalinas. para representar una dirección o una cantidad de dinero.Persistencia Relacional para Java Idiomático http://www. tal como se define por la opción de configuración thread para la clase CurrentSessionContext. // reasociación de aPerson. 1.getCurrentSession().setParameter("pid". en una aplicación Hibernate todas las clases JDK son consideradas "value types". cargar personas y eventos en distintas unidades de trabajo. flush).getCurrentSession().HIBERNATE .hibernar.uniqueResult(). en inglés detached). mgr. Long personId = mgr. A esas clases las llamamos value types. // fin de la primera unidad de trabajo aPerson.getSessionFactory(). por ejemplo. dos "entidades". System.createAndStorePerson("Foo". También se puede diseñar una colección de "value types". se denomina "nivelar.commit(). estos value types pueden ser encontrados no solamente en la JDK.id = :pid") .println("Added person " + personId + " to event " + eventId). personId) .4. Se podría. para que devuelvan dicho identificador). Como se mencionó anteriormente. Por supuesto. Long eventId) { Session session = HibernateUtil. El proceso de sincronizar el estado de lo que está en memoria con la base de datos.getTransaction(). Por ahora. session.getEvents(). eventId).commit(). como los int o String. else if (args[0]. Esto es conceptualmente bien distinto de una colección de referencias a otras entidades. generalmente al final de la unidad de trabajo. desagotar" la sesión (en inglés. usted ya los ha visto.getTransaction(). pero en el código Java ambas se ven casi igual. hacer referencia al mismo objeto firstname o primer nombre.3. este estado se llama "desprendido".org/documentacion_es/castellano. Bueno. private void addPersonToEvent(Long personId. pero usted puede escribir sus propias clases dependientes. la unidad de trabajo termina con un "commit" (o "rollback") de la transacción de base de datos. pero es un concepto importante. new Date()). Si necesita los identificadores de una persona y de un evento. de manera que cualquier modificación que se le hubiera hecho mientras estaba desprendido pueda ser grabada en la base de datos. // Eager fetch the collection so we can use it detached Event anEvent = (Event) session. esto no es muy útil en la situación actual.update(aPerson). ni se pueden compartir entre entidades (dos personas no pueden. hay otras clases y tipos "menos importantes" en un modelo típico. Person aPerson = (Person) session . session2. En nuestro código.createAndStoreEvent("My Event". simplemente complete este ejercicio agregando una nueva acción al método main() de EventManager. Esto incluye cualquier modificación que se le hubiera hecho a la colección de ese objeto entidad. por ejemplo. // aPerson (and its collection) is detached // comienzo de la segunda unidad de trabajo Session session2 = HibernateUtil.equals("addpersontoevent")) { Long eventId = mgr. . } Éste fue un ejemplo de una asociación entre dos clases igualmente importantes. De hecho. session. "Bar").m.beginTransaction().addPersonToEvent(personId. } El llamado a update convierte de nuevo en persistente un objeto que estaba desprendido. eventId). Se podría decir que lo liga a una nueva unidad de trabajo. e invóquelo desde la línea de comandos.html grabados en una unidad de trabajo). O modificar un objeto fuera de una sesión.add(anEvent). que estaba desprendida session2.class.

Une vez más. // el getEmailAddresses() podría disparar una carga "haragana" de la colección aPerson.m.5. Echémosle 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 colección es.getSessionFactory(). comparada con el mapeo anterior. sino a una colección de elementos de tipo string (al estar con minúscula nos damos cuenta de que es un tipo/conversor de Hibernate). } public void setEmailAddresses(Set emailAddresses) { this. es decir.html Agreguemos una colección de objetos "value type" a la entidad Person. vamos a hacer que la asociación funcione desde 19 de 198 17/02/2009 09:25 a.add(emailAddress). El atributo column de "element" define en dónde estas cadenas van a ser almacenadas. vamos a mapear una asociación bidireccional. Monitoree el log de SQL e intente optimizar esto con un "eager fetch" (captura ansiosa). El código Java es el mismo: private void addEmailToPerson(Long personId. igual que como hicimos antes al vincular personas y eventos.getTransaction(). } 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.commit(). private Set emailAddresses = new HashSet(). Asociaciones bidireccionales Acto seguido.3.beginTransaction(). . de nuevo un Set. session. Queremos almacenar direcciones de correo electrónico (email).getEmailAddresses(). no utilizamos una consulta con fetch para inicializar la colección. personId). que usa ambas columnas.hibernar.Persistencia Relacional para Java Idiomático http://www. lo cual es precisamente la semántica de un conjunto o "Set" en Java. y la colección. de manera que podamos agregarle un elemento.org/documentacion_es/castellano. una clave compuesta. es la parte element. String emailAddress) { Session session = HibernateUtil. 1. la cual le dice a Hibernate que la colección no contiene referencias a otra entidad. Person aPerson = (Person) session. de manera que el tipo que usaremos es String. en realidad.HIBERNATE .load(Person. Ahora podemos intentar agregar elementos a esta colección. Esto también implica que no puede haber direcciones de email duplicadas para una misma persona. El elemento key define el nombre de columna para la clave foránea. session.getCurrentSession(). De ahí que la invocacíón de su método "getter" disparará un SELECT adicional para inicializarla. } Esta vez.emailAddresses = emailAddresses. public Set getEmailAddresses() { return emailAddresses.class. el atributo table del set determina el nombre de la tabla para la colección.

Fíjese en que los nombres de columna en ambos documentos han sido alternados. en Event. que lo considere como un espejo de lo que ocurre en el otro 20 de 198 17/02/2009 09:25 a.. y crean métodos facilitadores que asignan correctamente los vínculos a ambos lados. Muchos programadores trabajan "defensivamente". y usted jamás debe olvidarse de hacerlo. event. Esto será más fácil de entender una vez que veamos cómo se crea el vínculo bidireccional entre las dos entidades.getParticipants().getParticipants().esto les permite a las clases en el mismo paquete.getEvents(). Primero.html ambos lados en Java. } Fíjese en que los métodos "get" y "et" de la colección ahora son "protected" . Usted debería. si queremos que este vínculo funcione también en sentido inverso.3. } public void removeFromEvent(Event event) { this. los datos pueden ser adquiridos de cualquier manera posible. y a las subclases. Trabajar con vínculos bidireccionales Primero que nada.hbm. obviamente. Desde luego. private Set participants = new HashSet(). en la clase Person: protected Set getEvents() { return events. mapee también este lado de la asociación. ¿Cómo habiamos creado un vínculo entre personas y eventos en el ejemplo unidireccional? Agregando una instancia de Event a la colección de referencias contenida en una instancia de Person. Marcar uno de los lados de la asociación como inverse. probablemente. no necesita cosas como una "dirección de navegación". } public void addToEvent(Event event) { this. public Set getParticipants() { return participants.org/documentacion_es/castellano.remove(event). Esto de "establecer el vínculo de los dos lados" es absolutamente necesario. es que Hibernate debería rferirse al otro lado (el lado "Person").xml.hibernar. básicamente le dice a Hibernate que lo ignore.remove(this). } public void setParticipants(Set participants) { this. tenga en cuenta que Hibernate no afecta la semántica normal de Java. casi). 1..m.events = events. Lo que esto significa. } Ahora. Y ¿qué hay del atributo de mapeo inverse? Para usted (y para Java). Por ejemplo. hacer lo mismo con las colecciones del otro lado.Persistencia Relacional para Java Idiomático http://www. el esquema de base de datos no cambia.getEvents(). todavía tenemos una multiplicidad de-muchosa-muchos (many-to-many). . tenemos que hacer lo mismo del otro lado: agregar una referencia a Person a la colección en Event. un vínculo bidrecciolal es simplemente cuestión de asignar correctamente las referencias en ambos lados .Person"/> </set> Como puede ver. éstos son mapeos set normales en ambos documentos de mapeo.Hibernate.add(event). <set name="participants" table="PERSON_EVENT" inverse="true"> <key column="EVENT_ID"/> <many-to-many column="PERSON_ID" class="events. agregue una colección de participantes al código de la clase Event. La adición más importante es el atributo inverse="true" en el elemento set del mapeo de la colección de Event. no tiene información suficiente como para organizar adecuadamente sus llamados a comandos SQL INSERT y UPDATE. } protected void setEvents(Set events) { this. acceder a los métodos. sin embargo.participants = participants.6.add(this). event. Una base de datos relacional es más flexible que un lenguaje de programación. Así que. cuando necesite obtener información sobre el vínculo entre los dos.HIBERNATE . pero les impide a todos los demás inmiscuirse con estas colecciones directamente (bueno.

la "unidad de trabajo" finaliza.html lado.getTransaction().getTransaction(). try { // comienzo nuestra unidad de trabajo HibernateUtil.getCurrentSession().org/documentacion_es/castellano. En una asociación de-muchos-a-muchos (many to many). en el paquete events: package events. En una asociación de-uno-a-muchos (one-to-many) tiene que ser el lado "many". lo mismo que la aplicacióm autosuficiente que vimos anteriormente.MM. // procesamiento de la solicitud (request) y presentación de la página. Use una sesión de Hibernate a lo largo de toda la request. no importa si para lectura o escritura.getSessionFactory(). IOException { SimpleDateFormat dateFormatter = new SimpleDateFormat("dd. HttpServletResponse response) throws ServletException.yyyy").commit(). así que el método que implementamos es doGet(): protected void doGet(HttpServletRequest request. (una sesión por cada "solicitud" o request HTTP).m.hibernar. Las reglas que usted denbe recordar son son simples: Toda asociación bidireccional necesita que uno de sus lados sea "inverse". se abre una nueva sesión de Hibernate mediante el primer llamado a getCurrentSession() de la SessionFactory. es conveniente usar algunos patrones de programación ("patterns").getSessionFactory(). Nunca cree una nueva sesión de Hibernate para cada operación de base de datos. throw new ServletException(ex). y es generada la respuesta HTML.La aplicación de web "EventManager" Convirtamos la siguiente discusión en una pequeña aplicación de web. Use getCurrentSession(). Finalmente. Escribir el servlet básico Cree una nueva clase en su directorio de código fuente. Parte 3 .. Escribamos un servlet EventManagerServlet que pueda listar los eventos alamacenados en la base de datos. Eso es todo lo que se necesita para que Hibernate resuelva todos los problemas que derivan de transformar un modelo de navegación bidireccional en un esquema de base de datos.getCurrentSession().HIBERNATE . de manera que quede automáticamente ligada al Thread actual.rollback(). que tenga un "alcance" de toda la sesión. 1. Una aplicación de web Hibernate utiliza sesiones y transacciones. Entonces. // Imports public class EventManagerServlet extends HttpServlet { // Servlet code } Este servlet maneja requests HTTP del tipo GET solamente. } } El "pattern" o patrón de programacíón que estamos aplicando aquí se llama session-per-request. cuando el procesamiento y presentación hayan sido completados. Enseguida nos dedicaremos a esa parte. } catch (Exception ex) { HibernateUtil. elija cualquier lado. 1. Si ocurrió algún problema durante este procesamiento o presentación. A continuación.Persistencia Relacional para Java Idiomático http://www..1. // fin de la unidad de trabajo HibernateUtil. en las aplicaciones no usamos auto-commit). ss inicia una transacción de base de datos (todo el código de acceso a datos ocurre dentro de la transacción. da lo mismo. se lanzará una excepción y la se ejecutará un "rollback" de la 21 de 198 17/02/2009 09:25 a.beginTransaction(). las acciones posibles de la request son procesadas. y provea un formulario HTML para ingresar nuevos eventos.4.4. Cuando una nueva request apela al servlet.getSessionFactory(). es decir. .getCurrentSession(). Sin embargo.

listEvents(out. String eventDate = request. out. 1.class) if (result.println("</body></html>"). .getWriter(). out. out.getParameter("eventTitle"). out.</i></b>"). } 22 de 198 17/02/2009 09:25 a.createCriteria(Event. // escribe el header encabezado HTML PrintWriter out = response.getCurrentSession(). out.close(). out. El primer método es trivial.getDate()) + "</td>").2.org/documentacion_es/castellano. mezclando Java y HTML.println("<td>" + dateFormatter.println("<td>" + event. y sólo produce HTML: private void printEventForm(PrintWriter out) { out.equals(eventTitle) || "".equals(eventDate) ) { out. En lugar de escribir código para demarcar la transacción en cada request. for (Iterator it = result. out.format(event. // maneja las acciones if ( "store". tenga en cuenta que sólo estamos ilustrando conceptos básicos de Hibernate en este instructivo. Este patrón se necesitará en cuanto usted considere presentar sus "vistas" usando JSP en lugar de servlets.equals(request. } out. este tipo de escritura de código.getTitle() + "</td>").println("<tr>").Persistencia Relacional para Java Idiomático http://www.hasNext().parse(eventDate)). out. usted debería crea un Servlet Filter. Dentro de la página propiamente dicha.getParameter("eventDate"). // escribe el pie HTML out. Procesamiento y presentación Implementemos el procesamiento de la solicitud y la presentación de la página. } else { createAndStoreEvent(eventTitle.</i></b>"). out.println("<h2>Events in database:</h2>"). out. SimpleDateFormat dateFormatter) { List result = HibernateUtil.m.println("<th>Event title</th>"). se imprime un formulario (form) para el ingreso de eventos. it.println("<form>").println("<b><i>Please enter event title and date.HIBERNATE . El código imprime un encabezado y un pie de página en HTML.println("Title: <input name='eventTitle' length='50'/><br/>"). } El método listEvents() usa la sesión de Hibernate ligada al Thread actual para ejecutar una consulta: private void listEvents(PrintWriter out. out. if ( "".next().) { Event event = (Event) it.println("</table>"). out.println("</tr>").flush(). Concedido.println("</tr>").getParameter("action")) ) { String eventTitle = request.println("<b><i>Added event. dateFormatter).iterator(). out.4. algo así como "apertura de una sesión por cada vista". out.println("<html><head><title>Event Manager</title></head><body>"). 24.println("<input type='submit' name='action' value='store'/>").println("<table border='1'>").println("<th>Event date</th>").println("</form>").hibernar.println("<tr>"). out.getSessionFactory(). llamado Open Session in View u OSIV.12. Esto cubre el "pattern" session-per-request. dateFormatter. sería inadmisible en aplicaciones más complejas. out.size() > 0) { out. out.2009): <input name='eventDate' length='10'/><br/>").println("Date (e.html transacción. } } // imprime la página printEventForm(out).g. out. Refiérase al sitio de web de Hibernate y a la Wiki para más información acerca de este "pattern".println("<h2>Add new event:</h2>").

descárguelo y siga las instrucciones.w3. Tal como ocurrió en el ejemplo anterior.jar.sun.html } Finalmente.sun. . tiene que crear un archivo ".m. y movería el código de acceso a datos (DAO.war en su directorio de proyecto. Es el kit de herramientas o "developer kit" para los servlets de Java. Date theDate) { Event theEvent = new Event(). Normalmente.getCurrentSession(). Asegúrese 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 estático en HibernateUtil).HIBERNATE . 23 de 198 17/02/2009 09:25 a.4" xmlns="http://java. Una vez desplegada y con Tomcat andando. el cual usa la sesión del Thread actual. note que se necesita una biblioteca adicional : jsdk. accceda a la aplicación en http://localhost:8080/hibernate-tutorial /eventmanager. invoque el comando ant war situado en el directorio de su proyecto. se la usa para compilar solamente. como ésta es una aplicación de web. HibernateUtil.setDate(theDate).war" webxml="web.Persistencia Relacional para Java Idiomático http://www.4. y también asegúrese de obtener una mensaje detallado si ocurre algún error. } Eso es todo. theEvent.xml:. el cual se espera que esté en el directorio base de su proyecto.getSessionFactory().sun.xml. El servlet está completo. Una request al servlet será procesada en una única sesión y transacción. Empaqueta todas las bibliotecas y el descriptor web. 1.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. Si aún no tiene esta biblioteca.0" encoding="UTF-8"?> <web-app version="2. De todos modos. <target name="war" depends="compile"> <war destfile="hibernate-tutorial.war".com/xml/ns/j2ee" xmlns:xsi="http://www.save(theEvent).org/documentacion_es/castellano. y luego copie el archivo hibernate-tutorial. <?xml version="1.hibernar.com/xml/ns/j2ee http://java.org/2001/XMLSchema-instance" xsi:schemaLocation="http://java.3. Agregue la siguiente target de Ant a su archivo build. Despliegue (deploy) y test Para desplegar (deploy) esta aplicación. descárguela del sitio de web de Sun y colóquela en su directorio de bibliotecas (lib).com/xml/ns/j2ee/web-app_2_4 <servlet> <servlet-name>Event Manager</servlet-name> <servlet-class>events. Para construir (build) y desplegar (deploy). No es necesario que cambie nada en la configuración de Tomcat para que este ejemplo ande.jar"/> </lib> <classes dir="${targetdir}"/> </war> </target> Esta target crea un archivo llamado hibernate-tutorial.war en el directorio webapp de Tomcat. la acción store es despachada al método createAndStoreEvent(). Refiérase a la Wiki de Hibernate para más ejemplos. usted usaría un diseño más sofisticado. por sus siglas en inglés) a otra "capa". no se incluye en los paquetes WAR. theEvent.setTitle(title). Esto le da a usted la libertad de acceder a la SessionFactory de cualquier manera que guste.xml"> <lib dir="${librarydir}"> <exclude name="jsdk*. protected void createAndStoreEvent(String title. Si no tiene Tomcat instalado. Hibernate puede ligar estos objetos al Thread actual de ejecución.

4. Esta arquitectura usa un subconjunto mínimo de las APIs de Hibernate. No olvide chequear el sitio de web de Hibernate en busca de más instructivos especializados. Si ya va tomando confianza con Hibernate. . Generalidades Una vista a vuelo de pájaro de la arquitectura de Hibernate Este diagrama muestra a Hibernate usando datos de configuración y base de datos para proveerle servicios de persistencia (y objetos persistentes) a la aplicación. Nos gustaría mostrar una vista más detallada de la arquitectura en tiempo de ejecución. Sumario Este instructivo cubrió lo básico para escribir una simple aplicación Hibernate autosuficiente. el uso de las API (interfaces de programación) (Capítulo 10. Vamos a mostrar los dos extremos: la arquitectura "liviana" fuerza a la aplicación a proveer sus propias conexiones JDBC y a gerenciar sus propias tranascciones. y una pequeña aplicación de Web.5. Trabajar con objetos) y las características de las consultas (Sección 10.HIBERNATE . continúe hojeando la tabla de contenidos en la documentación de referencia. Lamentablemente. Capítulo 2. “Consultar”). la performance de las capturas de datos o "fetch performance" (Capítulo 19. buscando temas que le interesen. Transacciones y Concurrencia). Hibernate es tan flexible.html 1.Persistencia Relacional para Java Idiomático http://www.org/documentacion_es/castellano.hibernar. Mejorar la performance).m. 24 de 198 17/02/2009 09:25 a.1. Los más solicitados son el procesamiento de transacciones (Capítulo 11. Arquitectura 2. que soporta muchas estrategias.

que se usa al navegar el árbol de objetos.HIBERNATE .hibernate. Session (org.html La arquitectura "con todas las luces" abstrae la aplicación.hibernate. y cliente de ConnectionProvider. y deja que Hibernate se encargue de los detalles. serán desprendidos. desde y hacia la capa de presentación). Objetos y colecciones persistentes Objetos de un solo thread y corta vida. que representa una conversación entre la aplicación y el repositorio persistente. a nivel de proceso o de cluster. .hibernar.Persistencia Relacional para Java Idiomático http://www. y quedarán listos para ser usados en cualquier capa de la aplicación (por ejemplo.org/documentacion_es/castellano. He aquí algunas definiciones de los objetos en los diagramas: SessionFactory (org.m. alejándola de las capas subyacentes de JDBC/JTA. Puede contener un caché optativo (llamado "de 2do nivel") que es reusable entre transacciones. o puros y simples objetos de Java (POJOs por sus siglas en inglés).SessionFactory) Un caché thread-safe e inmutable de mapeos. 25 de 198 17/02/2009 09:25 a. es que están asociados con una sesión. compilados para una base de datos en particular. Una fábrica (factory) de sesiones. o cuando se buscan los objetos por identificador. Pueden ser JavaBeans comunes. En cuanto la sesión se cierra. Contiene un caché obligatorio (llamado "de primer nivel") de objetos persistentes. Envuelve a una fábrica de conexiones JDBC por transacción. directamente como objetos de transmisión de datos o "DTOs". que contienen "estado" persistente y cumplen una función de negocio. la única característica notable que tienen.Session) Un objeto de thread simple y de corta visa.

Hibernate puede ser administrado via un servicio JMX estándar. los cuales se definen con respecto a un contexto de persistencia: la sesión. JTA o CORBA subyacente. No está expuesto directamente a la aplicación. Hibernate garantiza que la identidad persistente equivale a la "identidad Java" (ubicación en memoria del objeto).hibernate. pero puede ser implementada o extendida por el programador.Transaction) (Optativo) un objeto de un solo thread y corta vida. Tiene una identidad persistente y. Abstrae a la aplicación de la transacción JDBC. Pudieron haber sido instanciadas por la aplicacíón. pero puede ser implementado o extendido por el programador.HibernateService. por el momento.hibernate. un valor correspondiente en la base de datos. Integración con JMX JMX es el estándar de J2EE para la administración de componentes Java. no están asociadas con una sesión.html Objetos y colecciones transitorios y desprendidos Instancias de clases persistenteses que.jmx.org/documentacion_es/castellano. Hibernate no ofrece ninguna garantía acerca de la relación entre identida persistente e identidad Java. TransactionFactory (org. Interfaces de extensión Hibernate ofrece varias interfaces de extensión optativoes. tal vez.m. la aplicación se saltea las APIs de Transaction/TransactionFactory y/o ConnectionProvider APIs para dialogar con JTA o JDBC directamente.2.hibernate. el correspondiente registro en la base de datos. se pueden implementar para personalizar el comportamiento de la capa de persistencia. también se obtienen los siguientes beneficios si se 26 de 198 17/02/2009 09:25 a. desprendida (detached) La instancia estuvo alguna vez asociada con un contexto de persistencia. Abstrae la aplicación de la fuente de datos (Datasource) o del gerente de driver (DriverManager) subyacentes.hibernate. 2. sea como sea. o bien haber sido instanciadas por una sesión que en ese momento esté cerrada. Nosotros proveemos una implementación de MBean en la distribución: org. es decir. Para un ejemplo sobre cómo desplegar Hibernate como un servicio JMX en el servidor de aplicaciones JBoss. Estados de una instancia Una instancia de una clase persistente puede estar en uno de tres estados diferentes. pero dicho contexto está cerrado. o la instancia ha sido serializada a otro proceso. Una sesíón puede extenderse a lo largo de varias transacciones en algunos casos. persistente (persistent) La instancia está al momento asociada con un contexto de persistencia. 2. Tiene identidad persistente (valor de clave primaria) y. ni nunca lo ha estado.HIBERNATE . .3. de clave primaria.TransactionFactory) (Optativo) Una fábrica de instancias de Transaction. Transacción (org. usado por la aplicacíon para especificar unidades atómicas de trabajo. por favor vea la guía del usuario de JBoss.Persistencia Relacional para Java Idiomático http://www. ¡Pero. el código para demarcar transacciones (ya sea utilizando APIs subyancentes o la interfaz Transaction) nunca es optativo! ConnectionProvider (org. Para un contexto de persistencia determinado. transitorio (transient) La instancia no está asociada con ningún "contexto de persistencia" (sesión).hibernar. En el servidor de applicaciones JBoss. y aún no haber sido asociadas con una sesión. tal vez. Vea la documentación de la API para más detalles.ConnectionProvider) (Optativo) Una fábrica y repositorio (pool) de conexiones JDBC. En la arquitectura "liviana". No está expuesta directamente a la aplicación.connection. Carece de "identidad persistente".

este método asumía el uso de transacciones JTA.ManagedSessionContext .las sesiones actuales son localizadas y su alcance definido por una transacción JTA.0. en un archivo EAR o SAR.org/documentacion_es/castellano. la mayoría (si no todas) las aplicaciones deberían estar usando JTA para su manejo de transacciones (estén o no desplegadas en un contenedor J2EE).1. pero note que el soporte Hibernate de JCA se considera todavía experimental.context.hibernate. org.ThreadLocalSessionContext . cierra o le aplica flush a una sesión. Empezando con la versión 3. “Estadísticas de Hibernate” 2.context.HIBERNATE . usted es responsable por ligar y desligar las instancias de sesión.current_session_context_class) han sido agregados. Por favor. si decide usar el despliegue HAR. Soporte de JCA Hibernate también puede ser configurado como un conector JCA.las sesiones actuales son localizadas por thread de ejecución. para esto aún se debe nombrar a todos los archivos de mapeo en el descriptor de despliegue.CurrentSessionContext) y un nuevo parámetro de configuración (hibernate. vea los Javadocs para más detalles. el cual soporta las opciones de configuración de una SessionFactory de Hibernate. Las aplicaciones que usaban Hibernate antes de la versión a 3.5. org.las sesiones actuales son localizadas por thread de ejecución.4.getCurrentSession().CurrentSessionContext. donde una sesión determinada esté en efecto a lo largo del "scope" o alacance de un contexto determinado. El procesamiento aquí es exactamente el mismo que en el antiguo enfoque sólo-JTA. . Hibernate incorporó el método SessionFactory.hibernar.0. En cambio. dada la madurez de las numerosas implementaciones autosuficientes de JTA que existen hoy día. org. donde la transacción JTA definía tando el alcance como el contexto de la sesión actual. vea el sitio de web para más detalles. Hibernate ya viene con 3 implementaciones incuidas de esta interfaz. Vea los Javadocs acerca de la interfaz org. currentSession(). entre las distintas aplicaciones.Persistencia Relacional para Java Idiomático http://www. una nueva interfaz de extensión (org.hibernate. por el cual la implementación es responsable de rastrear la sesión contextual actual. use la API Transaction de Hibernate para eso). De nuevo.context. JBoss detecta automáticamente todos los archivos de mapeo en su archivo HAR. Sin embargo.4.getCurrentSession() es configurable. a partir de la versión 3. Nunca abre. Esto significa que usted ya no necesita abrir y cerrar manualmente las sesiones. 2. mediante métodos estáticos en esta clase. el proceso que ocurre por detrás de SessionFactory. Sin embargo.6. Inicialmente. Despliegue del Archivo de Hibernate (HAR por sus siglas en inglés): Normalmente se despliega el servicio JMX de Hibernate usando el "descriptor de despliegue" (deployment descriptor). Vea la Sección 3. así como la definición de qué constituye el contexto "actual".una transacción de base de 27 de 198 17/02/2009 09:25 a. Otra característica disponible en forma de servicio JMX son las estadísticas de Hibernate en tiempo de ejecución.m. Sesiones contextuales La mayoría de las aplicaciones que usan Hibernate necesitan alguna forma de sesión "contextual".hibernate. las sesiones contextuales JTA son todo lo que usted debería necesitar usar. la definición de lo que constituye un "contexto" suele diferir.hibernate. De todos modos. Consulte la guía del usuario del servidor de aplicaciones JBoss para mayor información acerca de estas opciones.context. Puede llamar a HibernateContext para acceder a una sesión. de esto se encarga el interceptor de JBoss. Define un solo método.context. El equipo de Hibernate mantiene que. De todos modos.hibernate. Las dos primeras implementaciones proveen un modelo de programación del tipo "una sesión . Tampoco debe preocuparse ya por demarcar la transacción en su código (a menos que quiera escribir usted mismo una capa de persistencia portátil. Basándose en eso. los cuales proveían sesiones contextuales basadas en proxies e intercepción. para permitir "enchufar" implementaciones nuevas para definir el alcance y contexto de las sesiones.html despliega (deploy) usando JMX: Manejo de sesiones: El ciclo de vida de una sesión de Hibernate puede ser automáticamente ligado al alcance (scope) de una transacción JTA.1. Vea los Javadocs para más detalles. para una descripción detallada del contrato que ésta implica.JTASessionContext . tendían a utilizar o bien versiones "caseras" de sesión contextual (basadas en ThreadLocal) o bien utilizaban frameworks de terceras partes (como Spring o Pico). Con este fin.

por compatibilidad con versiones anteriores.hibernate. Si el código se está ejecutando en un contenedor EJB que soporte CMT. Colocar un archivo llamado hibernate.connection.hibernate.properties en un directorio raíz del classpath.datasource".TransactionManagerLookup en su lugar. Refiérase al Capítulo 11.addClass(org.context.xml y /org/hibernate enfoque elimina la necesidad de "hardcodear" los nombres de archivo. Este Entonces Hibernate buscará archivos de mapeo llamados /org/hibernate/auction/Item.html datos".auction.1. Note que. "thread" y "managed". se le aconseja que use la API de Transaction de Hibernate. 3. si este parámetro de configuración no se asigna. la mayoría tiene valores por defecto razonables. Se puede ontener una instancia de org.hbm.hbm.setProperty("hibernate. Hibernate usará el org. que muestra varias de las opciones. Afortunadamente. Capítulo 3.transaction.xml") . es especificar la clase mapeada.org/documentacion_es/castellano. .hbm.Properties a Configuration.class) .Item. Simplemente coloque este ejemplo en su classpath y modifíquelo a medida. sino que se configura org. y especificando los archivos de mapeo XML.setProperties().auction.xml"). Si usted usa demarcación programática de transacciones.HIBERNATE .class). "java:comp/env/jdbc/test") .class) . org.hibernate.hibernate.setProperty("hibernate. Transacciones y Concurrencia para más información y ejemplos de código. El comienzo y fin de una sesión de Hibernate está definido por la duración de la transacción de base de datos.hibernate.setProperty("hibernate. El parámetro de configuración hibernate.addClass(org.Configuration instanciándola directamente.addClass(org. e Hibernate es distribuido con un archivo hibernate.class) . los límites de la transacción son definidos declarativamente.properties de ejemplo en el directorio etc/. para ocultar el sistema de transacciones subyacente.dialect.hibernate. y usted no necesita ninguna transacción ni demarcación de operaciones en el código propiamente dicho.hibernate. para las tres implementaciones de fábrica existen los respectivos nombres cortos: "jta".addResource("Item.auction. Ésta no es la única manera de pasarle propiedades de configuración a Hibernate.Item.hibernate.Bid. también llamado session-per-request. utilice addResource(): Configuration cfg = new Configuration() .xml en el calsspath. Configurar propiedades "de sistema" (System) usando java -Dproperty=value.order_updates". Configuración Como Hibernate está diseñado para operar en varios entornos diferentes. org. 28 de 198 17/02/2009 09:25 a. el valor de este parámetro simplemente nombra la clase de implementación a usar.context.addResource("Bid.cfg.hibernate.util. en simple JSE sin JTA.JTASessionContext.Configuration también permite especificar propiedades de configuración: Configuration cfg = new Configuration() . Los mapeos son compilados a partir de los varios archivos de mapeo XML.hibernar.auction. Una alternativa (a veces preferible). Entre las muchas otras opciones.hibernate.hbm. están éstas: Pasarle una instancia de java.MySQLInnoDBDialect") .current_session_context_class define cuál implementación de org.hibernate. "true").Configuration representa un conjunto completo de mapeos desde los tipos Java de una aplicación.CurrentSessionContext debe ser usada.cfg.Persistencia Relacional para Java Idiomático http://www. Típicamente.cfg.m.cfg. hacia una base de datos SQL.addClass(org. y dejar que Hibernate encuentre el documento de mapeo él solo: Configuration cfg = new Configuration() .SessionFactory inmutable. Configuración programática Una instancia de org. "org. Si los archivos de mapeo están en el classpath.Bid. /auction/Bid. hay un gran número de parámetros de configuración.hibernate.dialect".Configuration se usa para construir una org.hibernate.

properties para C3P0: hibernate. usted querrá que la org. Esto desactivará el "pooling" interno de Hibernate.HIBERNATE . Hibernate obtendrá las conexiones (y las administrará en un "pool") usando un java.Session.*.c3p0. Para que esto funcione. Si se adopta este enfoque. si lo que se busca es empezar rápido.connection.DriverManager si usted configura las siguientes propiedades: Table 3.connection. una nueva conexión JDBC será obtenida del "pool". bastante rudimentario. SessionFactory sessions = cfg.html Incluir elementos <property> en hibernate.hibernate. refiérase a las propiedades empaquetadas en hibernate.hibernate.Session es tan simple como escribir: Session session = sessions. Esto es útil si se está usando más de una base de datos. Vamos a describir los valores más importantes para configurar la conexión JDBC.hibernar. la aplicación debe obtener una fábrica o "SessionFactory" para las instancias de org.connection.cfg. 3. Hibernate sí le permite a la aplicación instanciar más de una org.connection.hibernate. Ustde debería usar un "pool" de algún tercero para asegurar mayor redimiento y estabilidad. Obtener una SessionFactory Una vez que todos los mapeos hayan sido revisados por org.cfg.username hibernate. o al sitio de web de Hibernate para mayor información.properties. para ser descartado luego.Persistencia Relacional para Java Idiomático http://www.1.m.pool_size URL de JDBC usuario de la base de datos clave del usuario de la base de datos número máximo de conexiones en el "pool" El algoritmo que ya viene incluido en Hibernate para el "pooling" de conexiones es.connection.hibernate.connection.buildSessionFactory(). Conexiones JDBC Usualmente.sql. Fue concebido más que nada para ayudarlo a dar los primeros pasos. si usted les asigna valores a las propiedades que empiezan con hibernate. Por ejemplo.url hibernate. hibernate.cfg.pool_size con propiedades específicas de la herramienta de "pooling" de su elección. He aquí un ejemplo de un hibernate. ni siquiera para un test de performance. abrir una org. Si prefiere usar Proxool. Todos los nombres y semántica de las propiedades Hibernate están definidos en la clase org.postgresql.org/documentacion_es/castellano. sin embargo.SessionFactory cree y administre el "fondo común" (pool) de sesiones por usted. necesitamos pasarle algunas propiedades de conexión JDBC a Hibernate. Hibernate JDBC Properties Nombre de la propiedad Propósito hibernate.Configuration es ser un objeto que viva durante el "tiempo de arranque" (startup).C3P0ConnectionProvider 29 de 198 17/02/2009 09:25 a. La idea de org. // abre una nueva sesión No bien se haga algo que requiera acceso a la base de datos. .password hibernate.connection. Hibernate usará su para efectuar el "pooling" de conexiones.driver_class = org. Esta fábrica será compartida por todos los threads que accedan a la aplicacíón.Configuration.SessionFactory.hibernate.hibernate.3.Environment.hibernate.driver_class clase del driver JDBC hibernate.xml (se discute más adelante). una vez que la SessionFactory haya sido creada.cfg.openSession(). usted podría elegir C3P0. C3P0 es una biblioteca para pool de conexiones distribuida junto con Hibernate en el direactorio lib. 3.2. Simplemente reemplace la propiedad hibernate.Driver org. no para ser usado en un sistema de producción.hibernate.properties es el enfoque más fácil.connection.

class hibernate.PostgreSQLDialect Para usar "pooling" dentro de un servidor de aplicaciones.charSet".dialect.password = secret hibernate.properties.PostgreSQLDialect Las conexiones JDBC que se obtengan de una fuente de datos JNDI participarán automáticamente de las transacciones "manejadas por el contenedor" del servidor de aplicaciones.hibernar. y tienen valores por defecto razonables.Persistencia Relacional para Java Idiomático http://www.url hibernate. afijando "hibernate.JBossTransactionManagerLooku hibernate. 30 de 198 17/02/2009 09:25 a.html hibernate. Propiedades para fuente de datos de Hibernate Nombre de la propiedad Propósito hibernate. Por ejemplo.c3p0. a Statement.connection.c3p0.hibernate. No se les puede asignar valores usando las técnicas descritas anteriormente.fetch_size por ejemplo classname.3.manager_lookup_class = org.connection.JTATransactionFactory hibernate.dialecto Propósito En laUn valor distintocasos.c3p0.jdbc. Advertencia: algunas de estas propiedades existen "a nivel de sistema" solamente.Dialect que le permita a Hibernate generar SQL optimizado para una BD relacional en particular.dialect = org.connection.properties para configurar la fuente de datos JNDI en un servidor de aplicaciones: hibernate.provider_class. Se necesitarán por lo menos las siguientes propiedades: Table 3.username = myuser hibernate.connection" al nombre de la propiedad de conexión. usando "hibernate. A las propiedades a nivel de sistema sólo se les puede asignar valores via java -Dproperty=value o hibernate.transaction.transaction.dialect.4.connection.4.connection.hibernate.min_size=5 hibernate.setFetchSize()).datasource = java:/comp/env/jdbc/test hibernate. 3.dialect = org.connection. se debería configurar Hibernate de manera tal. implementando la interfaz org.connection.max_size=20 hibernate.org/documentacion_es/castellano.hibernate. . Tabla 3.del.connection.timeout=1800 hibernate.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.sql. y especificando su propia implementación a medida en la propiedad hibernate. Propiedades optativas de configuración Hay varias otras propiedades que controlan el comportamiento de Hibernate en tiempo de ejecución.determina el tamaño de laelegir la implementación de mayoría de los de 0 Hibernate será capaz de captura o "fetch" JDBC (llama dialecto correcta. Usted también puede definir su propia estrategia de plugin para obtener conexiones JDBC. Propiedades Hibernate de JDBC y Conexión hibernate.completo.m.url = jdbc:postgresql://localhost/mydatabase hibernate.factory_class = org.dialect.transaction.connection.hibernate.connection.max_statements=50 hibernate.username hibernate. usted puede especificar una propiedad de conexión charSet (juego de caracteres).dialectde la propiedad Nombre hibernate.HIBERNATE . que siempre obtenga las conexiones desde una fuente de datos javax.jndi. También se pueden agregar propiedades de conexión arbitrarias.Datasource registrada usando JNDI.2. basándose en los metadatos devueltos por el driver JDBC. Porpiedades de Configuration de Hibernate Nombre de la propiedad Propósito El nombre de clase de un org.datasource nombre JNDI de la fuente de datos hibernate.transaction.c3p0.jndi. Todas son optativas.hibernate.hibernate. Tabla 3.ConnectionProvider.

Por hibernate.autocommit valors posibles true | false 31 de 198 17/02/2009 09:25 a.ConnectionProvider Determina el nivel de aislamiento de las transacciones JDBC. Requiere que a Requires JDBC3+ driver y a JRE1. El valor por defecto es false. *propiedad a nivel de sistema* hibernate. hibernate.jdbc.batch_versioned_data hibernate. Entonces.ConnectionProvider hibernate.jdbc. 2.jdbc. Hibernate usará "batched DML" (lenguaje de creación de datos en lotes) para datos a los que se les haya asignado automátiacmente número de versión.Batcher hecho a medida. De otro modo.m.use_scrollable_resultset hecho a medida que le hibernate.hibernar.jdbc. .factory_class por ejemplo classname.connection.use_get_generated_keys defecto. por ejemplo 1. Hibernate usa los metadatos de la conexión. Esta propiedad sólo es necesaria cuando se emplean conexiones JDBC provistas por el usuario.hibernate. valores posibles true|false El nombre de clase de un org.of. le sea asignado "false" si el driver que usted está usando tiene problemas con los generadores de identificadores.Connection para averiguar qué valores tiene sentido asignar aquí.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. Revise java. y algunas definen niveles no estándar adicionales.org/documentacion_es/castellano. 4. hibernate.BatcherFactory Habilita el uso de resultados JDBC2 navegables (scrollable resultsets) por parte de Hibernate.connection.Persistencia Relacional para Java Idiomático http://www.jdbc. 8 Habilita la autocomisión (autocommit) para las conexiones JDBC en pool (no se recomienda). por ejemplo classname.4+. valores posibles true | false Indica que se usarán streams al leer o escribir código binario. La mayoría de las aplicaciones no necesita configurar esta propiedad.html Nombre de la propiedad Propósito Un valor distinto de 0 habilita el uso de actualizacionesn en lotes (batch updates) de JDBC2 por parte de Hibernate.batch_size valores posibles se recomienda entre 5 y 30 Asígnele true a esta propiedad.sql. intenta determinar las capacidades del driver usando los metadatos de conexión.jdbc. si su driver JDBC devuelve conteos de fila al ejecutar executeBatch() (normalmente.provider_class provea conexiones JDBC a Hibernate.connection.jdbc. o tipos serializables desde o hacia JDBC. pero note que la mayoría de las BD no soportan todos los niveles de aislamiento (isloation levels).connection.of. valores posibles true | false Selecciona un org. es seguro hacerlo).HIBERNATE . hibernate.isolation hibernate.hibernate.

of. se debería usar after_statement para liberar conexiones agresivamente luego de cada llamado a JDBC. y after_transaction para las estrategias transaccionales JDBC.provider_class Propósito El nombre de clase de un CacheProvider hecha a medida. hibernate. usando after_transaction.Persistencia Relacional para Java Idiomático http://www.m.openSession.cache. Para las que se hayan obtenido usando SessionFactory.5.jndi. valores posibles true|false Habilita el caché de consultas.org/documentacion_es/castellano. Cada consulta (query) debe ser individualmente configurada como "cacheable".getCurrentSession. el cual está habilitado por defecto para toda clase que especifique un hibernate.getConnection(). hibernate. a menudo tiene sentido liberar las conexiones al final de cada transacción.use_second_level_cache mapeo <cache> valores posibles true|false El nombre de una interfaz QueryCache personalizada. auto elegirá after_statement para las estrategias JTA y CMT (manejadas por el contenedor). “Sesiones Contextuales” hibernate. y en Hibernate3 se habilita por defecto con cachés en cluster. lo que importa para determinar el modo de liberación de conexiones. que por defecto es StandardQueryCache.cache. por ejemplo classname. Propiedades del caché de Hibernate Nombre de la propiedad hibernate. Vea la Sección 2.use_query_cache valores posibles true|false Puede ser usado para inhabilitar completamente el caché de 2do nivel.cache.5. Para conexiones que no sean JTA.connection.connection. .html Nombre de la propiedad Propósito Especifica cuándo Hibernate debería liberar conexiones. una conexión JDBC es retenida hasta que la sesión es cerrada explícitamente o desconectada. la cual ya viene de fábrica.query_cache_factory por ejemplo classname.cache. hibernate. <nombreDeLaPropiedad> hibernate. Tabla 3.QueryCache 32 de 198 17/02/2009 09:25 a. Por defecto.cache.of.hibernar. <nombreDeLaPropiedad> Le pasa el valor de propiedad JDBC <propertyName> a DriverManager.use_minimal_puts hibernate.release_mode valores posibles auto (el valor por defecto) | on_close | after_transaction | after_statement Note que este valor sólo afecta sesiones devueltas por SessionFactory. al costo de realizar lecturas más frecuentemente. es la implementación que se haya configurado de CurrentSessionContext.HIBERNATE .CacheProvider Optimiza el caché de 2do nivel para minimizar escrituras. Le pasa la propiedad <nombreDeLaPropiedad> a la InitialContextFactory de JNDI. Esta configuración es más útil con cachés en "cluster". Para fuentes de datos JTA en un servidor de aplicaciones.

de la subclase de valores posibles jta | thread | managed | la clase org.transaction. por ejemplo prefix Fuerza a Hibernate a almacenar datos en el caché de 2do nivel en un formato más legible. hibernate.TransactionManagerLookup Si está habilitado. y el manejo automático de contexto de sesiones. JDBCTransactionFactory).7.transaction.manager_lookup_class hibernate. valores posibles true | false Si está habilitado. Es preferible usar el manejo de transacciones que ya viene hibernate.auto_close_session Tabla 3.use_structured_entries valores posibles true|false Tabla 3.region_prefix Propósito Un prefijo a usar con los nombres de región de caché de 2do nivel. Es preferible usar el manejo de transacciones que ya viene incorporado. Propiedades Misceláneas Nombre de la propiedad Propósito Provee una estrategia personalizada para determinar el alcance (scope) respecto de cuál es la sesión "actual". ahorrándole el esfuerzo de especificarlas 33 de 198 17/02/2009 09:25 a.of. Hibernate usará valores por personalizada defecto adecuados para otras de las propiedades listadas anteriormente.HIBERNATE . Véase la Sección 2.dialect al valor correcto. por ejemplo jndi/composite/name El nombre de clase de un TransactionManagerLookup.5.1.5.flush_before_completion incorporado. por ejemplo classname.hibernar.4. . valores posibles true | false jta. Obligatorio cuando se utiliza caché a nivel de la JVM. Si se especifica un dialecto.factory_class por ejemplo classname.Dialect que corresponda a su BD.cache. ver la Sección 2.5. a la sesión le será automátiamente hecho un "flush" antes de la fase de compleción de la transacción.transaction.of.m. “Sesiones contextuales”.dialect. Dialectos de SQL hibernate.transaction.UserTransaction hibernate. y el manejo automático de contexto de sesiones. Propiedades para la configuración de transaciones en Hibernate Nombre de la propiedad Propósito El nombre de clase de la TransactionFactory a usar con Hibernate (por defecto.org/documentacion_es/castellano.cache.TransactionFactory El nombre JNDI usado por JTATransactionFactory para obtener una UserTransaction JTA del servidor de aplicaciones.Persistencia Relacional para Java Idiomático http://www. o se usa el generador hilo en un entorno JTA. hibernate.html Nombre de la propiedad hibernate. la sesión será automáticamente cerrada durante la fase de compleción de la transacción.6. ver laSección 2.current_session_context_class opciones que ya vienen incorporadas. Siempre se debería configurar la propiedad hibernate. “Sesiones Contextuales” para más información sobre cuáles son las 3.hibernate. “Sesiones contextuales”.

dialect.dialect.SybaseAnywhereDialect org. a la propiedad de 1 o superior.dialect.DB2390Dialect org.Oracle9Dialect org.PointbaseDialect org.3.hibernate.SAPDBDialect org.dialect.FirebirdDialect 3.m.hibernate.hibernate. 34 de 198 17/02/2009 09:25 a.dialect.hibernate.use_streams_for_binary.hibernate.MySQLMyISAMDialect org.hibernate.hibernate.dialect.dialect.hibernate. de-muchos-a-uno.hibernar.IngresDialect org. de-muchos-a-muchos.InterbaseDialect org.hibernate. Tabla 3.DB2400Dialect org. con un solo comando SQL SELECT.MckoiDialect org.dialect.dialect. Ésta es una propiedad configurable a nivel de sistema solamente.Persistencia Relacional para Java Idiomático http://www.PostgreSQLDialect org.4. Si usted desea usar instancias grandes de tipos binary o serializable.hibernate.4.hibernate. Al asignar un valor Vea Sección 19.hibernate.8.hibernate.dialect.dialect. La captura por outer joins permite que todo un árbol (graph) de ojetos conectados por asociaciones de-uno-a-muchos.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. 3.SybaseDialect org.HIBERNATE . .MySQLInnoDBDialect org.hibernate. hibernate.dialect.DB2Dialect org.org/documentacion_es/castellano. y de-uno-a-uno sea capturado de una sola vez.dialect.1.hibernate.jdbc.dialect. Captura (fetch) por Outer Join Si su base de datos soporta outer joins del estilo ANSI. Streams binarios Oracle limita el tamaño de los arrays de tipo byte que pueden ser pasados desde y hacia el driver JDBC. 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 con outer joins a menudo aumentará la performance.max_fetch_depth.dialect.SQLServerDialect org. Dialectos SQL de Hibernate (hibernate.FrontbaseDialect org.ProgressDialect org.hibernate.hibernate. “Estrategias de captura (fetch)” para más información.dialect. Oracle o Sybase.InformixDialect org.dialect.HSQLDialect org.hibernate. 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".dialect.hibernate. La captura mediante outer joins puede ser inhabilitada globalmente asignándole el valor 0.dialect.hibernate.MySQLDialect org.OracleDialect org.2.dialect.hibernate.hibernate.dialect.dialect. debería habilitar hibernate.html manualmente.

log4j 1.hbm2ddl Función Loguea todo el "lenguaje de modificación de datos" (DML) de SQL a medida que éste es ejecutado. a través de SessionFactory. sin volverlo ilegible. Las propiedades con prefijo hibernate.hibernate. Por ejemplo: hibernate.hibernate.properties en su classpath. Para configurar el logueo adecuadamente.hibernate. Se ha invertido mucho trabajo en lograr que el logueo en Hibernate sea lo más detallado posible.substitutions true=1.cache org.stats para más información.m.ast. así como el archivo de jar de su preferencia (en el caso de log4j. Es una herramienta esencial para la detección y resolución de problemas.hibernate.6.hibernate.jdbc org. hibernate. Loguea toda la actividad del caché de 2do nivel Loguea toda actividad relacionada con transacciones Loguea toda adquisición de recursos JDBC Loguea todo AST de HQL y SQL durante la revisión (parsing) de las consultas org. 3. Vea la documentación de SLF4J para más detalles.substitutions.hql. bitácora) Hibernate utiliza la librería llamada "Fachada simple de logueo para Java" (Simple Logging Facade for Java o SLF4J por sus siglas en inglés). JDK 1.2. .4. Hibernate incluso puede ser configurado para exponer dichas estadísticas via JMX. Hibernate expondrá un buen número de mediciones que son útiles al ajustar (tuning) el rendimiento de un sistema en marcha.hibernar. Hibernate Log Categories Category (categoría) org.jar). Se pueden definir nuevos símbolos para las consultas de Hibernate usando hibernate. Caché de 2do nivel y caché de consultas. 3. Estadísticas de Hibernate Si se habilita hibernate. Para usar log4j también necesitará colocar un archivo log4j.5.hibernate.transaction org. SLF4J puede dirigir la salida de su actividad de logueo a varios "frameworks" de logueo: NOP.2. “El caché de 2do nivel” para más detalles. JCL o logback). Sustituciones en el lenguaje de consultas. Lea el Javadoc de las interfaces en org.4.AST 35 de 198 17/02/2009 09:25 a. Loguea todos los parámetros JDBC Loguea todos los comandos SQL de definición de datos (DDL) que hayan sido ejecutados Loguea el estado de todas las entidades (con un máximo de 20) asociadas con una sesión al momento de aplicarle "flush".pretty org.org/documentacion_es/castellano.hibernate.getStatistics().substitutions toLowercase=LOWER permitiría renombrar la propiedad LOWER (pasar a minúsculas) de SQL 3.HIBERNATE .tool. Un archivo de propiedades a modo de ejemplo viene distribuido con Hibernate en el directorio src/.html 3.type org. Logueo (logging.jar en su classpath.query. para loguear varios eventos de sistema.Persistencia Relacional para Java Idiomático http://www. Las categorías más interesantes son las siguientes: Table 3. dependiendo de la vinculación elegida. Vea Sección 19.query.cache le permiten usar un sistema de caché de 2do nivel con alcance (scope) de proceso o de cluster.9.hibernate.hibernate. necesitará slf4j-api.query.4.4. false=0 causrá que los símbolos true y false sean traducidos como valores enteros literates en el SQL que se genere.5. Le recomendamos fuertemente que se familiarice con los mensajes de log de Hibernate.4.SQL org.generate_statistics. Simple. slf4j-log4j12.

hibernate. La estrategia que Hibernate usa por defecto es bastante parca.hibernate.cfg. es especificar la configuración completa en un archivo llamado hibernate. 3. y puede ser un punto de partida útil para algunas aplicaciones.hibernate.INSTANCE) .hibernate.addFile("Item. Se espera que el archivo de configuración XML esté por defecto en la raíz de su CLASSPATH.show_sql enabled. o para procesar los nombres de tabla y columna "lógicos" dados en el archivo de mapeo. 3.xml") . .properties. o.hbm.html Category (categoría) org.sourceforge. Este archivo puede usarse en reemplazo del archivo hibernate. Se puede especificar una estrategia diferente.dialect.m. Esta característica reduce la locuacidad de los documentos de mapeo. llamando a Configuration. Usted puede proveer reglas para generar automáticamente los identificadores a partir de identificadores Java.xml.Persistencia Relacional para Java Idiomático http://www.hbm. Al desarrollar aplicaciones con Hibernate.hbm.6.xml"/> <mapping resource="org/hibernate/auction/Bid.configuración del caché --> 36 de 198 17/02/2009 09:25 a. org.MySQLDialect</property> <property name="show_sql">false</property> <property name="transaction.archivos de mapeo --> <mapping resource="org/hibernate/auction/Item. Implementar una NamingStrategy La interfaz org.setNamingStrategy() antes de agregar mapeos. habilitar la propiedad hibernate.0.cfg. Archivo de configuración XML Un enfoque alternativo de configuración.hbm. y convertirlos en nombres de tabla y columna "físicos". SessionFactory sf = new Configuration() .una instancia de SessionFactory listada como /jndi/name --> <session-factory name="java:hibernate/SessionFactory"> <!-. por ejemplo.propiedades --> <property name="connection.cfg.hibernate Función Loguea todas las autorizaciones para requests JAAS Loguea todo (un montón de información.NamingStrategy permite especificar un estándar de nombrado o "NamingStrategy" para los objetos de base de datos y elementos del esquema.dtd"> <hibernate-configuration> <!-.xml"/> <!-.hibernar.factory_class"> org. alternativamente.HIBERNATE . si ambos están presentes.xml") . para suplantar propiedades de éste. se debería trabajar casi siempre con debug habilitado para o.0' encoding='utf-8'?> <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD//EN" "http://hibernate.datasource">java:/comp/env/jdbc/MyDB</property> <property name="dialect">org.buildSessionFactory().net/hibernate-configuration-3. He aquí un ejemplo: <?xml version='1.7.hibernate. pero muy útil a para detectar y solucionar problemas).secure org.JTATransactionFactory </property> <property name="jta.UserTransaction">java:comp/UserTransaction</property> <!-.ImprovedNamingStrategy es una estrategia que ya viene de incorporada.hibernate. org.transaction.SQL.org/documentacion_es/castellano. eliminando el "ruido" provocado por la repetición de prefijos TBL_.setNamingStrategy(ImprovedNamingStrategy.addFile("Bid.

.properties es indistinto. e. El container hará arrancar su HibernateService. usted también puede demarcar los límites de sus transacciones programáticamente (BMT) o usar la API de transacciones de Hibernate (Transaction) para mantener su código portable.m. puede elegir desplegar Hibernate como un "Managed MBean" Esto le ahorra el códgo de arranque de una línea que construye la SessionFactory a partir de Configuration.cfg.xml") . provistas a través de JNDI.xml o hibernate.cfg.transaction.aggressive_release. idealmente. usted puede tener que asignar el valor "true" a la opción de configuración hibernate.hibernar. Con la configuración XML.Persistencia Relacional para Java Idiomático http://www. Configuración de una estrategia transaccional La sesión de Hibernate es independiente de cualquier sistema de demarcación de transacciones presente en la arquitectura de su sistema. usando: SessionFactory sf = new Configuration() .buildSessionFactory(). un TransactionManager compatible con JTA y un ResourceManager se hacen cargo del manejo de transacciones (CMT). Enlace JNDI automático: Hibernate puede ligar su SessionFactory a JNDI luego del arranque.factory_class.auction. también se hará cargo de las dependencias de servicios (la fuente de datos tiene que estar disponible antes de que Hibernate arranque. Despliegue JMX: Si usted cuenta con un servidor de aplicaciones habilitado para JMX. etc). 3. Por supuesto. Usualmente.buildSessionFactory(). Va a tener que especificar una clase "fábrica" de instancias de Transaction. hibernate. la cual envuelve y oculta el sistema subyacente. Enlace de sesión JTA: La sesión de Hibernate puede ser automáticamente ligada al alcance o "scope" de las transacciones JTA.org/documentacion_es/castellano. La demarcación de transacciones es o bien declarativa (CMT) o bien programática (BMT/UserTransaction). Si usted ejecuta su aplicación en un servidor de aplicaciones J2EE.xml también es más conveniente para ajustar los valores del caché. especialmente transcciones distribuidas a lo largo de varias fuentes de datos.1.8. 3. la ventaja de este enfoque es externalizar la configuración de los nombres de los acrhivos de mapeo. Si usted deja que Hibernate use JDBC directamente a través de un "pool" de conexiones. Dependiendo del entorno. Para mantener su código portable entre estos dos entornos (y otros).configure().bids" usage="read-write"/> </session-factory> </hibernate-configuration> Como se puede ver.Bid" usage="read-only"/> <collection-cache collection="org. si su servidor de aplicaciones produce excepciones de "contención de conexiones" ("connection containment" exceptions).cfg.connection. 37 de 198 17/02/2009 09:25 a. Deje que Hibernate se haga cargo de aplicarle "flush" y de cerrar la sesión cuando la transacción JTA se haya terminado. configurando la propiedad de Hibernate hibernate. Simplemente obtenga la SessionFactory de JNID (haciendo un "lookup"). Integración con los Servidores de Aplicación J2EE Hibernate tiene los siguientes puntos de integración con la infraestructura J2EE Fuentes de datos manejadas por el contenedor: Hibernate puede usar conexiones JDBC manejadas por el contenedor (container-mamaged). Se puede elegir un archivo distinto de configuración.Item. Note que usar hibernate. es posible que prefiera usar transaccioes manejadas por bean (bean-managed) e invocar la API de JTA y UserTransaction según haga falta. y de ahí obtenga la sesión actual.html <class-cache class="org.hibernate.Item" usage="read-write"/> <class-cache class="org. le recomedamos emplear la API Transaction de Hibernate.hibernate.8.auction.configure("catdb. excepto por los beneficios mencionados de usar una sintaxis XML.hibernate. usted puede comenzar y terminar sus transacciones llamando a la API de JDBC. JBoss). (por ejemplo.auction.HIBERNATE . hacer arrancar a Hibernate es tan simple como: SessionFactory sf = new Configuration().

sesiones contextuales con JTA.transaction.JTATransactionFactory delega a la transacción manejada por el contenedor (container-managed) si hay una tranascción en proceso en este contexto (por ejemplo.html Éstas son las tres opciones estándar.transaction. por ejemplo).BESTransactionManagerLookup Servidor de aplicaciones JBoss Weblogic WebSphere WebSphere 6 Orion Resin JOTM JOnAS JRun4 Borland ES 3. dado que en J2EE no hay un mecanismo estándar y único.WeblogicTransactionManagerLookup org.hibernate.org/documentacion_es/castellano. Hibernate colocará la fábrica de sesiones (SessionFactory) automáticamente en JNDI en cuanto se invoque cfg.JOnASTransactionManagerLookup org.ResinTransactionManagerLookup org. En un servidor de aplicaciones.transaction. .transaction.10. (Esto es especialmente útil en entornos que por defecto tienen una JNDI de sólo lectura. etc) requieren aceso al TransactionManager de JTA en un entorno administrado.transaction. Algunas características de Hibernate (por ejemplo.hibernar. que ya vienen incluidas "de fábrica": org.hibernate.WebSphereExtendedJTATransactionLookup org.JBossTransactionManagerLookup org.class para instanciar un contexto inicial.hibernate.JDBCTransactionFactory delega a las transacciones JDBC de la base de datos (es el valor por defecto) org.HIBERNATE .url y hibernate. SessionFactory ligada a JNDI Una fábrica de sesiones (SessionFactory) ligada a JNDI puede simplificar la búsqueda y obtención (lookup) de nuevas sesiones.OrionTransactionManagerLookup org. usted tiene que especificar cómo Hibernate obtendrá una referencia al TransactionManager.session_factory_name.JRun4TransactionManagerLookup org. crea una nueva transción.Persistencia Relacional para Java Idiomático http://www. se usa el InitialContext por defecto.jndi.transaction.transaction. Si esta propiedad es omitida. caché de 2do nivel. como por ejemplo Tomcat).hibernate.transaction. TransactionManagers de JTA Fábrica de transacciones org. Esto significa que este llamado estará presente.transaction.hibernate.hibernate. un método de un Session EJB). con HibernateService (lo cual se discute luego). Si no son especificadas. en algún código de arranque (o clase utilitaria) de su aplicación. Cuando de liga una fábrica de sesiones a JNDI.hibernate.hibernate. Note que esto no se relaciona con las Datasource.hibernate. y se utilizan transacciones manejadas por bean.transaction.hibernate. Tabla 3.hibernate.8. también ligadas a JNDI. java:hibernate/SessionFactory) usando la propiedad hibernate.transaction.CMTTransactionFactory delega a transacciones JTA manejadas por el contenedor Usted también puede definir sus propias estrategias transaccionales (por un servicio de transacciones CORBA.jndi. org.transaction.2.transaction.hibernate.buildSessionFactory(). 38 de 198 17/02/2009 09:25 a.hibernate. en caso contrario. especifique un nombre (por ejemplo. la fábrica de sesiones no quedará ligada a JNDI.JOTMTransactionManagerLookup org.WebSphereTransactionManagerLookup org. a menos que usted usa el despliegue JMX. Hibernate empleará los valores de hibernate. ¡ambas simplemente comparten el mismo repositorio de registro (registry)! Si usted desea mantener la fábrica de sesiones ligada a un "espacio de nombre" o "namespace" JNDI.m. por lo menos.

como JBoss. A las sesiones que hayan sido creadas de esta manera.4. se creará una y se la asociará con la transacción la primera vez que sessionFactory. El despliegue y configuración son específicos de la marca del servidor. o (lo que más recomendamos para producir código portable) usar la API de Transaction de Hibernate para establecer los límites de la transacción. use JNDI para obtener sus fábricas de sesiones. en un entorno administrado.jmx. Esto permite que las sesiones sean manejadas por el ciclo de vida de la transacción JTA al cual están asociadas. Note que dicha clase es también una buena manera de hacer arrancar Hibernate (capítulo 1).name=HsqlDS</depends> <!-.HIBERNATE .HibernateService" name="jboss.org/documentacion_es/castellano.caché <attribute <attribute <attribute de 2do nivel --> name="SecondLevelCacheEnabled">true</attribute> name="CacheProviderClass">org. y en cualquier otro entorno. HibernateUtil. les será automáticamente efectuado el "flush" antes de que la transacción finalice.transaction. Le recomendamos que.buildSessionFactory() aín tiene que ser ejecutada en algún lado para meter una fábrica de sesiones en JNDI. .Servicios requeridos --> <depends>jboss. manteniendo al código libre de ese tipo de preocupaciones administrativas. Hibernate es distribuido con org.3. también le recomendamos que oculte el código que efectivamente realiza el "lookup" dentro de una clase utilitaria.HSQLDialect</attribute> <!-.html Si usted usa una fábrica de sesiones JNDI.hibernate.cache.hibernar.hibernate. Despliegue de JMX La línea cfg. Manejo del contexto actual de la sesión con JTA La manera más fácil de manejar sesiones y transacciones es el manejo automático que Hibernate hace de la "sesión actual". si no hay ninguna sesión de Hibernate asociada con la transacción JTA actual. Usando el contexto de sesión "jta".name=HibernateFactory"> <!-.Persistencia Relacional para Java Idiomático http://www.EhCacheProvider</attribute> name="QueryCacheEnabled">true</attribute> <!-.opciones de captura --> <attribute name="MaximumFetchDepth">5</attribute> <!-.8. y las conexiones JDBC serán agresivamente liberadas después de cada comando.hibernate. 3.0. serán cerradas después de que la transacción finalice. Su código puede utilizar o bien JTA programáticamente a través de UserTransaction.JTATransactionFactory</attribut <attribute name="TransactionManagerLookupStrategy">org.jca:service=HibernateFactory.archivos de mapeo --> 39 de 198 17/02/2009 09:25 a.Ligar el servicio Hibernate a JNDI --> <attribute name="JndiName">java:/hibernate/SessionFactory</attribute> <!-. Vea la discusión en Sesiones actuales.0"?> <server> <mbean code="org.jmx.hibernate.transaction. (como por ejemplo. Para escudar su aplicación de estos detalles. un EJB o cualquier otra clase puede obtenerla usando el JNDI lookup.integración de transacciones --> <attribute name="TransactionStrategy">org. 3. Si su aplicación se está ejecutando en un contenedor de EJB.xml de ejemplo para for JBoss 4.fuente de datos --> <attribute name="Datasource">java:HsqlDS</attribute> <attribute name="Dialect">org.dialect. He aquí un jboss-service.HibernateService para el despliegue en servidores de aplicaciones con capacidad JMX. un singleton estático. Esto se puede lograr o bien con un bloque inicializador estático en una clase utilitaria (como el que está en HibernateUtil) o bien desplegando Hibernate como un "servicio administrado" (managed service).hibernate.m.jca:service=RARDeployer</depends> <depends>jboss.getCurrentSession() sea invocada. se prefiere utilizar demarcación declarativa de transacciones con CMT (siglas en inglés de "transacciones manejadas por el contenedor").hibernate.8.getSessionFactory()).JBossTransactionMa <attribute name="FlushBeforeCompletionEnabled">true</attribute> <attribute name="AutoCloseSessionEnabled">true</attribute> <!-.x: <?xml version="1.jca:service=LocalTxCM.Logueo --> <attribute name="ShowSqlEnabled">true</attribute> <!-.

sar (service archive o "archivo de servicio).Set. } void setColor(Color color) { 40 de 198 17/02/2009 09:25 a.m. import java. No todas las instancias de una clase persistente se considera que estén en un "estado persistente".weight = weight.hibernar. Color color. Hibernate trabaja mejor si estas clases siguen un formato muy simple. Clases Persistentes Las clases persistentes son clases de una aplicación que implementen las entidades de un problema de negocios (por ejemplo.id=id. Un modelo de dominio (domain model) se puede expresar de otras maneras: mediante árboles de instancias de Map. Un simple ejemplo de POJO La mayoría de las aplicaciones Java requieren una clase persistente que represente felinos: package eg.util. // identificador private private private private private Date birthdate. Hibernate3 presupone muy poco acerca de la naturaleza de sus objetos persistentes. private Set kittens = new HashSet().Persistencia Relacional para Java Idiomático http://www. conocido como el modelo de programación de "objeto Java liso y llano" o POJO (Plain Old Java Object) por sus siglas en inglés. Capítulo 4. import java.xml</attribute> </mbean> </server> Este archivo es desplegado en un directorio llamado META-INF. } public Long getId() { return id.Date.html <attribute name="MapResources">auction/Item. en cambio. y empaquetado en un archivo JAR con la extensión . } void setWeight(float weight) { this. por ejemplo. Sus EJB (usualmente session beans) pueden ser conservados en su propio archivo JAR. } public Color getColor() { return color. "Cliente" y "Orden" en una aplicación de e-commerce). ser transitoria (transient) o desprendida (detached). Consulte la documentación del servidor de aplicaciones JBoss para más información acerca del servicio JMX y el despliegue de EJB. private Cat mother. public class Cat { private Long id. ninguna de estas reglas es estrictamente obligatoria. Una instancia pude. int litterId. Mas aún. } void setBirthdate(Date date) { birthdate = date.1.org/documentacion_es/castellano.HIBERNATE . private void setId(Long id) { this. float weight. } public Date getBirthdate() { return birthdate. 4. } public float getWeight() { return weight.xml.util.auction/Category. char sex. Sin embargo. .hbm. pero este archivo JAR de EJB se puede incluir en el archivo principal de servicio para obtener una única desplegable "en caliente" (hot deployment).hbm.

sex=sex. en sus clases 41 de 198 17/02/2009 09:25 a. } //kittens=gatitos void setKittens(Set kittens) { this. La propiedad puede llamarse como sea. } } Aquí hay 4 reglas principales a seguir: 4.org/documentacion_es/castellano. Si su base de datos anticuada tiene claves compuestas. y su tipo puede ser cualquiera de los tipos de dato primitivos. } //litter=en inglés. kitten.1. } public Set getKittens() { return kittens.merge() Cat tiene Le recomendamos que declare propiedades indentificador nombradas de una manera consistente. camada void setLitterId(int id) { this. Todas las clases persistentes deben tener un constuctor por defecto (el cual puede no ser público) de manera qu Hibernate pueda instanciarlas usando Constructor.m.setMother(this). } public Cat getMother() { return mother. “Persistencia Transitiva” Session.String. Implemente un constructor sin argumentos Cat tiene un constuctor sin argumentos. Esta propiedad corresponde a la columna de clave primaria de la base de datos. De hecho. java. La puede omitir e Hibernate aún podrá seguirle la pista al objeto.util.size() ). cualquier tipo "envoltorio" (wrapper).litterId = id.11.1. o java. } public int getLitterId() { return litterId. Recomendamos fuertemente un constructor por defecto.Date. que tenga al menos visibilidad package para la generación del "proxy" en Hibernate.HIBERNATE . } void setMother(Cat mother) { this.lang.saveOrUpdate() Session.newInstance(). Recuperación (reattachment) transitiva para objetos desprendidos (update o merge en cascada)-vea Sección 10.add(kitten). } public char getSex() { return sex.hibernar. 4. algunas de las funcoionalidades están disponibles sólo para aquellas clases que sí tienen identificador. internamente.html this.1. .mother = mother.kittens = kittens.setLitterId( kittens. no le recomendamos que haga esto. kittens. Provea una propiedad indentificadora (optativo) una propiedad llamada id.color = color.Persistencia Relacional para Java Idiomático http://www.2. De todos modos. La propiedad indentificadora es estrictamente optativa. usted puede usar inclusive una clase definida por el usuario con propiedades de los tipos mencionados (vea la sección sobre claves compuestas más adelante). } // addKitten no es requerido por Hibernate public void addKitten(Cat kitten) { kitten. } void setSex(char sex) { this.

public String getName() { return name. depende de que la clase persistente no sea final.html persistentes. sin grabar.3. } protected void setName(String name) { this. Si se quiere usar clases con métodos públicos finales. public class DomesticCat extends Cat { private String name. 4.1. Mas aún. y sus valores de equals() y hashCode() (que estarían 42 de 198 17/02/2009 09:25 a. Declare métodos de acceso y "mutadores" (accessors. Implementar herencia Una subclase también debe cumplir con la primera y la segunda regla. se debe inhabilitar el "proxying" explícitamente. y reconoce nombres de método de la forma getAlgo. tan pronto como mezclamos instancias que hayan sido obtenidas de distintas sesiones.name=name. ¡Desafortunadamente. pero usted no será capaz de usar proxies para la captura por asociaciones perezosas (lazy association fetching). Así que. Implementar equals() y hashCode() Usted debe reemplazar (override) los métodos equals() y hashCode() si: planea poner instacias de clases persistentes en un Set (lo cual es la manera recomendada de representar cualquier asociación con un lado "muchos"). ambos deben ser el mismo registro de la base de datos.3. mutators) para los campos persistentes. sólo dentro del alcance de una sesión en particular. sólo tendremos un elemento en el Set. Se puede persistir clases finales que no implementen una interfaz con Hibernate. isAlgo y setAlgo.2. .hibernar. La manera más obvia es implementar equals()/hashCode() comparando el valor identificador de ambos objetos.1. grabarla le va a asignar un identificador. está dentro de un Set. y planea usar recuperación (reattachment) de instancias desprendidas Hibernate garantiza la equivalencia de la identidad persistente (el registro de base de datos) y la identidad de Java. lo cual limitará sus opciones de ajuste de performance.m. Nosotros creemos que es mejor proveer un nivel de aislamiento entre el esquema relacional y la estructura interna de datos de la clase.4. También se debería evitar declarar métodos public final en las clases no finales. usted puede revertir esto. Prefiera clases que no sean finales (optativo) Una característica central de Hibernate. Por defecto. siendo por lo tanto iguales (si ambos son agregados al Set. y permitir el acceso directo. especificando lazy="false". 4. le recomendamos que use un tipo anulable (es decir.org/documentacion_es/castellano. o de que sea la implementación de una interfaz con todos sus métodos públicos. debemos implementar equals() y hashCode() si deseamos tener una semántca con sentido para los Sets. y una instancia que haya sido recientemente creada ¡aún no tiene ningún identificador! Más aún. Hibernate puede persistir una propiedad con un par get/set que tenga acceso por defecto (package) o privado.). Hibernate persiste propiedades del tipo JavaBean. para propiedades específicas. no podemos utilizar ese enfoque con los identificadores generados! Hibernate sólo asignará identificadores los objetos que hayan sido creados. Hereda su identificador de la superclase Cat.. } } 4. 4.Persistencia Relacional para Java Idiomático http://www. Si el valor es el mismo. Cat declara métodos de acceso para todos sus campos persistentes. Si es necesario.. si una de estas instancias.HIBERNATE . package eg. Muchos otras herramientas de ORM persisten directamente sus variables de instancia. No se necesita que las propiedaes sean declaradas como públicas. no primitivo). los representantes o proxies.

Note que esto no es un problema de Hibernate. .hashCode(). rompiendo el contrato del Set. result = 29 * result + getLitterId().3. necesariamente.equals( getMother() ) ) return false. if ( !cat. Esto quiere decir. y la representación de entidades como árboles DOM4J. public boolean equals(Object other) { if (this == other) return true. com clases POJO u objetos JavaBean.html basados en el identificador) cambiarían. usando la opción de configuración default_entity_mode (vea Tabla 3. Vea el sitio de web de Hibernate para una discusión completa de este problema. usualmente son buenas candidatas a "clave de negocio". } } Note que la clave de negocio no necesita ser tan sólida como una clave primaria de la base de datos. Modelos dinámicos Advierta que las siguientes características se consideran experimentales. no se escriben clases.org/documentacion_es/castellano. Hibernate también soporta modelos dinámicos (usando Maps de Maps en tiempo de ejecución). } public int hashCode() { int result..4.HIBERNATE .getLitterId().m. Los ejemplos siguientes demuestran la representación usando mapas. final Cat cat = (Cat) other. result = getMother(). que estos métodos comparen solamente propiedades que formen la clave de negocio. “Propiedades de Configuración de Hibernate”. Por defecto.hibernar. y pueden cambiar en el futuro cercano Las entidades persistentes no tienen que ser representadas.3. if ( !(other instanceof Cat) ) return false. “Considerar la identidad de un objeto”). Con este enfoque. se debe declara un entity-name en lugar de (o además 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. Primero. en el archicvo de mapeo.getMother(). return true.1.equals( getLitterId() ) ) return false. Propiedades que sean únicas o inmutables. if ( !cat. 4. simplemente archivos de mapeo. return result. una clave que identificaría a nuestro objeto en el mundo real (una clave candidata natural). Se puede configurar un modo de representación de entidad por defecto para una fábrica de sesiones en particular. (vea Sección 11. public class Cat { . en tiempo de ejecución. Nosotro recomendamos implementar equals() y hashCode() utilizando una igualdad "por clave de negocio". Hibernate trabaja en el modo POJO normal.. sino parte de la semántica normal de Java en lo que respecta a la igualdad e identidad de los objetos.Persistencia Relacional para Java Idiomático http://www.

tuple.EntityMode de dicha representación. sin la necesidad de implementar clases de entidades. Esto vuelve innecesario invocar flush() y close() en la sesión secundaria. Por ejemplo. no de SessionFactory.save("Organization". permitiendo agregar una implementación apropiada de modelo de dominio encima.hibernate. Si un determinado fragmento de datos se concibe como una estructura de datos..close() . tx. Session s = openSession(). "Foobar Inc.").. T-uplizadores org.hibernate. entonces un t-uplizador es lo que sabe cómo crear dicha estructura.Tuplizer. dado el org. // Crear una organización Map foobar = new HashMap(). david). foobar.beginTransaction().put("organization". Session s = openSession(). incluso si las asociaciones son declaradas usando nombres de clases de destino.html </class> </hibernate-mapping> Note que.close(). Se puede encontrar más información sobre las capacidades de representación con XML en Capítulo 18. david.put("name". . Transaction tx = s. // Crear un cliente Map david = new HashMap().save("Customer". Hay dos t-uplizadores de alto nivel. para prototipos. foobar). el tipo de destino de una asociación también puede ser una entidad dinámica en lugar de un POJO. // Continúa con la sesión "POJO" Dese cuenta por favor de que el llamado a getSession() usando un EntityMode determinado. . Después de configurar el modo de entidad por defecto a dynamic-map para esta SessionFactory. david. De esta manera. La ventaja de un mapeo dinámico es acelerar el tiempo de entrega.hibernar. y sus sub-interfaces. s. representados por las interfaces org. // Grabar a ambos s.getSession(EntityMode. "David").EntityTuplizer y 44 de 198 17/02/2009 09:25 a.HIBERNATE .tuple.. son los encargados de manejar una representación en particular de un fragmento de datos. la nueva sesión comparte la misma conexión JDBC subyacente. para el modo de entidad "POJO". y le deja el manejo de transacciones y conexiones a unidad de trabajo primaria. s.entity.org/documentacion_es/castellano. foobar).flush(). 4. y cómo acceder a las propiedades de POJO usando los métodos de acceso.MAP). más adelante. De todos modos.Persistencia Relacional para Java Idiomático http://www. podemos trabajar con "mapas de mapas" en tiempo de ejecución. y esto muy probablemente causará varias excepciones en tiempo de ejecución.put("name".m. // Vincular a ambos david.hibernate. el t-uplizador correspondiente sabe cómo crear el POJO mediante su constructor. dynamicSession.5.save("Customer". Gracias al mapeo de Hibernate.commit(). se pierde el chequeo de tipos en tiempo de compilación. es cosa de la API de Session API. dynamicSession. david).. Los modos de representación de entidad también pueden ser configurados por sesión: Session dynamicSession = pojoSession. "David"). dynamicSession. y otra información de contexto. // Crea un cliente Map david = new HashMap().put("name". Mapeo XML. el esquema de base de datos puede ser fácilmente normalizado y saneado.

DynamicMapEntityTuplizer { // suplanta al método buildInstantiator() para "enchufar" nuestro mapeo hecho a medida .. mientras que los ComponentTuplizers hacen lo propio para los componentes. Comencemos con un mapeo de ejemplo: <?xml version="1.1.. Declaración del mapeo Los mapeos objeto/relacionales generalmente se definen en un documento XML.. El usuario puede.tuple. } //suplanta a generateMap() para devolver nuestro map hecho a medida private static final class CustomMapInstantiator extends org. existe un buen número de herramientas para generar el documento de mapeo. Note que.sourceforge.ComponentTuplizer. no de tablas. </class> </hibernate-mapping> public class CustomMapTuplizerImpl extends org. o tal vez usted necesita que se utilice una estrategia de generación de proxies distinta de la que viene de fábrica.hibernate.Persistencia Relacional para Java Idiomático http://www.hibernate. lo cual significa que los mapeos se construyen en torno a declaraciones de clases persistentes. protected final Instantiator buildInstantiator(org. aunque muchos usuarios de Hibernate eligen escribir el XML a mano.component. Tal vez usted desee que par el modo de entidad "dynamic-map" se utilice una implementación de java.org/documentacion_es/castellano. Extensiones A HACER: documentar el framework de extensiones de usuario y paquetes proxy. insertar sus propios t-uplizadores. El lenguaje de mapeo es "Javacéntrico". Middlegen y AndroMDA. <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> <!-.m. Los EntityTuplizers see encargan de manejar los "contratos" recién descritos para las entidades.net/hibernate-mapping-3. } } } 4.DynamicMapInstanti protected final Map generateMap() { return new CustomMap().0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.HashMap. El documento de mapeo ha sido diseñado para ser legible y editable a mano.Map que no sea java. como: XDoclet.hibernar.util. Mapeo O/R básico 5.tuple.mapping.html org.0//EN" "http://hibernate.HIBERNATE . Volviendo al ejemplo de la entidad "cliente" (customer).util. Las definiciones de t-uplizer van adjuntas a la entidad o mapeo de componentes que están destinadas a manejar.hibernate.hibernate.entity.PersistentClass mappingInf return new CustomMapInstantiator( mappingInfo ).tuple.0. Capítulo 5.6.dtd"> 45 de 198 17/02/2009 09:25 a. . asimismo.otras propiedades--> ..

una locución latina que en inglés hace las veces de "por ejemplo".1.org/documentacion_es/castellano. .x/src/org/hibernate o en hibernate3. EntityResolver Como se mencionó anteriormente.1.EntityResolver con el SAXReader que usa para leer los archivos xml.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"> <!-. A lo largo de esta documentación.hibernar. 5.xml. y (2).types.m. Hibernate siempre buscará la DTD primero en el classpath.x.Persistencia Relacional para Java Idiomático http://www. Ahora discutiremos el contenido del documente de mapeo.sourceforge.1. Un ejemplo de utilización de un espacio de nombre (namespace) hecho a medida: 46 de 198 17/02/2009 09:25 a. el resolver intentará resolver esas entidades a través de (1) el classloader del contexto de thread actual. compare su declaración de DTD contra el contenido de su classpath. 5. y elementos que afectan los esquemas de BD exportados por herramientas de exportación de esquemas (por ejemplo. un espacia de nombre de usuario se reconoce siempre que el resolver encuentra un systemId que use un protocolo de URL classpath://. La DTD real puede ser encontrada en la URL mencionada.sax. es registrando una implementación personalizada de org. Hibernate primero intentará resolver la DTD en su classpath. Si experimenta problemas al buscar la DTD debido a su conexión de Internet.net/. El Doctype o "tipo de documento XML" Todos los mapeos XML deberían declarar el doctype que se muestra. Este EntityResolver perosnalizado reconoce dos espacios de nombre de systemId diferentes. El documento de mapeo también contiene algunos atributos optativos adicionales.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. un "espacio de nombre" (namespace) de Hibernate es reconocido siempre que el resolver encuentra un systemId qie comience con http://hibernate.acá podría ir un mapeo para Perro --> </class> </hibernate-mapping> (N.HIBERNATE . el classloader que haya cargado las clases de Hibernate. el atributo not-null).1. en el directorio hibernate-x. La manera en que lo hace. Sólo describiremos los elementos y atributos del documento que son usados por Hibernate en tiempo de ejecución.1. el resolver intenta resolver estas entidades mediante el classloader que haya cargado las clases de Hibernate.jar.del T): "eg" son las siglas de "exempli gratia". "eg" se usa como el paquete por defecto para los ejemplos de código.

none): El estilo por defecto de propagación en cascada (4) defecto. hibernate-mapping Este elemento tiene varios atributos optativos. usar un nombre de clase no calificado en el lenguaje de consultas.. Si no están presentes.2.. (7) package (optativo): Especifica un prefijo de paquete a ser asumido.HIBERNATE . para las clases no calificadas en el documento de mapeo.domain"> <class name="MyEntity"> <id name="id" type="my-custom-id-type"> .por defecto true): Especifica si se puede usar nombres de clase no calificados (de clases en el mapeo) el en lenguaje de consultas.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 catálogo de BD (3) default-cascade (optativo . .Persistencia Relacional para Java Idiomático http://www. </id> <class> &types. Los atributos schema y catalog especifican que las tablas a las que este mapeo se refiere pertenecen al esquema o catálogo indicado.sourceforge.m. El atributo defaultcascade especifica qué estilo de propagación en cascada debería asumirse para las propiedades y colecciones que no especifiquen un atributo cascade. 5. property): La estrategia que Hibernate debería usar para acceder a todas las propiedades.org/documentacion_es/castellano.domain y contiene una definición de tipo a medida typedef.xml es un recurso en el paquete your. (5) default-lazy (optativo . los nombres de tabla serán calificados con el esquema y/o catálogo dados. default-access (optativo .0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3. Puede ser una implementacíón personalizada de PropertyAccessor.html <?xml version="1. </hibernate-mapping> En donde types.dtd" [ <!ENTITY types SYSTEM "classpath://your/domain/types.hibernar.por defecto.por (6) auto-import (optativo . <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.por defecto. true): El valor por defecto para los atributos lazy no especificados de clases y colecciones. por defecto.0//EN" "http://hibernate. 47 de 198 17/02/2009 09:25 a.net/hibernate-mapping-3.1.xml"> ]> <hibernate-mapping package="your.0. los nombres de tabla no serán calificados. El atributo auto-import nos permite. Si se especifican.

<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. usado para comportamiento polimórfico.m. (6) catalog (optativo): Suplanta al nombre de catálogo especificado por el elemento <hibernate-mapping> raíz. 48 de 198 17/02/2009 09:25 a.por defecto el nombre no calificado de la clase): El nombre de su tabla en la base de datos (3) discriminator-value (optativo .org/documentacion_es/castellano. Cat. Note que el elemento hibernate-mapping le permite anidar los mapeos de varias clases persistentes. (2) table (optativo .hbm. . Se puede especificar el nombre de la clase misma.xml.3.hibernar. o. Dog. si se usa herencia. (5) schema (optativo): Suplanta al nombre de esquema especificado por el elemento <hibernate-mapping> raíz. 5. (4) mutable (optativo.xml.HIBERNATE . debería configurar auto-import="false". por defecto.1. Hibernate lanzará una excepción si usted le intenta asignar dos clases al mismo nombre "imported". el nombre de la clase): Un valor que distingue entre subclases individuales. null y not null también son valores aceptables. (7) proxy (optativo): Especifica una interfaz a utilizar para los proxies de inicialización perezosa.Persistencia Relacional para Java Idiomático http://www.hbm. Si este atributo está ausente. class Se puede declarar una clase persistente usando el elemento class.por defecto.xml. Animal.hbm.html Si usted tiene dos clases persistentes cuyo nombre (no calificado) es el mismo. Por ejemplo. como se muestra anteriormente. Sin embargo. se asume que no se trata de una entidad POJO. true): Especifica si las instancias de esta clase son o no mutables. mapear sólo una clase persistente (o jerarquía de clases) por archivo de mapeo es una costumbre más establecida (y lo que algunas herramientas esperan).

por defecto false): Especifica que Hibernate nunca debería ejecutar un UPDATE SQL a menos que esté seguro de que en realidad se está modificando algún objeto. por defecto. y permite mapeos de entidades qie estén representados por Maps a nivel de Java.hibernar. y representa la ubicación física de una t-upla alamacenada.Persistencia Relacional para Java Idiomático http://www. Hibernate puede usar la columna adicional rowid para actualizar más rapidamente.org/documentacion_es/castellano. por defecto false): Especifica que los comandos SQL UPDATE deberían ser generados en tiempo de ejecución. (12) where (optativo) especifica una condición SQL WHERE arbitraria a ser usada cuando se seleccionen objetos de esta clase. version): Determina la estrategia de "locking" optimista. sólo cuando un objeto transitorio ha sido asociado con una nueva sesión usando update()). “Modelos dinámicos” y Capítulo 18. 1) especifica un "tamaño de lote" para capturar instancias de esta clase por identificador. (21) abstract (optativo): Usado para marcar superclases abstractas en jerarquías de <union-subclass>. por defecto.HIBERNATE . (10) select-before-update (optativo. (20) subselect (optativo): Mapea una entidad inmutable y de sólo-lectura a un subselect de la base de datos. conteniendo sólo las columnas cuyos valores son no nulos. por defecto. (15) optimistic-lock (optativo. si usted configura esta opción a rowid. (11) polymorphism (optativo. En estos casos. para determinar si un en realidad un UPDATE es necesario. por defecto. (9) dynamic-insert (optativo. (19) rowid (optativo): Hibernate puede usar los vulgarmente llamados ROWIDs. (17) entity-name (optativo. (18) check (optativo): Una expresión SQL arbitraria usada para generar una constraint tipo check multifila a usar durante la generación automática del esquema.m. Es útil si se quiere tener una vista en lugar de una tabla. Un ROWID es un detalle de implementación. por defecto. (13) persister (optativo): Especifica un ClassPersister hecho a medida. Mapeo XML for more information. . y contener sólo aquéllas comlumnas cuyos valores hayan cambiado.html (8) dynamic-update (optativo. En algunos casos (en realidad. false): Especifica que se deberían generar comandos SQL INSERT en tiempo de ejecución. (16) lazy (optativo): La captura haragana puede ser completamente inhabilitada espefificando lazy="false". el nombre de la clase): Hibernate3 permite que una clase sea mapeada muchas veces (potencialmente.4. esto significa que Hibernate ejecutará un comando SQLSELECT adicional. implicit): Determina si se usa polimorfismo explícito o implícito. (14) batch-size (optativo. pero no se cuenta con una vista en la base de datos. en aquellas DB que lo soporten. Por ejemplo. se debería proveer un nombre arbitrario explícito para la entidad. Vea más adelante para más información. 49 de 198 17/02/2009 09:25 a. a distintas tablas). Vea Sección 4. en Oracle.

Se debería especificar el nombre de este tipo de clases usando la nomenclatura estándar. y es la única estrategia que maneja correctamente las modificaciones que se hagan a instancias desprendidas (es decir. Esto le permite a Hibernate realizar algunas optimizaciones menores.amount).test.item_id = item.Persistencia Relacional para Java Idiomático http://www.id group by item. Para un mapeo Hibernate. En este caso. Ésta es la estrategia óptima en lo que a performace se refiere. pero no puede crear una en la base de datos (por ejemplo. así que pueden ser especificadas en los elementos <subclass> o <joined-subclass>. El atributo optativo proxy permite la inicialización perezosa de instancias persistentes de la clase. Inicialmente.EntityPersister. Vea "Inicializar colecciones y proxies" más adelante. Si usted habilita dynamic-update. o LDAP. En ese caso. usted puede mapear una entidad inmutable y de sólo-lectura a una expresión "subselect" de SQL. es decir com.m.ClassPersister que persista.hibernar. El atributo persister le permite personalizar la estrategia de persistencia usada para la clase. max(bid. count(*) from item join bid on bid. tendrá las siguientes opciones de "locking" optimista version verifica all las columnas de versión/timestamp verifica todas las columnas verifica las columnas que hayan cambiado. </class> 50 de 198 17/02/2009 09:25 a.. o hasta puede proveer una implementación completamente nueva de la interfaz org. especialmente actualizaciones de éstas). .persister. con un esquema heredado anticuado).Mi$ClaseInterna.html Es perfectamente aceptable que la clase persistente nombrada sea une interfaz. Vea org. no hay diferencia entre una vista y una tabla de la base de datos. Polimorfismo explícito significa que instancias de esta clase sólo serán devueltas por consulta que nombren a esta clase. permitiendo algunas modificaciones concurrentes dirty none no usa "locking" optimista Recomendamos muy fuertemente que se utilicen las columnas de versión/timestamp para locking optimista con Hibernate.merge() ). Note que las asignaciones de valores dynamic-update y dynamic-insert no son heredadas por la subclases. usted puede especificar su propia subclase de org. 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 sesión.hibernate. El objeto persistente propiamente dicjo será cargado cuando se invoque un método del proxy.hibernate. Estos valores pueden incrementar la performance en algunos casos.name. A veces usted quiere usar una vista. Como es de esperarse. El uso de select-before-update normalmente bajará la performance. que implementan la interfaz mencionada. Las clases inmutables (mutable="false") no pueden ser actualizadas o borradas por la aplicación. <class name="Summary"> <subselect> select item. Para la mayoría de los casos. o usando serialización a archivos planos. Hibernate devolverá proxies CGLIB.CustomPersister para un ejemplo simple (de "persistencia" a una Hashtable). por ejemplo. Polimorfismo implícito significa que cualquier consulta que nombre a una superclas o interfaz devolverá instancias de la clase misma.hibernate.. y que las consultas que nombren a esta clase devolverán sólo instancias de subclases que hayan sido mapeados como <subclass> o <joined-subclass>. El polimorfismo explícito 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). se debe declarar la clase implementadora usando el elemento <subclass>. Úselos con cuidado. valiéndose de una llamada a un procedimiento almacenado de base de datos. es lo más apropiado.org/documentacion_es/castellano. cuando se use Session.name </subselect> <synchronize table="item"/> <synchronize table="bid"/> <id name="name"/> . Por ejemplo. el valor por defecto polymorphism="implicit".HIBERNATE . pero reducirla en otros. Se puede persistir cualquier clase anidada (inner class) estática.persister. esto es transparente a nivel de base de datos (note que algunas base de datos no soportan vistas correctamente.

con clave compuesta.4.m. el nombre de la propiedad): El nombre de la columna de la clave primaria (4) unsaved-value (optativo. Si falta el atributo name . Si hace falta algún parámetro para inicializar la instancia del generador. <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|.TableHiLoGenerator"> <param name="table">uid_table</param> <param name="column">next_hi_value_column</param> </generator> </id> Todos los generadores implementan la interfaz org.1. Desaconsejamos su uso en cualquier otro caso. . property): La estrategia que Hibernate debería usar para acceder al valor de la propiedad.HIBERNATE . para permitur el acceso a datos de formato anticuado. por defecto.id. La mayoría de las clases también tendrán una propiedad del estilo JabaBeans conteniendo el didentificador único de una instancia determinada. 5. <subselect> está disponible como atributo y como elemento anidado. (5) access (optativo.id.hibernar.Persistencia Relacional para Java Idiomático http://www. distinguiéndola de las instancias desprendidas que fueron grabadas o cargadas en una sesión previa. 5. Hay una declaración alternativa de <composite-id>. El atributo unsaved-value casi nunca se usa en Hibernate3. En el mapeo. id Las clases mapeadas deben declarar la columna de clave primaria de la tabla en la base de datos.hibernate. El elemento <id> define el mapeo de esa propiedad a la columna de clave primaria. <id name="id" type="long" column="cat_id"> <generator class="org.1. (2) type (optativo): Un nombre que indica el tipo de Hibernate (3) column (optativo. 51 de 198 17/02/2009 09:25 a.html Declara las tablas contra las cuales se ha de sincronizar esta entidad. Generator El elemento opcional hijo <generator> nombra a la clase de Java que se usa para generar los identificadores únicos de la clase persistente. se asume que la clase no posee propiedad indentificadora. Es una interfaz muy simple.IdentifierGenerator. asegurándose de que el auto-flush ocurra correctamente. y que las consultas efectuadas contra la entidad derivada no devuelvan datos vencidos. por defecto." <generator class="generatorClass"/> </id> (1) (2) (3) (4) (5) (1) name (optativo): El nombre de la propiedad indentificadora. por defecto.org/documentacion_es/castellano. se pasa usando el elemento <param>. un valor "adecuado"): Una propiedad identficadora que indica que una instancia ha sido recientemente instanciada (no grabada).hibernate.4.1.

short o int.4. El algorithmo hi/lo genera identificadores que son únicos sólo para una base de datos en particular. short o int eficientemente. El identificador que se devuelve es de tipo long. select obtiene una clave primaria asignada por un trigger de la base de datos. short o int hilo usa un algoritmo hi/lo para generar identificadores de los tipos long.html algunas aplicaciones podrían elegir proveer su propia implementación a medida. assigned deja que sea la aplicación la que asigne el identificador al objeto antes de que save() sea llamado. pero lo combina con el método de JDBC3 getGeneratedKeys para devolver el valor final. El identificador que se devuelve es de tipo long. Note que los comentarios en estos comandos están inhabilitados. sequence o hilo. Oracle. dependiendo de las capacidades de la base de datos subyancente. El UUID es codificado como una cadena de 32 dígitos hexadecimales. PostgreSQL. Esta estrategia sólo es soportada. guid usa una cadena GUID generada por la base de datos. MS SQL Server. Ésta es la estrategia por defecto si no se especifica un elemento <generator>. foreign usa el identificador de algún otro objeto asociado. uuid usa un algoritmo UUID de 128 bits para generar identificadores de tipo string. dada una tabla y una columna (por defecto. Sybase e HypersonicSQL. identity soporta "columnas de identidad" (identity) en DB2. Hibernate provee una variedad de implementaciones que ya vienen incluidas. native elije identity. short o int que son únicos solamente cuando ningún otro proceso está insertando datos en la misma tabla. Los siguientes son los apodos mnemónicos para estos generadores ya incluidos: increment genera identificadores de tipo long.HIBERNATE . Normalmente se usa en conjunción con una asocoación <one-to-one> por clave primaria. sequence usa una secuencia (sequence) en DB2. short o int eficientemente.Persistencia Relacional para Java Idiomático http://www. 52 de 198 17/02/2009 09:25 a. únicos para toda una red (se usa la dirección de IP). hibernate_unique_key y next_hi respectivamente) como fuente de los valores "hi". MySQL. que sepamos. seleccionando la fila por alguna clave única y obteniendo el valor de clave primaria. en MS SQL Server y MySQL. seqhilo usa un algoritmo hi/lo para generar identificadores de los tipos long. debido a un error en los drivers de Oracle.m. McKoi o un generador en Interbase. sequence-identity una generación de secuencias especializada que utiliza una sequencia de base de datos para la generación del valor en sí. De todos modos. dada una secuencia (sequence) nombrada de base de datos. SAP DB.hibernar.org/documentacion_es/castellano. como parte del comando INSERT. . No usar en un cluster. por los drivers de Oracle 10g diseñados para JDK1.

<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 más portátil entre distintas plataformas (cross-platform).hibernar. Este generador se usa cuando la clave primaria es una clave natural en lugar de una clave sustituta (surrogate key). Interbase.html 5. MySQL. Cuando Hibernate use una fuente de datos de un servidor de aplicaciones para obtener conexiones inscriptas en JTA.org/documentacion_es/castellano. 5. <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.Persistencia Relacional para Java Idiomático http://www.HIBERNATE . usted puede usar el "generador" assigned. SAP DB) se puede usar el valor sequence. y un valor contador que es único a lo ancho de la JVM. El algoritmo hi/lo Los generadores hilo y seqhilo proveen dos implementaciones alternativas del algoritmo hi/lo.5. usted no puede usar hilo cuando le provee su propia conexión (Connection) a Hibernate.4.4.manager_lookup_class. sin usar JNI.4. Ambas estrategias requieren el uso de 2 comandos SQL para insertar un objeto nuevo. usted deberá configurar adecuadamente la hibernate.4. 5.4. ya que elige entre identity.1. 53 de 198 17/02/2009 09:25 a. la hora del sistema. El algoritmo UUID El UUID (siglas en inglés de "identificador universal único) contiene: la dirección de IP. usa una secuencia al estilo de Oracle (si esto se soporta). Éste es el comportamiento por defecto. Identificadores asignados Si desea que sea la aplicación la que asigne los identificadores (en lugar de que Hibernate los genere). MS SQL).1.transaction. .1. Columnas de indentidad y secuencias Con las BD que soportan columnas de identidad (DB2. La primera implementación requiere una tabla de base de datos especial que almacene el siguiente valor "hi" disponible.3. se puede usar la generación de claves identity. Desde el código Java no se puede obtener la dirección MAC o direcciones de memoria.1. Este generador especial usa el valor de identificador ya asignado a la propiedad indentificadora del objeto. Sybase.2. así que esto es lo mejor que se puede lograr. Oracle. La segunda. PostgreSQL. si no se especifica el elemento <generator>.m. dependiendo de las capadidades de la DB subyacente. 5. Con las que soportan secuencias (DB2. un enfoque muy común para generar identificadores. sequence e hilo. el tiempo de comienzo de la JVM (al cuarto de segundo). McKoi.

las cuales tienen en general semánticas distintas.id. 5.html Elegir el generador assigned.HIBERNATE .id. siguen incluyéndose en los lanzamientos actuales.hibernate.2. el segundo es la optimización (no tener que consultar a la base de datos cad vez que se requiera un valor de identificador nuevo).org/documentacion_es/castellano. el cual ha sido primariamente concebido en reemplazo del generador table. definido por la clase.4. o usted defina Interceptor. El primer aspecto. 1): El valor de la secuencia (o tabla) a ser usada. por defecto. 1): El incremento usdo en llamadas ulteriores a la tabla/secuencia.6. ha sido concebido como una reimplementación de org. Secundariamente.id. en realidad. none): Vea Sección 5.1. hay 2 nuevos generadores que representan un replanteo de 2 aspectos diferentes de la generación de identificadores.3. por defecto.Persistencia Relacional para Java Idiomático http://www.hibernate.id. funciona mucho más como un org. false): Deberíamos forzar el uso de una tabla como estructura de respaldo.enhanced. forzándolo a determinar si una instancia es transitoria o desprendida. dependiendo de las capacidades del dialecto que esté siendo usado.1.x) han sido concebidos con el objetivo de reemplazar a algunos de los generadores nombrados anteriormente De todos modos. sin embargo. (aunque. esto es análogo a la cláusula típica "INCREMENT BY". hibernate_sequence): El nombre initial_value (optativo. La diferencia entre esto y native. force_table_use (optativo. es que el almacenamiento basado en tablas y el basado en secuencias tienen exactamente la misma semántica (de hecho.UU. por defecto.hibernate.isUnsaved(). por defecto. El primero de estos nuevos generadores es el org.3. este generador define una tabla que es capaz de contener múltiples valores de 54 de 198 17/02/2009 09:25 a.id. el cual ha sido concebido como reemplazo del generador sequence. En esencia. org. Generadores de identificador mejorados A partir de la versión 3.1. 5.hibernate.hibernar.MultipleHiLoPerTableGenerator). inicial a ser devuelto por la tabla/secuencia. <id name="id" type="long" column="person_id"> <generator class="select"> <param name="key">socialSecurityNumber</param> </generator> </id> (N del T): el número de seguridad social o SSN es un número único asignado por el Estado a cada persona en EE.6. En el ejemplo precedente. y se puede hacer referencia a ellos via FQN. por defecto.SequenceStyleGenerator. Estos dos nuevos generadores (a partir de la versión 3. esto es análogo a la cláusula típica "STARTS WITH". las secuencias son exactamente lo que Hibernate trata de emular con sus generadores badados en tablas). Elije entre usar una tabla o una secuencia en la base de datos para almacenar sus valores incrementados. incluso si el dialecto soporta secuencias? value_column (optativo. Este generador tiene varios parámetros de configuración: sequence_name (optativo. lo cual puede causar sutiles problemas aplicaciones que consideren portabilidad). consigue la portabilidad de una manera diferente. Claves primarias asignadas por triggers Para esquemas de DB anticuados/heredados solamente (Hibernate no genera DDL con triggers). cuyo valor es generado por un trigger que seleciona dicho número.TableGenerator. increment_size (optativo. y una clave primaria en la tabla llamada person_id. hay un valor de propiedad único llamado socialSecurityNumber. por defecto. . a menos que haya una propiedad "version" o "timestamp". En términos de la creación de la secuencia.MultipleHiLoPerTableGenerator que utiliza la noción de optimizadores "enchufables" (pluggable).enhanced. next_val): ¡Sólo relevante para estructuras de tabla! El nombre de la columna en la tabla usada para almacenar el valor.5. y como un generador con una portabilidad superior a native (porque native (generalmente) elije entre identity y sequence. En términos de la creación de la secuencia.enhanced. es la portabilida de base de datos.hibernate. hace que Hibernate use unsaved-value="undefined". como clave natural. “Optimización de los generadores de identificador” El segundo de estos nuevos generadores es org.m.SequenceStyleGenerator. optimizer (optativo.

y solamente acudir a la base de datos cuando se ese grupo de valores se haya agotado. initial_value (optativo. 1): El valor inicial a ser devuelto por la tabla.1.1. hibernate_sequences): El nombre de la tabla a usar. Este generador tiene varios parámetros de configuración: table_name (optativo. increment_size (optativo. default): El valor de "clave de segmento" del cual queremos extraer valores de incremento para este generador. segment_value (optativo.. se puede mapear varias de sus propiedades como identificadores. hilo: aplica un algoritmo hi/lo en torno a los valores devueltos por la base de datos.html incremento distintos. Ésta es la función de los "optimizadores enchufables". segment_value_length (optativo.. por defecto. Se espera que los valores de base de datos para este optmizador sean secuenciales.. segment_column_name (optativo. por defecto. En lugar de ello. 1): El valor optimizer (optativo. estos optimizadores intentan minimizar el número de viajes a la base de datos.org/documentacion_es/castellano. “Generadores mejorados de identificadores ”) soportan esta noción. Los valores devueltos desde la estructura de base de datos para este optmizador indican el "número de grupo". más que un valor secuencial en combinación con un algoritmo de agrupamiento en memoria. Este es el valor que identifica de manera distintiva qué valor de incremento usar. <composite-id> <key-property name="medicareNumber"/> 55 de 198 17/02/2009 09:25 a.. Aquí.HIBERNATE . . que será usada para contener el valor. El elemento <composite-id> acepta mapeos de propiedades <key-property> y mapeos como elementos hijos. usando múltiples registros con claves diferentes. por defecto. next_val): El nombre de la columna en la tabla. sequence_name): El nombre de la columna en la tabla que setá usada para contener la "clave de segmento".6.1.. por value_column_name defecto. el increment_size (tamaño del incremento) se multiplica por el valor en memoria para definir un grupo "hi value".Persistencia Relacional para Java Idiomático http://www. por defecto. “Optimización de los generadores de identficadores” 5. el valor por defecto si no se especificó ningún optimizador): Esto indica que no se efectúe ninguna optimización. pooled: como fue discutido para hilo.7.m. por defecto.hibernar." <key-property name="propertyName" type="typename" column="column_name"/> <key-many-to-one name="propertyName class="ClassName" column="column_name"/> . ): Vea Sección 5.6. por el cual las llamdas subsiguientes a la tabla deberían diferir. increment_size se refiere a los valores que vienen de la base de datos. </composite-id> En una tabla con clave compuesta. por defecto. generalmente. Optimización de los generadores de identficador Para los identificadores que almacenan valores en la base de datos. lo ideal es agrupar un buen número de ellos en la memoria.1. 5. 255): Usado para la generaciónde esquemas. por defecto. sin embargo. Por el momento sólo los dos generadoeres mejorados (Sección 5. (optativo. composite-id <composite-id name="propertyName" class="ClassName" mapped="true|false" access="field|property|ClassName"> node="element-name|. es ineficiente acudir a la base de datos cada una de las veces en que se necesita generar un nuevo valor de identificador. y que se acuda a la base de datos para todos y cada uno de los pedidos.5.Aquí. none (éste es. el tamaño del campo de esta "clave de segmento". simplemente almacenamos en valor inicial para el "próximo grupo" en la estructura de base de datos.

html <key-property name="dependent"/> </composite-id> Su clase persistente debe reemplazar equals() y hashCode() para implementar igualdad entre identificadores compuestos. que le dice a la capa de persistencia qué clase debe instanciar para cada registro en particular. 5. Los siguientes atributos son usados para especificar un identificador compuesto mapeado: mapped (optativo. y poblarle sus propiedades identificadores antes de poder cargarlo en estado persistente asociado con una clave primaria.m. Los atributos descritos a continuación se aplican sólo a este enfoque alternativo: name (optativo. character. por defecto.Persistencia Relacional para Java Idiomático http://www. Vamos a describir una tercera manera. <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. También debe implementar Serializable.del. y otros países. Este tercer abordaje. La clase identificadora debe reemplazar equals() y hashCode() e implementar Serializable. yes_no. por defecto. discriminator (discriminador) El elemento <discriminator> se requiere para la persistencia polimórfica que use la estrategia de mapeo de "una tabla por cada jerarquía de clases" y declara una columna como el "discriminador" de la tabla. el tipo de propiedad determinado por reflexión): La clase componente usada como identificador compuesto (ver la sección siguiente). integer. A este enfoque lo llamamos "identificador compuesto incrustado (embedded)". aún más conveniente de enfocar el tema de los modificadores compuestos. tanto la clase del identificador compuesto.T): "Medicare" es el nombre en inglés del seguro estatal de salud en EE. pero requerido para un identificador compuesto mapeado): La clase usada como identificador compuesto. property): La estrategia que Hibernate debería usar para acceder al valor de las propiedades.UU.8. en donde el identificador compuesto es implementado como una clase componente en Sección 8. No hay otro "puntero" al objeto que no sea el objeto mismo. y lo desaconsejamos para cualquier aplicación seria.1. La columna "discriminador" contiene un valor rótulo. false): indica que se usa un identificador mapeado compuesto. boolean. Sólo un número restringido de tipos puede ser usado: string. MedicareId. access (optativo. short. La desventaja de este abordaje es obvia: duplicación de código. Se debe instanciar el objeto persistente mismo. Desafortunadamente. true_false. byte. un compoennte identificador. <composite-id class="MedicareId" mapped="true"> <key-property name="medicareNumber"/> <key-property name="dependent"/> </composite-id> (N.org/documentacion_es/castellano. es el que recomendamos para casi todas las aplicaciones. El segundo abordaje es lo que llamamos "identificador compuesto mapeado". class (optativo.hibernar. class (optativo. este abordaje de los identificadores significa que el objeto persistente es su propio identificador. “Componentes como identificadores compuestos”. y que los mapeos contenidos de propiedades se refieren tanto a la clase entidad como a la clase del identificador compuesto. .4.HIBERNATE . por defecto. pero obligatorio para este abordaje): Una propiedad de tipo "componente" que contiene el identificador compuesto (ver capítulo 9). como la clase de la entidad misma tienen propiedades llamadas medicareNumber y dependent. en donde las propiedades identificador usadas dentro del <composite-id> son duplicadas tanto en la clase persistente como en una clase identificadora separada. En este ejemplo.

El atributo force solamente es útil si la tabla contiene valores de discriminador "adicionales" que no están mapeados a una clase persistente. 'b'. <discriminator formula="case when CLASS_TYPE in ('a'. por defecto. por defecto. <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|.hibernar. false) "fuerza" a Hibernate a especificar valores permitidos de discriminador cuando captura todas las instancias de la clase raíz." /> (1) (2) (3) (4) (5) (6) (7) (1) column (optativo. true) asígnele false si su columna de discriminador tambíén forma parte de un identificador compuesto mapeado (le dice a Hibernate que no incluya a esta columna en el INSERT). el nombre de la propiedad): El nombre de la columna que contiene el número de versión. (5) formula (optativo) una expresión SQL arbitraria que se ejecuta cuando un tipo tiene que ser evaluado. propiedad.HIBERNATE . por defecto. timestampobtener el valor de la access (optativo. integer): El tipo del número de versión. string) un nombre que indica el tipo de Hibernate (3) force (optativo.Persistencia Relacional para Java Idiomático http://www.1.m. Éste no es casi nunca el caso. (4) Los números de versión pueden ser depropertydeLa estrategia que integer. se puede declarar una expresión SQL arbitraria que puede ser usada para evaluar el tipo de una fila. (2) name: El nombre de una propiedad de la clase persistente. 'c') then 0 else 1 end" type="integer"/> 5. Los verdaderos valores de la columna del discriminador son especificados por el atributo discriminator-value de los elementos <class> y <subclass>.html (1) column (optativo. por defecto. (4) insert (optativo. los tipos ): Hibernate long. por defecto. Permite discriminación basada en contenido. version (optativo) El elemento <version> element es optativo e indica que la tabla contiene datos con versión. . Usando el atributo formula. (3) type (optativo. class) el nombre de la columna del discriminador (2) type (optativo. short.9. Hibernate debería usar para o calendar. por defecto.org/documentacion_es/castellano. por defecto. 57 de 198 17/02/2009 09:25 a. Esto es particularmente útil si se planea usar transacciones largas (véase más abajo).

vm): ¿De dónde debería Hibernate obtener el valor de la timestamp? ¿De la base de datos. por defecto. . Las timestamps son. Declarar una propiedad versión o timestamp como anulable es un forma fácil de evitar problemas con la revinculación transitiva en Hibernate. the property name): el nombre de una columna que contiene la timestamp.1. (6) generated (optativo. porque Hibernate debe consultar la base de datos para determinar el "próximo" valor. unsaved-value (optativo. por defecto. por defecto. que no se sabe si todos los dialectos soportan esta obtención de timestamps de la base de datos.m. Note que <timestamp> equivale a <version type="timestamp">. por naturaleza. la aplicación podría usar timestamps de otras formas. por defecto. estilo JavaBeans. <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|.hibernar. (4) por defecto.html Una propiedad de versión o timestamp nunca debería ser nula para una instancia desprendida. property): La estrategia que Hibernate debería usar para acceder al valor de la propiedad. ¡especialmente útil para quienes usen identificadores asignados o claves compuestas! 5. que indica que una instancia ha sido recientemente instanciada (no grabada. (5) source (optativo.10. never): Especifica que esta propiedad timestamp en realidad es generada por la base de datos. Vea la discusión de propiedades generadas. timestamp (optativo) El elemento optativo <timestamp> indica que la tabla contiene datos marcados con fecha y hora. por ejemplo)." /> (1) (2) (3) (4) (5) (6) (1) column (optativo. De todos modos.HIBERNATE . (3) access (optativo. property El elemento <property> declara una propiedad pesistente de la clase.Persistencia Relacional para Java Idiomático http://www. Y <timestamp source="db"> equivale a <version type="dbtimestamp"> 5. o de la JVM actual? Las timestamps originadas en la base de datos son costosas. una implementación menos segura de "locking" optimista. (2) name: El nombre de una propiedad estilo JavaBeans del tipo Date o Timestamp de la clase persistente. <property name="propertyName" column="column_name" type="typename" (1) (2) (3) 58 de 198 17/02/2009 09:25 a. de manera que Hibernate pueda identificar cualquier instancia con una versión o timestamp nulos como transitoria. Esto apunta a ser una alternativa a asignar números de versión. "transitoria"). null): Una propiedad de versión.1. mientras que otros pueden ser inseguros de usar en "locking". Note también. sin importar qué otras estrategias de unsaved-value se hayan usado.11. distinguiéndola de una instancia desprendida. dada su falta de precisión (Oracle 8. pero serán más seguras en entornos de cluster.org/documentacion_es/castellano. que haya sido cargada o grabada por una sesión previa (undefined especifica que debería usarse el valor de la propiedad indentificadora).

por defecto. (8) unique (optativo): Habilita la generación del lenguaje de definición de datos (DDL) para una constraint única para las columnas.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|. cuyo valor es inicializado solamente por alguna otra propieadad que se mapea a la(s) misma(s) columna(s). por defecto. true): Especifica si las actualizaciones al valor de esta propiedad requieren o no un "lock" optimista. por defecto.Persistencia Relacional para Java Idiomático http://www. (10) optimistic-lock (optativo. .HIBERNATE .m. determina si pueden ocurrir incrementos de versión cuando la propiedad está "sucia". false): Especifica que esta propiedad debería ser obtenida de manera haragana. insert (optativo." 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. Asignarles false a las dos permite una propiedad puramente "derivada".org/documentacion_es/castellano. true) : indica que las columnas mapeadas deben ser incluidas en los comandos SQL UPDATE y/o INSERT. También puede especificarse con elemento(s) <column> anidados. (4) update. (5) formula (optativo): una expresión SQL que define el valor de una propiedad computada. En otras palabras. (6) access (optativo. Las propiedades computadas no tienen un mapeo de columna propio. (7) lazy (optativo. (2) column (optativo. También permite que esto sea apuntado por una property-ref. u otra aplicación. por defecto. por defecto.hibernar. o por un trigger. cuando se acceda por primera vez a la variable de instancia (requiere implementación bytecode en tiempo de ejecución). com una letra minúscula inicial. never): Especifica que el valor de esta propiedad es en realidad generado por la 59 de 198 17/02/2009 09:25 a. (3) type (optativo): un nombre que indica el tipo de Hibernate. (9) not-null (optativo): Habilita la generación del lenguaje de definición de datos (DDL) para una constraint de nulabilidad para las columnas. por defecto. (11) generated (optativo. property): La estrategia que Hibernate debería usar para acceder al valor de esta propiedad. the property name): el nombre de la columna de la tabla en la base de datos mapeada.

Clob). por definición.TIMESTAMP. Las propiedades derivadas son una característica especialmente poderosa. o para especificar un tipo hecho a medida). usando reflexión.Persistencia Relacional para Java Idiomático http://www. object.hibernate. customerId).MiTipoPersonalizado). float. 5. También note que puede usar elementos <formula> anidados si no le gusta especificar el valor como un atributo.productId AND li. El nombre de un tipo de Java hecho a medida (por ejemplo. <property name="totalPrice" formula="( SELECT SUM (li.customerId = customerId AND li. java.HIBERNATE .quantity*p. evitando usar el alias para una columna en particular (en el ejemplo. <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|.1.lang.sql. El nombre de una clase de Java serializable. serializable. aún se necesita el atributo type (por ejemplo. Product p WHERE li. para adivinar el tipo Hibernate correcto. blob).lang.productId = p.html base de datos.String. Hibernate intentará interpretar el nombre de la clase devuelta por el método "getter" de la propiedad. Hibernate usará reflexión en la propiedad nombrada. typename puede ser: El nombre de un tipo básico de Hibernate (por ejemplo integer. nombrando una clase que implemente la interfaz org.price) FROM LineItem li. Si usted especifica access="field". para distinguir entre Hibernate. string. Son computadas en el momento en que se cargan.mipaquete. java. Hibernate invocará al par get/set. usando las reglas 2. com.util. 3 y 4." 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. binary. El modelo relacional es una asociación de-muchos-a-uno: la clave foránea en una tabla se refiera a la(s) columna(s) clave de la tabla de destino. java. float. many-to-one Una asociación común con otra clase persistente se declara usando un elemento many-to-one element.property. timestamp.org/documentacion_es/castellano. Hibernate salteará el par get/set y accederá al campo directamente.orderNumber = orderNumber )"/> Note que usted se puede referir a la tabla misma de la entidad.PropertyAccessor. Se declara dicha computación como un comando SQL. que se traduce en una subconsulta SELECT en el código SQL que carga la instancia. en ese orden.Integer. date. java.DATE e Hibernate. .12.Date.hibernar. Por defecto. esto no siempre es suficiente. character.m. El nombre de una clase de Java con un tipo básico por defecto (por ejemplo int. Estas propiedades son de sólo lectura. Vea la discusión de propiedades generadas. El atributo access le permite controlar cómo Hibernate accederá a la propiedad en tiempo de ejecución. De todos modos. En algunos casos. char. Si no se especifica un tipo. Usted puede especificar su propia estrategia de acceso.

(6) update.HIBERNATE . (7) property-ref: (optativo) El nombre de una propiedad de una clase asociada que está ligada a esta clave foránea. determinado por reflexión): El nombre de la clase asociada (4) cascade (optativo): Especifica qué operaciones serán propagadas en cascada desde el objeto padre hacia los objetos asociados. efectivamente. (13) not-found (optativo. por defecto. de-uno-a-uno. determina si debería ocurrir un incremento de versión cuando esta propiedad esté "sucia".hibernar. (2) column (optativo): El nombre <column> anidados. (12) lazy (optativo. por defecto. por defecto. property): La estrategia que Hibernate debería usar para acceder al valor de la propiedad. En otras palabras. exception): Especifica cómo serán manejadas las claves foráneas que se refieran a filas ausentes. el tipo de la propiedad. (10) not-null (optativo): Habilita la generación de lenguaje de definición de datos (DDL) para la creación de una constraint de nulabilidad para las columnas de la clave foránea. .html unique_key="unique_key_id" foreign-key="foreign_key_name" /> (1) name: El nombre de la propiedad. por defecto. (5) fetch (optativo. por defecto. lazy="false" especifica que la asociación siempre será capturada de manera ansiosa ("eager" fetching). También permite que ésta sea el blanco referido por una property-ref. (9) unique (optativo): Habilita la generación de lenguaje de definición de datos (DDL) para la creación de una constraint única para la columna de clave foránea. de la columna de clave foránea. (11) optimistic-lock (optativo. o desde un trigger. cuyo valor es inicializado desde alguna otra propiedad. lazy="noproxy" especifica que el valor de la propiedad debe ser capturado en forma haragana. por defecto. por defecto. u otra aplicación. (8) access (optativo. También puede ser especificada por elementos (3) class (optativo.org/documentacion_es/castellano.m.Persistencia Relacional para Java Idiomático http://www. Asignarles false permite una propiedad puramente "derivada". proxy): Las asociaciones de extremo único están "proxied" por defecto. insert (optativo. Si no se especifica. 61 de 198 17/02/2009 09:25 a. cuando se acceda a la variable de instancia por primera vez (requiere instrumentación bytecode en tiempo de ejecución). true) especifica que las columnas mapeadas deben incluirse en el los comandos SQL UPDATE y/o INSERT. se usa la clave primaria de la clase asociada. ignore tratará dicha fila ausente como si fuera una asociación nula. Esto hace que la "multiplicidad" de la asociación sea. true): Especifica si las actualizaciones de esta propiedad requieren o no la adquisición de un "lock" optimista. select): Elije entre la captura (fetching) por outer-join y la captura por selección secuencial.

Una declaración many-to-one típica 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 foránea apunte a una clave única de la tabla asociada que no es la clave primaria. Si la clave única referida es la propiedad de un componente. replicate.13. Asignarle cualquier valor que tenga sentido al atributo cascade que no sea none propagará ciertas operaciones al objeto asociado.merge. que no es la clave primaria. persist. delete. Note que las asociaciones a un solo valor (de-muchos-a-uno y de-uno-a-uno) no soportan el borrado de huérfanos.delete-orphan".1. por ejemploc ascade="persist.HIBERNATE .hibernar. usted debería mapear las propiedades referidas dentro de un elemento llamado <properties>. merge. (El atributo unique controla en Hibernate la generación de DDL con la herramienta SchemaExport).11. . <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|. 62 de 198 17/02/2009 09:25 a. <property name="serialNumber" unique="true" type="string" column="SERIAL_NUMBER"/> Entonces.Persistencia Relacional para Java Idiomático http://www. refresh. esto se desaconseja. Los valores que tienen sentido son las operaciones básicas de Hibernate. “Persistencia transitiva” para una explicación completa." 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. save-update. así como los valores especiales delete-orphan y all. Vea la Sección 10.org/documentacion_es/castellano. lock. se puede especificar un "path de propiedades": <many-to-one name="owner" property-ref="identity. Por ejemplo.m. evict.html (14) entity-name (optativo): El nombre de entidad de la clase asociada. Éste es un modelo relacional feo. el mapeo para OrderItem podría usar: <many-to-one name="product" property-ref="serialNumber" column="PRODUCT_SERIAL_NUMBER"/> De todos modos.evict" o cascade="all. (15) formula (optativo): una expresión SQL que define el valor de una clave foránea computada. suponga que la clase Product class tiene un número de serie único.ssn" column="OWNER_SSN"/> 5. Si la clave única referida comprende múltiples propiedades de la entidad asociada. one-to-one Una asociación de-uno-a-uno a otra clase persistente se declara usando el elemento one-to-one. y combinaciones de nombres de operacion separados por comas.

asociaciones por clave foránea única. lazy="noproxy" especififica que la propuedad debe ser capturada en forma haragana cuando se accede a la variable de instancia por primera vez (requiere instrumentación bytecode de tiempo de ejecución). por defecto. (9) lazy (optativo. se puede especificar alguna otra columna o expresión con la cual asociarla usando una fórmula SQL.hibernate. <one-to-one name="person" class="Person"/> <one-to-one name="employee" class="Employee" constrained="true"/> Ahora. property): La property-ref: (optativo) estrategia que Hibernate debe usar para acceder al valor de la propiedad. lazy="false" especifica que á asociación será siempre capturada de forma "ansiosa" (eager fetching). agréguele los siguientes mapeos a Employee y Person. debemos asegurarnos de que las claves primarias de las filas relacionadas en las tablas PERSON y EMPLOYEE son iguales. si dos filas están relacionadas por esta asociación. entonces las dos filas en las respectivas tablas comparten el mismo valor de clave primaria. y determina si la asociación puede generar "proxies" (también es usada por la herramienta de exportación de esquema de base de datos).onetooneformula por un ejemplo). por defecto. proxy): Por defecto. se usa la clave primaria de la clase asociada. las asociaciones de extremo único usan proxies.m. por defecto. Si no se especifica. En el raro caso de que no sea así. por defecto. Hay dos variantes de asociación de-uno-a-uno: asociaciones por clave primaria. (6) El nombre de una propiedad de la clase asociada que está asociada a la clave primaria de esta clase. ¡Así que si usted quiere que dos objetos estén relacionados por la misma asociación de clave primaria. Usamos una estrategia especial de Hibernate para asegurarnos de que las claves primarias de filas relacionadas sean iguales: un a estrategia de generación de identificador llamada foreign: 63 de 198 17/02/2009 09:25 a. ¡Note que si se usa constrained="false". determinado por reflexión): El nombre de la clase asociada. (5) fetch (optativo. usar proxies es imposible e Hibernate siempre capturará en forma ansiosa! (10) entity-name (optativo): El nombre de entidad de la clase asociada. (3) cascade (optativo) especifica qué operaciones deben ser propagadas en cascada desde el objeto padre hacia el objeto asociado.html (2) class (optativo. (4) constrained (optativo) especifica que una constraint de clave foránea a la clave primaria de la tabla mapeada apunta a la tabla de la clase asociada. (8) formula (optativo): Casi todas las asociaciones de-uno-a-uno se mapean a la clave primaria de la entidad a la que pertenecen. (vea org.org/documentacion_es/castellano. select): Elige entre captura por outer-join y captura por selección secuencial. Esta opción afecta el orden en que save() y delete() son propagadas en cascada. (7) access (optativo.hibernar. el tipo de la propiedad. tiene que asegurarse de que se les asigne el mismo valor de identificador! Para una asociación por clave primaria.test.Persistencia Relacional para Java Idiomático http://www. Las asociaciones por clave primaria no necesitan una columna extra en la tabla.HIBERNATE . respectivamente. .

</natural-id> Aunque recomendamos el uso de clave sustitutas como claves primarias. Si también es inmutable. false): Por defecto..... component. 5. .m.15. /> . mutable (optativo. 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.... Recomentamos fuertemente que implemente equals() y hashCode() para comparar las propiedades de la clave natural de la entidad.. Los componenes a su vez pueden declarar sus propias propiedades. Este mapeo no debería usarse con entidades para las cuales la clave primaria es la clave natural. mejor todavía. por defecto.." > <property . /> .HIBERNATE ..... puede expresarse como: <many-to-one name="person" class="Person" column="PERSON_ID" unique="true"/> Y esta asociación puede ser convertida en bidireccional agregando lo siguiente al mapeo de Person: <one-to-one name="employee" class="Employee" property-ref="person"/> 5. Una clave natural es una propiedad o combinación de propiedades que sea única y no nula.org/documentacion_es/castellano.Persistencia Relacional para Java Idiomático http://www. Vea "Componentes" a continuación. <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|.html <class name="person" table="PERSON"> <id name="id" column="PERSON_ID"> <generator class="foreign"> <param name="property">employee</param> </generator> </id> .1. <one-to-one name="employee" class="Employee" constrained="true"/> </class> Entonces...... natural-id <natural-id mutable="true|false"/> <property ... dynamic-component El elemento <component> mapea propiedades de un objeto hijo a columnas de la tabla de la clase padre./> <many-to-one ... /> <many-to-one . componentes o colecciones..hibernar.. una clave foránea que apunte a una constraint única de Employee a Person.14..1. </component> (1) (2) (3) (4) (5) (6) (7) (8) 64 de 198 17/02/2009 09:25 a. propiedades identificador naturales que asume son inmutables (constantes). y su mapeo quedará más auto-documentado. aún se deberían identificar claves naturales para todas las entidades. Mapee las propiedades de la clave natural dentro del elemento <natural-id>. e Hibernate generará las constraints necesarias de unicidad y nulabilidad.

hibernar. /> . También es una manera conveniente de definir una constraint de unicidad. true): Especifica si las actualizaciones de este componente requieren o no la adquisición de un "lock" optimista. de algunas propiedades de una clase. por defecto.. véase Sección 8... por defecto.Persistencia Relacional para Java Idiomático http://www. . false): Especifica que este componente debería ser capturado en forma haragana (lazy fetching) cuando se acceda a la variable de instancia por primera vez (requiere implementación bytecode en tiempo de ejecución). properties El elemento <properties> permite la definición de un agrupamiento lógico. El elemento <component> acepta un subelemento <parent> que mapea una propiedad del componente como una referencia que apunta de vuelta a la entidad contenedora. 65 de 198 17/02/2009 09:25 a. es que permite que una combinación de propiedades sea el blanco de un property-ref.. por defecto...org/documentacion_es/castellano..16. La utilidad más importante de este tipo de construcción. en donde el nombre de la propiedad se refiere a claves del mapa.... el tipo de la propiedad. </properties> (1) (2) (3) (4) (5) (1) name: El nombre lógico del agrupamiento ( no es un nombre de propiedad real). (7) optimistic-lock (optativo.. El elemento <dynamic-component> permite que un Map sea mapeado como componente.5. determina si debería haber un incremento de versión cuando la propiedad esté "sucia" (8) unique (optativo.. (3) insert: ¿Aparecen las columnas mapeadas en los SQL INSERTs? (4) update: ¿Aparence las columnas mapeadas en los SQL UPDATEs? (5) access (optativo.html (1) name: El nombre de la propiedad (2) class (optativo.. determinado por reflexión): El nombre de la clase componente (hija). por defecto..m. false): Especifica que existe una constraint de unicidad sobre todas las columnas mapeadas del componente. property): La estrategia que Hibernate debería usar para acceder al valor de la propiedad. (6) lazy (optativo.HIBERNATE . <properties name="logicalName" insert="true|false" update="true|false" optimistic-lock="true|false" unique="true|false" > <property . “Componentes dinámicos”. En otras palabras. por defecto./> <many-to-one . con un nombre. 5. Las propiedades <property> hijas mapean propiedades de la clase hija a columnas de la tabla.1.

. </subclass> (1) (2) (3) (4) (1) Cada subclase debería declara sus propias propiedades subclase. si tenemos el siguiente mapeo de <properties>: <class name="Person"> <id name="personNumber"/> .1.17. Cada subclase en la jerarquía debe definir un valor único de discriminator- 66 de 198 17/02/2009 09:25 a. <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 . (5) unique (optativo. la persistencia polimórfica requiere la declaracíón de cada subclase de la clase persistente raíz. por defecto.HIBERNATE . excepto en el contexto de un mapeo a datos anticuados/heredados. Para la estrategia de mapeo una-tabla-por-clase. <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.org/documentacion_es/castellano.. por defecto. Por ejemplo.. .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. 5. que se refiera a esta clave única de la tabla Person table.. se usa la declaración <subclass>. true): Especifica si las actualizaciones de esta propiedad requieren o no la adquisición de un "lock" optimista. en lugar de a la clave primaria.. En otras palabras..hibernar. false): Especifica que existe un constraint de unicidad sobre todas las columnas mapeadas del componente. /> . <properties name="name" unique="true" update="false"> <property name="firstName"/> <property name="initial"/> <property name="lastName"/> </properties> </class> Y entonces podemos tener una asociación de datos al estilo anticuado. determina si debería ocurrir un incremento de versión cuando esta propiedad esté "sucia". subclass Finalmente. Se asume que las propiedades <version> name: El nombre (enteramente calificado) de la persistentes e <id> serán heredadas de la clase raíz. y subclases..m.Persistencia Relacional para Java Idiomático http://www...

El mapeo del comienzo del capítulo sería rescrito así: <?xml version="1. <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 .0. </joined-subclass> (1) (2) (3) (4) (1) name: El nombre enteramente calificado de la subclase. . 5. se usa el nomre enteramente calificado de la clase de Java.sourceforge. (3) proxy (optativo): Especifica una clase o interfaz a usar para la inicilización haragana de proxies.html value...hibernar. Sin embargo. Mapeo de Herencia..m.HIBERNATE .net/hibernate-mapping-3. por defecto. > <property ..0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD//EN" "http://hibernate. Para esta estrategia de mapeo no se requiere ninguna columna discriminadora.. vea Capítulo 9...1.org/documentacion_es/castellano. (2) table: El nombre de la tabla de la subclase. joined-subclass Alternativamente. /> . El estado heredado se captura haciendo un "join" con la tabla de la superclase.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. Usamos el elemento <joined-subclass>.. Para información sobre el mapeo de herencias..18. cada subclase puede ser mapeada a su propia tabla (la estrategia de mapeo "una-table-por-subclase"). cada subclase debe declarar una columna de tabla que contenga al identificador de objeto.Persistencia Relacional para Java Idiomático http://www. true): Asignar lazy="false" inhabilita el uso de captura haragana (lazy fetching). usando el elemento <key>.. Si no es especificado ninguno. (4) lazy (optativo.

(la estrategia de "una-tablapor-clase-concreta").hibernar.m.1. . 5.. Mapeo de Herencia.org/documentacion_es/castellano. si desea usar asociaciones polimórficas (por ejemplo.. (3) proxy (optativo): Especifica una clase o interfaz a usar para la inicilización haragana de proxies.acá podría ir el mapeo de Dog --> </class> </hibernate-mapping> Para información sobre los mapeos de herencias. vea Capítulo 9. Mapeo de Herencia.19. </union-subclass> (1) (2) (3) (4) (1) name: El nombre. De todos modos. 5. (4) lazy (optativo. join Usando el elemento <join>.Persistencia Relacional para Java Idiomático http://www. simplemente. Para esta estrategia de mapeo no se requiere una columna discriminadora. de la subclase. cuando hay una relacion de-uno-a-uno entre dichas tablas. <join 68 de 198 17/02/2009 09:25 a..HIBERNATE ..20.. En Hibernate.1. (2) table: El nombre de la tabla de la subclase. es necesario usar un mapeo con <union-subclass>. no es absolutamente necesario mapear dichas jerarquías de herencia... mapear cada clase con una declaracíón separada de <class>. Se puede. por defecto. /> . vea Capítulo 9. union-subclass Una tercera opción es mapear a tablas sólo las clases concretas de la jerarquía de herencias. true): Especificar lazy="false" inhabilita el uso de captura haragana (lazy fetching). una asociación a la superclase de su jeraquía).Dog"> <!-. incluido el estado persistente. Para información sobre los mapeos de herencias. enteramente calificado. es posible mapear propiedades de una clase a varias tablas.html <property name="name" type="string"/> </joined-subclass> </class> <class name="eg. <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 . en la cual una tabla define todo el estado persustente de la clase.

al nombre del esquema de base de datos especificado en el elemento raíz (3) catalog (optativo): Suplanta <hibernate-mapping>. (5) inverse fetch (optativo. una clase Dirección dentro de una clase Persona. etc) directamente en Persona. entonces Hibernate usará una asociación secuencial definida en una subclase. en lugar de incluir los campos de la direccíón (calle..m.org/documentacion_es/castellano. Los INNER JOINS aún serán usados para capturar asociaciones definidas por la clase y sus superclases.. (6) optional (optativo. se considera que una representación jerárquica que use las clases Persona y Dirección es más "detallada" que la simple tabla PERSONA subyacente 69 de 198 17/02/2009 09:25 a. por ejemplo.. Si se le asigna el valor select. número. join): Si se (optativo. Esta característica es a menudo sólo útil para modelos de datos anticuados.</id> <join table="ADDRESS"> <key column="ADDRESS_ID"/> <property name="address"/> <property name="zip"/> <property name="country"/> </join> . /> <property ...HIBERNATE . Hibernate usará un INNER JOIN para capturar una asociación definida por una clase en su superclase. por defecto. la cual sólo será emitida cuando ocurra que una fila represente una instancia de la subclase. y un modelo de dominio bien detallado. por defecto. /> .hibernar.html table="tablename" schema="owner" catalog="catalog" fetch="join|select" inverse="true|false" optional="true|false"> <key .. Hibernate insertará una nueva fila sólo si las propiedades definidas por esta asociación son no nulas. por defecto..: se les suele llamar "detallados" (en inglés "fine-grained") a los modelos con clases que contiengan otras clases como miembro. la información de la dirección de una perosna puede ser mapeada en una tabla separada. Por ejemplo. y utilizará un OUTER JOIN para una asociación definida por una subclase. N. Hibernate no intentará insertar o acualizar las propiedades definidas por esta asociación. false): Si se habilita. y siempre usará un OUTER JOIN para capturar las propiedades. . </join> (1) (2) (3) (4) (5) (6) (1) table: El nombre de la tabla asociada. Aunque los campos de Dirección probablemente se terminen persistiendo en la misma tabla que los de Persona... false): Si se habilita. Recomendamos que haya menos tablas que clases. al tiempo que se preserva la semántica para todas las propiedades.del T. <class name="Person" table="PERSON"> <id name="id" column="PERSON_ID">.. (2) schema (optativo): Suplanta <hibernate-mapping>.Persistencia Relacional para Java Idiomático http://www. al nombre del catálogo de base de datos especificado en el elemento raíz (4) le asigna el valor pr defecto join.

Los atributos not-null y update son útiles cuando se mapea una asociación de-uno-a-muchos unidireccional. en lugar de varios comandos DELETE individuales. .html De todos modos. (3) property-ref (optativo): Especifica que la clave foránea se refiere a columnas que no son la clave primaria de la tabla original. key Hemos visto surgir el elemento <key> varias veces ya. De la misma manera. el elemento <formula> es una alternativa al atributo formula. Aparece cada vez que el mapeo de un elemento padre define una asociación a una nueva tabla.Persistencia Relacional para Java Idiomático http://www. Esto también puede ser especficado por elementos (2) on-delete (optativo. <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.22.HIBERNATE . elementos column y formula Cualquier elemento de mapeo que acepte un atributo column aceptará.m. 5. hay que declarar la columa clave usando <key not-null="true">. e Hibernate generará una constraint ON CASCADE DELETE a nivel de la base de datos. que haga referencia a la clave primaria de la tabla original.org/documentacion_es/castellano. noaction): Especifica si la constraint de clave foránea tiene habilidtado el borrado en cascada a niver de la base de datos. como se explica más adelante. Si la mapea a una clave foránea no anulable. (provisto para datos anticuados/heredados solamente).21. "join-table" es útil para alternar entre distintas estrategias de mapeo en una misma jerarquía. un subelemento <column>. toda las claves sean definidas con on-delete="cascade". para sistemas en los cuales la performance de delete sea importante. alternativamente. por defecto. <column name="column_name" length="N" precision="N" scale="N" not-null="true|false" 70 de 198 17/02/2009 09:25 a.1. de la columna de clave foránea.1. (4) not-null (optativo): Especifica que las columnas de la clave foránea no son anulables (lo cual se sobreentiende cuando la clave foránea es también parte de la clave primaria) (5) update (optativo): Especifica que la clave foránea nunca debería ser actualizada (lo cual se sobreentiende cuando la clave foránea es también parte de la clave primaria) (6) unique (optativo): Especifica que la clave foránea debería tener una constraint de unicidad (lo cual se sobreentiende cuando la clave foránea es también la clave primaria). Tenga presente que esta característica saltea la estrategia usual de locking optimista para datos versionados.hibernar. Recomendamos que. 5.

. codiciones de asociación exóticas. La primera columna contiene el tipo de la entidad asociada.m.23.Persistencia Relacional para Java Idiomático http://www.1. Usted puede incluso importar clases e interfaces que no estén mapeadas explícitamente. etc). (2) rename (optativo.hibernar. <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. para expresar. las cuales tendrán propiedades indentificadoras del tipo identificado por id-type. El atributo meta-type le permite a la aplicación especificar un tipo hecho a medida. Es imposible especificar una constraint de clave foránea para este tipo de asociaciones. logs de auditoría. por ejemplo. <import class="java.1.Object" rename="Universe"/> <import class="ClassName" rename="ShortName" /> (1) (2) (1) class: The fully qualified class name of of any Java class. por defecto. Las clases pueden ser "importadas" explícitamente en lugar de tener que confiar en el auto-import="true". y usted no quiere especificar un nombre de clase enteramente calificado (con el paquete) en las consutas de Hibernate. any Hay un tipo más de mapeo de propiedad: El elemento de mapeo <any> define una asociación polimórfica a clases de múltiples tablas. Esto se debería usar sólo en casos muy especiales (por ejemplo.24.lang. que mapeará valores de columna en la base de datos a clases persistentes.HIBERNATE . 5. Este tipo de mapeo siempre requiere más de una columna. datos de sesión de usuario.org/documentacion_es/castellano. <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. import Supongamos que su aplicación tiene dos clases persistenes con el mismo nombre.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 asociación. Se debe especificar el mapeo desde los valores valores del meta-tipo a los nombres de las clases. the unqualified class name): A name that may be used in the query language.

string): Cualquier tipo que sea permisible para mapear un discriminador. /> . ser una entidad en general implica que varios otros objetos compartirán referencias a ella. sin embargo. </any> (6) (1) name: el nombre de la propiedad..HIBERNATE . Tipos de Hibernate 5. que consiste en la persistencia de objetos basada en la capacidad de acceder a ellos. "entity") existe independientemente de que cualquier otro objeto tenga o no referencias a ella. ni entre colecciones. no lo que está dentro de ellas). por defecto. y por lo tanto no pueden ser compartidos entre dos o más entidades. (2) id-type: el tipo del identificador.. El estado persistente de una entidad consiste en referencias a otras entidades. No tienen "identidad" independiente. La diferencia es que estos "componentes" tienen la semántica de un "value type". /> <meta-value . property): La estrategia que Hibernate debería usar para acceder al valor de la propiedad.. (6) optimistic-lock (optativo... Una clase definida por el usuario puede ser. necesitamos clasificarlos en 2 grupos: Una entidad (en inglés. (3) meta-type (optativo. true): Especifica si las actualizaciones de esta propiedad requieren o no la adquisición de un "lock" optimista. definida por el usuario. pero. en donde un objeto sufre "garbage colection" en cuanto dejan de referirse a él.m. un "componente" (en inglés. las colecciones (el componente colección en sí. y pueden ser versionadas. a criterio del programador de la aplicación. por defecto none): el estilo de propagación en cascada (5) access (optativo.2. por defecto. determina si debería ocurrir un incremento de versión cuando esta propiedad esté "sucia". component) también es una clase. que es persistente. (4) cascade (optativo. Hasta ahora hemos usado el término "clase persistente" para referirnos a entidades. <column . Los "value types" son los tipos primitivos.1. /> ...org/documentacion_es/castellano. mientras que los "value types" simplemente forman parte de una única clase. Entidades y "value types" Para comprender el comportamiento de varios objetos (a nivel del lenguaje Java) con respecto al servicio de persistencia. o un tipo definido por el usuario. sino que son persistidos junto con la entidad que los contiene...... Un "value type" puede ser. En un modelo de dominio. y ciertos objetos inmutables. o una String.html optimistic-lock="true|false" > <meta-value . Los "value types" no pueden ser grabados ni versionados independientemente.. Lo seguiremos haciendo.Persistencia Relacional para Java Idiomático http://www. En otras palabras.. un "value type" o una entidad. Las entidades soportan referencias compartidas y circulares. "composition" y "aggregation").. Éste es un tipo distinto de manejo de objetos de datos (ODMG. Las entidades deben ser grabadas y borradas explícitamente (excepto cuando los borrados o grabaciones en cascada se transmiten de padre a hijos). y a instancias de lo que en Hibernate se denomina "value types" (tipos "valor"). 5. por defecto. 72 de 198 17/02/2009 09:25 a.hibernar. vía composición o agrupación (en inglés. /> <column . Contraste esto con el modelo de Java normal.. .. por sus siglas en inglés). estrictamente hablando.2.. un tipo primitivo de la JDK. entonces. no la de una entidad. lo cual corresponde más íntimamente con cómo los objetos de una aplicación son usados en sistemas grandes.

boolean.Persistencia Relacional para Java Idiomático http://www. <component>. java. short. como veremos más adelante. calendar_date Mapeos de tipo de java.org/documentacion_es/castellano. yes_no.String a VARCHAR (o el VARCHAR2 de Oracle). Todos los tipos que vienen ya incluidos en Hibernate. El puente entre ambos sistemas es provisto por Hibernate. excepto las colecciones. El valor de este atributo es uno de los tipos para mapeo de Hibernate.Locale.hibernar. timezone.util. Estos tipos pueden ser inconvenientes para algunas aplicaciones.util.BigDecimal y java. También se puede indicar el tipo de Hibernate serializable con el nombre de una clase o interfaz serializable de Java.Boolean de Java. .lang.sql. text Mapea cadenas largas de Java los tipos CLOB o TEXT de SQL.util. binary Mapea arrays de bytes a un tipo SQL binario apropiado. (Más 73 de 198 17/02/2009 09:25 a. 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.2.Clob y java. soportan la semántica de nulo.lang.math. <subclass> y así sucesivamente. date. calendar. timestamp Mapeos de tipo de java.lang.Currency a VARCHAR (o el VARCHAR2 de Oracle).HIBERNATE .html Retomaremos estos conceptos todo a lo largo de la documentación. "Value types" básicos Los tipos de mapeo básicos ya incluidos pueden ser someramente clasificados en: integer. class Un mapeo de tipo java. Hibernate trae varios mapeos (para los tipos estándar de la JDK) ya incluidos. Pero usted puede escribir sus propios tipos para mapeo e implementar sus propias estrategias de conversión. etc.2. que no sea por defecto un tipo básico.Calendar a tipos SQL TIMESTAMP y DATE (o equivalente). Las instancias de TimeZone son mapeadas a su ID. Para las entidades proveemos <class>.TimeZone y java. serializable Mapea tipos serializables de Java a un tipo SQL binario apropiado.Blob. time. string Un mapeo de tipo de java. locale. clob. 5. Las instancias de Locale y Currency son mapeadas a sus códigos ISO.m.BigInteger a NUMERIC (e el NUMBER de Oracle).util. El desafío es mapear el sistema de tipos de Java (junto con la definición del desarrollador de las entidades y "value types") a un sistema del tipo SQL/BD. TIME y TIMESTAMP (o equivalentes). Para los "value types" usamos <property>.Class a VARCHAR (o la VARCHAR2 de Oracle). double.util. normalmente con un atributo type. long. blob Mapeos de tipo para las clases JDBC java..Date y sus subclases a tipos SQL DATE.sql. Una Class es mapeada con su nombre enteramente calificado. float. byte. big_integer Mapeos de tipo de java. dado que los objetos clob y blob no pueden ser reusados fuera de una transacción. currency Mapeos de tipo de java.math. character. big_decimal. yes_no y true_false son todas codificaciones alternativas de un boolean o un java.

String que sea persistida varias columnas.3.hibernate. imm_time. Para crear un tipo a medida. el soporte de drivers es esporádico e inconsistente).hibernate. imm_timestamp. Para lograr esto.ParameterizedType.hibernate. EnhancedUserType. Los "value types" básicos tienen constantes Type definidas en org. y la aplicación trata al objeto como inmutable. Esto se puede hacer usando el elemento <typedef>.DoubleStringType"> <column name="first_string"/> <column name="second_string"/> </property> Note el uso de los elementos <column> para mapear una sola propiedad a múltiples columnas.hibernate. imm_date.mycompany. Hibernate no trae un tipo ya incluido para esto.hibernar. APELLIDO.html aún. es relativamente fácil crear sus propios "value types". y UserVersionType poveen soporte para usuarios más especializados. Por ejemplo: para una instancia mapeada como imm_timestamp.lang. <property name="priority"> <type name="com. blob y (Los identiicadores compuestos también están permitidos. la aplicación tiene que asignarle un nuevo objeto (no idéntico) a la propiedad. Los "typedefs" le asignan un nombre a un tipo a medida. Por ejemplo. usted puede tener una propiedad Java con métodos getNombre()/setNombre() de tipo java. clob. Incluso se le pueden proveer parámetros a un UserType en el archivo de mapeo. INICIAL_DEL_SEGUNDO. 5.usertypes. UserCollectionType.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. Si se usa un objeto UserType muy a menudo. implemente org.setTime(). Para proveerle parámetros a su tipo a medida.DoubleStringType para comprobar el tipo de cosas que es posible hacer.Persistencia Relacional para Java Idiomático http://www.test.STRING representa el tipo string. imm_calendar. Por ejemplo.hibernate.lang.test. Pero los tipos a medida no solamente sirven para mapear una propiedad de Java (o un elemento colección) a una sola columna de una tabla.HIBERNATE .CompositeUserType y declare propiedades usando el nombre enteramente calificado del tipo.2. sería útil definirle un nombre corto. usted puede usar el elemento <type> en sus archivos de mapeo.hibernate. Para cambiar el valor de la propiedad (y hacer que ese valor cambiado sea persistido). ver más adelante). en los que Hibernate adopta ciertas optimizaciones que son sólo apropiadas para tipos inmutables de Java.DefaultValueIntegerType"> <param name="default">0</param> </type> </property> Ahora el UserType puede aceptar valrores para el parámetro llamado default con el objeto Properties que le fue pasado. como PRIMER_NOMBRE. Hibernate.BigInteger a columnas VARCHAR. Por ejemplo.usertypes.org/documentacion_es/castellano. <typedef class="com. Las interfaces CompositeUserType. Revise org.UserType o org. imm_binary Mapeos de tipo para lo que normalmente se considera "tipos mutables de Java". imm_calendar_date. usted podría querer persistir propiedades del tipo java. <property name="twoStrings" type="org. y pueden contener también una lista de parámetros por defecto si el tipo es parametrizado.Hibernate. imm_serializable. "Value types" hechos a medida Para los programadores. Los identificadores únicos de las entidades y colecciones pueden ser de cualquier tipo básico excepto binary. no se debería invocar Date. su UserType debe implementar la interfaz org.usertype.mycompany.

HIBERNATE - Persistencia Relacional para Java Idiomático

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

También es posible sustituir (override) los parámetros provistos en un typedef, caso por caso, usando parámetros de tipo en el mapeo de propiedades. Aunque la rica variedad de tipos ya incluidos en Hibernate hace que sólo 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 aplicación. Por ejemplo, una clase MonetaryAmount (suma de dinero) sería una buena candidata para un CompositeUserType, incluso si pudiere ser fácilmente mapeada como componente. Uno de los motivos para esto es abstracción. Con un tipo a medida como éste, sus documentos de mapeo serán a prueba de posibles cambios en la forma en que los valores monetarios se representaren en el futuro.

5.3. Mapear una misma clase más de una vez
Es posible proveer más de un mapeo para una clase persistente en particular. En tal caso, se debe proveer un nombre de entidad para desambigüar 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 cómo 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 inglés, "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 información de mapeo directamente en su código 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 Idiomático

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 Idiomático

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 más 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 compilación. Este mecanismo es más poderoso que las anotaciones XDoclet, y mejor soportado por las herramientas gráficas (IDE) como IntelluJ IDEA, muchas de las cuales proveen autocompleción y resaltado de sintaxis para anotaciones de JDK 5.0. La nueva revisión 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; // métodos Getter/setter, y de negocio ... }

Note que el soporte para anotaciones JDK 5.0 (y JSR-220) todavía es un trabajo en curso, incompleto. Por favor remítase al módulo de Anotaciones de Hobernate para más 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 aplicación 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 añadidura, las propiedades marcadas como generadas debe ser no insertables y e inmodifocables. Sólo 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 Idiomático

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 creación" entrarían en esta categoría. Note que, aunque las propiedades version y timestamp pueden ser marcadas como generadas, esta opción 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 ejecución de comandos CREATE y DROP arbitrarios para objetos de base de datos, en conjunción con las herramientas de evolución 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 específicamente 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 válido aquí: ALTERs, INSERTs, etc). Esencialmente, hay dos maneras de definir objetos de base de datos auxiliares: La primera es listar explícitamente 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 cómo 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 sólo 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>

Capítulo 6. Mapeo de colecciones 6.1. Colecciones persistentes
Hibernate requiere que los campos con valor de colección 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 Idiomático

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 cómo inicializamos la variable de instancia con una instancia de HashSet. Ésta es la mejor manera de inicializar propiedades con valor de colección, 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 implementación 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 colección 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 automáticamente persistidas cuando son referidas por un objeto persistente, y aumáticamente borradas cuando son "des-referidas". Si una colección 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 colección. Dado el modelo relacional subyacente, las propiedades con valor de colección no soportan la semántica de nulo. Hibernate no distingue entre una colección nula y una colección vacía. No vale la pena preocuparse mucho por nada de esto. Use las colecciones persistentes del mismo modo en que usaría las colecciones comunes de Java. Sólo asegúrese de comprender la semántica de las asociaciones bidireccionales (la cual se discute más 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 común. Le sugerimos que experimente con la herramienta de generación de esquemas de DB para tener una idea de cómo 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 colección 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>

Además de <set>, también están 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 Idiomático

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 colección

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

de la propiedad) el nombre de la tabla de la colección (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

raíz. (4)
lazy (optativo, por defecto, true) puede usarse para inhabilitar la "captura haragana" (lazy fetching) y especificar que la asociación es siempre capturada en forma "ansiosa" (eager fetching), o para especificar que la asociación es "súper-haragana", en donde la mayoría de las operaciones evitan inicializar la colección (prescrito para colecciones muy grandes).

(5)
inverse

(optativo, por defecto, false) marca esta colección como el extremo "inverso" de una asociación bidireccional.

(6)
cascade

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

(7)
sort (optativo)

especifica una colección 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 iteración del Map, Set o bag, junto con un asc o desc opcional (ascendente/descendente).

(9)
where (optativo)

especifica una condición SQL WHERE arbitraria, a ser usada ciando se capture o borre la colección (útil cuando la colección sólo 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)

6.2.1. batch-size (optativo,las colecciones Claves foráneas de por defecto, 1) especifica el "tamaño de lote" al capturar instancias de esta colección en
forma haragana.

80 de 198

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

los tipos a medida. mapeado con <map-key>. (2) <map-key-many-to-many formula (optativo): Una fórmula column="column_name" SQL usada para evaluar la clave del mapa (1) 81 de 198 17/02/2009 09:25 a. por defecto. 6.hibernar.3."/> (1) (1) column_name (obligatorio): El nombre de la columna que contiene el valor del índice de la colección. en el caso de referencias a entidades. La columna clave de la colección es mapeada por el elemento <key>. Los otros dos. El índice de un Map puede ser de cualqueira de los tipos básico. <key column="productSerialNumber" not-null="true"/> la constraint de clave foránea puede usar ON DELETE CASCADE. <key column="productSerialNumber" on-delete="cascade"/> Vea el capítulo correspondiente para una definición completa del elemento <key>. o puede ser una referencia a otra entidad.2. así que a veces es necesario especificar not-null="true". con <one-to-many> o <many-to-many>. Colecciones indexadas Todos los mapeos de colección. Esta es una distinción importante: un objeto en una colección puede ser manipulado con la semántica de "valor" (que todo su ciclo de vida dependa del dueño de la colección). La columna mapeada contiene enteros secuenciales (comenzando por cero.2.m. con su propio ciclo de vida. necesitan una columna índice en la tabla de la colección (una columna que mapea a un índice de una array). Para la mayoría de las colecciones. por supuesto. Puede haber constraints de nulabilidad en la columna de la clave foránea.Persistencia Relacional para Java Idiomático http://www..HIBERNATE . <list-index column="column_name" base="0|1|. <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 colección. Elementos de las colecciones Las colecciones pueden contener casi cualquier otro tipo de Hibernate.html Las instancias de colecciones se distinguen en la BD por la clave foránea que posee a la colección. o un índice de List. Para las asociaciones de-uno-a-muchos unidireccionales. o puede ser un tipo compuesto. sólo el "vínculo" entre ambos objetos es lo que se considera como estado almacenado por la colección. o. . puede ser una entidad mapeada con <map-key-many-to-many>. incluyendo todos los tipos básicos. 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 de la clave primaria es anulable por defecto. Al tipo contenido se lo refiere como al tipo del elemento de la colección. excepto los los que tengan semántica de set o de bag. esto está implícito. Los primeros dos.2. Los elementos de la colección son mapeados por <element> o <composite-element>.. o una clave de un Map. se usan para mapear asociaciones de entidades. por defecto). 6. y. mapean elementos con la semántica de valor. Esta clave foránea se denomina columna (o columnas) clave de la colección en la tabla de la colección.org/documentacion_es/castellano. (1) base (optativo. referencias a otras entidades. En este último caso. componentes. 0): El valor de columna índice correspondiente al primer elemento de la lista o array.

posiblemente. Una bag (bolsa) no retiene su orden cuando es obtenida de la base de datos.hibernar.html formula="any SQL expression" class="ClassName" /> (2)(3) (1) column (optativo): El nombre de la columna de clave foránea para los valores de índice de la colección. (2) formula (optativo): Una fórmula SQL usada para evaluar el elemento. Si su tabla no tiene una columna índice. (3) type (obligatorio): El tipo de elemento de colección Una asociación de-muchos-a-muchos (many-to-many) se especifica usando el elemento <many-to-many>. con una columna o columnas de clave foránea.HIBERNATE . pero puede ser opcionalmente ordenada. 6. Para una colección de valores. . <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. (3) class (obligatorio): La clase de entidad usada como clave primaria del mapa.4. una columna o columnas para el elemento de la colección. pero usted aún desea usar una List como el tipo de propiedad. Colecciones de valores y asociaciones de-muchos-a-muchos Cualquier colección de valores o asociación de-muchos-a-muchos requiere una tabla de colección dedicada. <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 colección. y. usted debería mapear la propiedad como una <bag> de Hibernate. usamos la tag <element>.Persistencia Relacional para Java Idiomático http://www.m.org/documentacion_es/castellano. (2) formula (optativo): Una fórmula SQL usada para evaluar la clave foránea de la clave del mapa. una columna o columnas índice.2.

Si no se especifica. en la clase asociada que está ligada a esta clave foránea. (4) fetch (optativo. por defecto. . se usa la clave primaria de la clase asociada. Primero. algunos ejemplos. (2) formula (optativo): una fórmula SQL usada para evaluar el valor del elemento clave foránea (3) class (obligatorio): el nombre de la clase asociada.Persistencia Relacional para Java Idiomático http://www. <set name="names" table="person_names"> <key column="person_id"/> <element column="person_name" type="string"/> </set> Una bag conteniendo enteros. sino también en este atributo del elemento anidado <many-to-many>. join): permite capturas para esta asociación mediante un outer-join o un select secuencial. con un orden de iteración 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.html (1) column (optativo): el nombre de columna del elemento clave foránea. como una alternativa a class.HIBERNATE . É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.hibernar. Esto vuelve efectivamente "de-uno-a-muchos" la multiplicidad de la asociación. se debería habilitar la captura (fetch) de tipo join no solamente en la colección misma. por defecto. un conjunto de strings. ignore tratará la fila faltante como una asociación nula actuará cuando le falten filas a la clave (7) entity-name (optativo): el nombre de entidad de la clase asociada.org/documentacion_es/castellano.m. (5) unique (optativo): habilita la generación de lenguaje de definición de datos (DDL) para una constraint de unicidad en la columna de clave foránea. (8) property-ref: (optativo) el nombre de una propiedad. A continuación. (6) not-found (optativo. una asociación 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 más adelante): 83 de 198 17/02/2009 09:25 a. exception): Especifica cómo se foránea.

util. Una instancia de la clase-entidad contenida.Persistencia Relacional para Java Idiomático http://www. (3) entity-name (optativo): El nombre de la entidad asociada. por defecto.HIBERNATE .3.m. exception): especifica cómo se manejarán los identificadores en caché que estén refiriéndose a columnas perdidas. Una asociación de Product a Part (producto a parte) requiere la existencia de una clave foránea. y posiblemente una columna índice en la tabla Part. Vea la discusíón sobre asociaciones bidireccionales más adelante en este capítulo.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.5.1.util. Se debe especificar un comparador en el archivo de mapeo.SortedSet.2.hibernar. .org/documentacion_es/castellano. Note que el elemento <one-to-many> no necesita declarar ninguna columna.SortedMap y java. Nota muy importante: Si la columna de clave foránea de una asociación <one-to-many> se declara NOT NULL.3. Una tag <one-to-many> indica que ésta es una asociación de-uno-a-muchos. Este mapeo pierde algo de la semántica de las colecciones normales de Java. es una propiedad persistente de Part). no puede pertenecer a más de una instancia de la colección. <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. Colecciones ordenadas. ignore tratará la fila ausente como una asociación nula. Tampoco es necesatio especificar un nombre de tabla en ningún lado. Hibernate soporta colecciones que implementen java. como alternativa a class. Mapeos de colección avanzados: 6. se debe declarar el mapeo de <key> not-null="true" o usar una asociación bidireccional con el mapeo de la colección marcado como inverse="true". Este ejemplo muestra un mapa de entidades Part por nombre (donde el nombre de la parte. (2) not-found (optativo. partName. no puede aparecer en más de un valor de índice de la colección. <map name="parts" cascade="all"> <key column="productId" not-null="true"/> <map-key formula="partName"/> <one-to-many class="Part"/> </map> 6. 84 de 198 17/02/2009 09:25 a. porque: Una instancia de la clase-entidad contenida. Note el uso de un índice basado en una fórmula. Asociaciones de-uno-a-muchos Una asociación de-uno-a-muchos vincula las tablas de dos clases a través de una clave foránea. sin la intervención de una "tabla de colección".

TreeSet o java.. use el atributo order-by del mapeo de los mapeos de set.custom..TreeMap.m.2. bag o map. Las colecciones ordenadas en realidad se comportan como un java. Esto efectúa el ordenamiento en la consulta SQL.util.getUsers().hibernar. pero no puede ser una colección indexada).util.list(). Esta solución sólo se encuentra disponible bajo la JDK 1.3. y declarando uno de los extremos como inverse (cuál.4 o superior (se implementa usando LinkedHashSet o LinkedHashMap). 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. un valor simple en en otro extremo.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.createFilter( group.Comparator. Asociaciones bidireccionales Una asociación bidireccional (bidirectional association) permite navegar desde ambos "extremos" de la asociación. . He aquí un ejemplo de una asociación bidireccional de-muchos-a-muchos. 6. sortedUsers = s. no HQL! Las asociaciones pueden incluso ser ordenadas por algún criterio arbitrario en tiempo de ejecución. "order by this. Si quiere que la base de datos misma ordene los elementos de la colección. no en memoria. <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. <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.org/documentacion_es/castellano. es a elección. many-to-many (de-muchos-a-muchos) un set o una bag con valores en ambos extremos Se puede especificar una asociación bidireccional de-muchos-a-muchos simplemente mapeando dos asociaciones a la misma tabla de la base de datos.html <set name="aliases" table="person_aliases" sort="natural"> <key column="person"/> <element column="name" type="string"/> </set> <map name="holidays" sort="my.util.name" ). natural y el nombre de una clase que implemente java. usandp un filtro (filter()) de colección.HIBERNATE . Se soportan dos tipos de asociación bidireccional: one-to-many (de-uno-a-muchos) un set o una bag en un extremo.Persistencia Relacional para Java Idiomático http://www. cada categoría puede tener muchos items y cada ítem puede tener muchas categorías: <class name="Category"> <id name="id" column="CATEGORY_ID"/> .

..: un vínculo de A a B... <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"/> .org/documentacion_es/castellano. ¡Son conceptos ortogonales! 6.persist(item). <class name="Parent"> <id name="id" column="parent_id"/> . Esto significa que Hibernate tiene dos representaciones en memoria por cada asociación bidireccional.add(item). <!-..hibernar... Si existe una propiedad de la clase hija que mapee a la columna de índice.. // La categoría ahora "sabe" acerca de la relación // El ítem ahora "sabe" acerca de la relación // ¡La relación no será grabada! // La relación sí será grabada El lado no-inverso se usa para grabar en la base de datos la representación en memoria.getItems(). Esto es más fácil de entender si se piensa en el modelo de objetos Java y cómo se crea una relación de-muchos-a-muchos en Java.. Una asociación bidireccional en donde un extremo esté representado como una <list> o un <map>necesita algunas consideraciones especiales. Se puede definir una asociación bidireccional de-muchos-a-muchos mapeando un a asocíación de-uno-a-muchos a la(s) misma(s) columna(s) de la tabla que una asociación de-muchos-a-uno..m.. <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. session. no hay problema.. item.. no son persistidos. <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"/> . y otro vínculo de B a A. <class name="Parent"> <id name="id" column="parent_id"/> .add(category). <many-to-one name="parent" class="Parent" column="parent_id" not-null="true"/> </class> Mapear uno de los extremos de la asociación con inverse="true" no afecta las propagaciones en cascada. category. session...html <id name="id" column="ITEM_ID"/> . Asociaciones bidireccionales con colecciones indexadas.persist(category). y poniendo inverse="true" en el el extremo 'muchos'.Persistencia Relacional para Java Idiomático http://www. podemos continuar usando inverse="true" en el mapeo de la colección.getCategories().HIBERNATE .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 sólo al extremo inverso de la asociación.3.3.

3. y de que las entidades debe tener identidicadores "sintéticos" (claves sustitutas). El elemento <idbag> le permite mapear una List (o Collection) con semántica 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. <many-to-one name="parent" class="Parent" column="parent_id" insert="false" update="false" not</class> Note que en este mapeo.m.3.Persistencia Relacional para Java Idiomático http://www. podemos usar el siguiente mapeo. . Éste es el enfoque que se usa más comúnmente. es usar elementos compuestos. Uno es usar un Map con la asociación 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 asociación como una clase de entidad.. <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"/> . 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. En este caso. no podemos mapear la colección con inverse="true". En lugar de eso.html Pero si tal propiedad no existe en la clase hoja. el extremo con la colección es el responsable de las actualizaciones de la clave foránea.4. Asociaciones ternarias Hay tres abordajes posibles para mapear asociaciones ternarias. Hibernate provee un mecanismo que permite mapear asociaciones de-muchos-a-muchos y colecciones de valores a una tabla con clave sustituta. 6. A HACER: ¿esto resulta realmente en la ejecución de UPDATES innecesarios? 6.org/documentacion_es/castellano..hibernar... De todos modos... Usar una <idbag> Si usted está totalmente convencido de que las claves compuestas son una cosa mala. no podemos concebir la asociación como verdaderamete bidireccional (hay información disponible en un extremo que no lo está en el otro extremo).5.HIBERNATE . Una tabla que sea puramente "de asociación" no se beneficia mucho con la existencia de una clave sustituta (aunque una colección de valores compuestos sí podría). lo cual se discute más adelante. Una última alternativa. <class name="Parent"> <id name="id" column="parent_id"/> .

.4.. private Set children.util. } private void setId(long id) { this. import java. 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. el identificador native como estrategia de generación de identificadores no se soporta para las <idbag>s. el mapeo más natural es una asociación 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. Hibernate no provee ningún mecanismo para descubrir el valor de la clave sustituta de una fila en particular.. } Tiene una colección de instancias Child. ¡igual que una clase de entidad! A cada fila de la colección se le asigna una clave sustituta diferente. 6.hibernar. } .Set.m. name varchar(255).HIBERNATE . public class Parent { private long id. . } private Set getChildren() { return children. Si embargo. En la implementación actual.. public long getId() { return id. Note que la performance al actualizar una <idbag> ¡es mucho mejor que la de una <bag> común! Hibernate puede localizar filas individuales eficientemente.org/documentacion_es/castellano. . Si cada child (hijo) tiene como mucho un padre. } private void setChildren(Set children) { this.id=id.. y actualizarlas o borraras individualmente. Así que veamos un ejemplo. Ejemplos de colecciones Las secciones precedentes son bastante confusas..html Como se puede ver. Esta clase: package eg. un map o un set. parent_id bigint ) alter table child add constraint childfk0 (parent_id) references parent If the parent is required.children=children. una <idbag> tiene un generador de id "sintético".Persistencia Relacional para Java Idiomático http://www. como si fuera una list.

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. si usted insiste absolutamente en que la asociación debe ser unidireccional. si un hijo tiene múltiles padres.org/documentacion_es/castellano. name varchar(255). debe declarar la constraint NOT NULL en el mapeo de la <key>.m. .Persistencia Relacional para Java Idiomático http://www. <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. <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.HIBERNATE . parent_id bigint not null ) alter table child add constraint childfk0 (parent_id) references parent Alternativamente.hibernar. lo apropiado es una relación de-muchos-a-muchos.

7. <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.html create table child ( id bigint not null primary key. Usaremos Person y Address ("persona" y "dirección") en todos los ejemplos. Asociaciones unidireccionales. Mapeos de asociaciones 7. Son posibles mapeos de asociaciones aún más exóticas. name varchar(255) ) create table childset ( parent_id bigint not null.HIBERNATE . y según su multiplicidad.Persistencia Relacional para Java Idiomático http://www. En esta sección revisaremos los casos canónicos uno por uno. addressId bigint not null ) create table Address ( addressId bigint not null primary key ) 7. en la modelización de datos tradicional. Catalogaremos todas las posibilidades en el capítulo siguiente.2. La única diferencia es la constraint de unicidad. vea Capítulo 21.org/documentacion_es/castellano. y una explicación paso a paso del mapeo de una relación padre-hijo. child_id bigint not null. los mapeos aún funcionarían si se eliminara la constraint de nulabilidad. <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.hibernar. 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 más ejemplos. de-muchos-a-uno Una asociación unidireccional de-muchos-a-uno es el tipo más común de asociación unidireccional.m. Clasificaremos las asociaciones según usen o no una tabla de asociación.1. y siguiendo con los bidireccionales.2. Capítulo 7. Esto no es obligatorio. así que todos nuestros ejemplos usarán claves foráneas no nulas. de-uno-a-uno Una asociación unidireccional de-uno-a-uno por clave foránea es prácitcamente idéntica.2.1.2. Las claves foráneas anulables no son consideradas una práctica recomendable. . Ejemplo: Padre/Hijo. empezando con los mapeos unidireccionales. Introducción Los mapeos de asociaciones son lo más difícil de comprender correctamente. 7.

personId bigint not null ) Pensamos que para este caso es mejor usar una tabla de asociación.1.2.3. que no recomendamos usar.hibernar. 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. de-uno-a-muchos Una asociación unidireccional de-uno-a-muchos por clave foránea es un caso muy inusual.m. <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.3. addressId bigint not null unique ) create table Address ( addressId bigint not null primary key ) Una asociación unidirectional de-uno-a-uno por clave primaria normalmente usa un generador de id especial (note que hemos revertido la dirección de la asociación en este ejemplo).HIBERNATE . de-uno-a-muchos Una asociación unidireccional de-uno-a-muchos por tabla de asociación es mucho más recomendable. Note que al especificar unique="true".Persistencia Relacional para Java Idiomático http://www. 7.3.html <generator class="native"/> </id> </class> create table Person ( personId bigint not null primary key. <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. Asociaciones unidireccionales con tablas de asociación 7.org/documentacion_es/castellano. .

4. .3.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.hibernar.HIBERNATE . addressId bigint not null unique create table Address ( addressId bigint not null primary key ) 7. <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.2.Persistencia Relacional para Java Idiomático http://www.3. addressId bigint not null ) create table Address ( addressId bigint not null primary key ) 7.3. de-uno-a-uno Una asociación unidireccional de-uno-a-uno por tabla de asociación es muy inusual.m. addressId bigint not null primary key ) create table Address ( addressId bigint not null primary key ) 7. pero posible. cuando la asociación 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. de-muchos-a-uno Una asociación A unidireccional de-muchos-a-uno por tabla de asociación es muy común.3. de-muchos-a-muchos 92 de 198 17/02/2009 09:25 a.org/documentacion_es/castellano.

HIBERNATE - Persistencia Relacional para Java Idiomático

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

Finalmente, tenemos una asociación 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 asociación bidireccional de-muchos-a-uno es el tipo más común de asociación (la relación padre/hijo estándar).
<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 colección idexada) se necesitará asignarle not null a la columna "key" de la clave foránea, y dejar que Hibernate maneje la asociación 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 Idiomático

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

Es importante que se defina not-null="true" en el elemento <key> del mapeo de la colección, si la columna de clave foránea 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 asociación bidireccional de-uno-a-uno por clave foránea es bastante común
<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 asociación 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 asociación
7.5.1. de-uno-a-muchos / de-muchos-a-uno
Un asociación bidireccional de-uno-a-muchos por tabla de asociación. Note que el inverse="true" puede ir an cualquier extremo de la asociación, en la colección, 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 Idiomático

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 asociación bidireccional de-uno-a-uno por tabla de asociación 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 asociación 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 más complejas
95 de 198 17/02/2009 09:25 a.m.

Por ejemplo.key=key. } private void setKey(String key) { this. private String key.hibernar. Capítulo 8. Entonces.Date getBirthday() { return birthday.1. Objetos dependientes Un componente es un objeto contenido. 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 asociación 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 más complejo. para distintos propósitos. } public java.m. no como referencia a una entidad.util. una asociación al empleador más reciente de un empleado (el que tuviere la startDate más reciente) podría ser mapeada de esta manera: <join> <key column="employeeId"/> <subselect> select employeeId.birthday = birthday. se puede modelar a una persona así: public class Person { private java. 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.html Asociaciones más complejas son extremadamente raras. component) se reusa a lo largo y a lo ancho de Hibernate en distintos contextos. llena de datos históricos de empleo.util. El término "componente" se refiere a la noción orientada a objetos de "composición" (no a "componentes" a nivel de arquitectura). Hibernate posibilita manejar asociaciones más complejas usando fragmentos SQL incrustados en el documento de mapeo. } public Name getName() { 96 de 198 17/02/2009 09:25 a. . private Name name. si una tabla con información contable histórica definiere las columnas accountNumber. que es persistido como "value type". Mapeos de componentes La noción de componente (en inglés. 8.org/documentacion_es/castellano.Date birthday. Por ejemplo.Date birthday) { this. pero normalmente es más práctico manejar estos casos unando HQL o consultas Criteria. } public void setBirthday(java. effectiveEndDate and effectiveStartDate.util.Persistencia Relacional para Java Idiomático http://www.HIBERNATE . public String getKey() { return key. imagine que la asociación entre Employee y Organization estuviere mantenida por una tabla Employment.

} public char getInitial() { return initial. String last. Cuando se recargue el objeto contenedor. .. Como todos los "value types". pero no necesita declarar ninguna interfaz ni propiedades identiicadoras. Las propiedades de un componente pueden ser de cualquier tipo Hibernate (colecciones. Note que Name define métodos getter y setter para sus propiedades persistentes. Los componentes anidados no deben ser considerados una rareza.hibernar.. } void setInitial(char initial) { this. Hibernate assumirá que el componente entero es nulo. } . Name puede ser persistida como un componente de Person (en inglés.. etc).m. pero los dos objetos Person correspondientes contendrán dos objetos nombre independientes.Person" table="person"> <id name="Key" column="pid" type="string"> <generator class="uuid"/> </id> <property name="birthday" type="date"/> <component name="Name" class="eg. Nuestro mapeo Hibernate se vería así: <class name="eg.el atributo 'class" es optativo --> <property name="initial"/> <property name="first"/> <property name="last"/> </component> </class> La tabla PERSON tendría las columnas pid.. sólo que con "el mismo" valor.first = first.HIBERNATE . } } Ahora.name = name. birthday.initial = initial.Persistencia Relacional para Java Idiomático http://www..html return name. Dos personas pueden tener el mismo nombre. Se espera que Hibernate soporte un modelo de objetos muy jerárquico y detallado en este sentido.org/documentacion_es/castellano.last = last.Name" unique="true"> <parent name="namedPerson"/> <!-. } public class Name { char initial... los componentes no soportan referencias compartidas. Esto debería alcanzar para la mayoría de los casos. String first. La semántica de nulo de un componente es ad hoc. } public void setName(Name name) { this. <class name="eg. public String getFirst() { return first.Person" table="person"> <id name="Key" column="pid" type="string"> <generator class="uuid"/> </id> <property name="birthday" type="date"/> <component name="Name" class="eg.referencia de vuelta a Person --> <property name="initial"/> 97 de 198 17/02/2009 09:25 a. asociaciones de-muchos-a-uno. . 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.. respectivamente)... } void setFirst(String first) { this. } void setLast(String last) { this. } public String getLast() { return last. otros componentes. "nombre" y "persona". initial. first y last.Name"> <!-.

<set name="someNames" table="some_names" lazy="true"> <key column="id"/> <composite-element class="eg..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. un array de tipos Name).org/documentacion_es/castellano. lo cual no es posible con valores nulos. <class name="eg. pero dése cuenta de que. A este punto usted debería preguntarse si no sería más apropiada una asociación de-uno-a-muchos. le modelo relacional y la semántica de persistencia son aún ligeramente diferentes. Se deberá o bien usar sólo valores no nulos en un <composite-element>. Una simple compra (Purchase) puede estar en el set de una Order. Los elementos compuestos pueden contener otros componentes. Un caso especial de elemento compuesto ese el elemento compuesto que tiene un elemento <many-to-one> anidado. Colecciones de objetos dependientes Hay soporte para colecciones de componentes (por ejemplo. Trate de remodelar el elemento compuesto como una entidad.Persistencia Relacional para Java Idiomático http://www. Incluso son posibles asociaciones ternarias o cuaternarias: <class name="eg. Declare su colección de componentes reemplazando la tag del elemento <element> con una tag <composite-element>..Item"/> <!-. <set name="purchasedItems" table="purchase_items" lazy="true"> <key column="order_id"> <composite-element class="eg. <set name="purchasedItems" table="purchase_items" lazy="true"> <key column="order_id"> <composite-element class="eg.m. Por favor. 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). <bag> o <idbag>. el precio (price) y la cantidad (quantity) son propiedades de la asociación. > .. aunque el modelo de Java es el mismo.Order" . Un mapeo como éste permite mapear columnas extra de una tabla de asociación de-muchos-a-muchos a la clase del elemento compuesto. <map>. Si su componente compuesto a su vez contiene componentes. o bien elegir una <list>.. pero no colecciones. La siguiente es una asociación de-muchos-a-muchos de from Order a Item (de orden a ítem) en donde la fecha de compra ( purchaseDate). > .el atributo "clase" es optativo --> </composite-element> </set> </class> Por supuesto. y no aceptan referencias compartidas. note que un mapeo de elemento compuesto no soporta propiedades anulables si se está usando un <set>. Éste es un caso batante exótico: una colección de componentes que a su vez tengan componentes.HIBERNATE .Item"/> </composite-element> </set> 98 de 198 17/02/2009 09:25 a.OrderLine"> <many-to-one name="purchaseDetails class="eg.Order" . ... no puede haber una referencia a la compra del otro lado. para proveer navegación bidireccional de la asociación. use la tag <nested-composite-element>.Name"> <!-. pero no puede ser referida por el Item al mismo tiempo.Purchase"/> <many-to-one name="item" class="eg.Purchase"> <property name="purchaseDate"/> <property name="price"/> <property name="quantity"/> <many-to-one name="item" class="eg.. es importante implementar equals() y hashCode() correctamente. Recuerde que los componentes son "value types".....2..html <property name="first"/> <property name="last"/> </component> </class> 8.hibernar.

Esto se debe declarar en los mapeos para otras clases.4. <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. 8.org/documentacion_es/castellano. No se puede usar un IdentifierGenerator para generar claves compuestas. En lugar de eso.Persistencia Relacional para Java Idiomático http://www. Componentes usados como identificadores compuestos Se puede usar un componente como identificador de una clase entidad.HIBERNATE . el segundo requisito no es "sine qua non".el atributo "class" es optativo.) Una asociación de-muchos-a-muchos a OrderLine también usa la clave foránea compuesta. usando la misma sintaxis que las entidades. 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. pero cúmplalo de todos modos. <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> .io. la aplicacíón debe asignar sus propios identificadores. Asegúrese de reemplazar correctamente los métodos hashCode() y equals() en la clase componente.3. de una manera consistente con la noción de igualdad para la clave compuesta en la DB. la clase OrderLine (línea de una orden) tiene una clave primaria que depende de la clave (compuesta) de Order. Use la tag <composite-id> (con elementos <key-property> anidados) en lugar de la declaración de <id> usual. </class> Ahora. 8..Serializable. cualquier clave foránea que se refiera a la tabla ORDERLINE. Por ejemplo. Dicho componente debe satisfacer ciertos requisitos: Debe implementar java. Debe reimplementar equals() y hashCode()..html </class> Los elementos compuestos pueden aparecer en consultas.hibernar. Nota: en Hibernate3.. también será compuesta. La asociación con OrderLine sería mapeada así: <many-to-one name="orderLine" class="OrderLine"> <!-. . 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.

Persistencia Relacional para Java Idiomático http://www. </composite-element> </set> </class> 8. no declara ninguna columna). Componentes dinámicos 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 semántica de un mapeo <dynamic-component> es idéntica a la de <component>...m. <class name="OrderLine"> . Si la OrderLine misma posee una colección.hibernar.html <column name="customerId"/> </many-to-many> </set> La colección de OrderLines en Order usaría: <set name="orderLines" inverse="true"> <key> <column name="orderId"/> <column name="customerId"/> </key> <one-to-many class="OrderLine"/> </set> (El elemento <one-to-many>. .HIBERNATE . Las tres estrategias Hibernate soporta tres estrategias básicas de mapeo de herencia: una tabla por jerarquía de clases una tabla por subclase una tabla por clase concreta 100 de 198 17/02/2009 09:25 a..1. <list name="deliveryAttempts"> <key> <!-. también tiene una clave foránea compuesta.. simplemente editando el archivo de mapeo.. se puede acceder al meta-modelo de tiempo de configuración de Hibernate (y cambiarlo) usando el objeto Configuration . También es posible la manipulación en tiempo de ejecución del documento de mapeo.5. La ventaja de este tipo de mapeo es la capacidad de determinar las verdaderas propiedades del bean en tiempo de despliegue (deployment). . Capítulo 9.una colección 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"> . Mejor aún.... usando un parser DOM. como es usual. Mapeo de herencia 9.org/documentacion_es/castellano.

101 de 198 17/02/2009 09:25 a.. hay una gran limitación: las columnas declaradas por las subclases. Es posible definir mapeos de subclass. simplemente agregando un nuevo archivo de mapeo. combinando los elementos <subclass> y <join> (véase a continuación).html Adicionalmente.2. El mapeo de "una tabla por jerarquía" se vería 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"/> .Persistencia Relacional para Java Idiomático http://www. CashPayment. y joined-subclass en documentos de mapeo separados. el orden no importa cuando se usa la palabra "extends".. Sí es posible mezclar las estrategias de "una tabla por jerarquía" y de "una tabla por subclase" bajo el mismo elemento <class>.. <subclass name="CreditCardPayment" discriminator-value="CREDIT"> <property name="creditCardType" column="CCTYPE"/> .. 9. justo debajo de hibernate-mapping.. Sin embargo. efectivo y cheque respectivamente). </subclass> <subclass name="ChequePayment" discriminator-value="CHEQUE"> . and <joined-subclass> y <union-subclass> bajo el mismo elemento <class> de la clase raíz. </subclass> </class> Se requiere exactamente una tabla. <hibernate-mapping> <subclass name="DomesticCat" extends="Cat" discriminator-value="D"> <property name="name" type="string"/> </subclass> </hibernate-mapping> 9. union-subclass. </subclass> <subclass name="CashPayment" discriminator-value="CASH"> . ligeramente diferente: polimorfismo implícito Es posible usar estrategias de mapeo diferentes para distintas ramas de la misma jerarquía de herencias. El orden dentro de cada documento individual. Nota: en el pasado. no pueden tener constraints NOT NULL. Hibernate soporta una cuarta clase de polimorfismo.HIBERNATE . Se debe especificar el atributo extends en el mapeo de la subclase. Una tabla por jerarquía de clases Suponga que tenemos una interfaz Payment (pago).org/documentacion_es/castellano. ChequePayment (pago por tarjeta de crédito. Desde Hibernate 3.1. nombrando una superclase previamente mapeada.. Hibernate no soporta mezclar mapeos de <subclass>.hibernar. Una tabla por subclase El mapeo de una tabla por sublcase se vería así: <class name="Payment" table="PAYMENT"> <id name="id" type="long" column="PAYMENT_ID"> <generator class="native"/> </id> <property name="amount" column="AMOUNT"/> .. y después hacer uso del polimorfismo implícito para lograr polimorfismo todo a lo largo de dicha jerarquía....m.1. esta característica hacía que el orden de los documentos de mapeo fuese relevante. implementada por las clases CreditCardPayment. Con esta estrategia de mapeo.1. aún tiene que tener las superclases antes de las subclases. Esto permite extender la jerarquía de clases. . como CCTYPE.

. puede combinar el uso de <subclass> y <join>. </join> </subclass> </class> La declaración 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.HIBERNATE .. <subclass name="CreditCardPayment" discriminator-value="CREDIT"> <join table="CREDIT_PAYMENT"> <key column="PAYMENT_ID"/> <property name="creditCardType" column="CCTYPE"/> ...org/documentacion_es/castellano. usando un discriminador Note que la implementación de Hibernate para "una tabla por subclase" no requiere una columna discriminadora. </joined-subclass> <joined-subclass name="ChequePayment" table="CHEQUE_PAYMENT"> <key column="PAYMENT_ID"/> ..m..4... Mezclar "una tabla por jerarquía de clases" con "una tabla por subclase" Incluso se pueden mezclar las estrategias de "una tabla por jerarquía de clases" con "una tabla por subclase" usando este abordaje: <class name="Payment" table="PAYMENT"> 102 de 198 17/02/2009 09:25 a.hibernar. .. Otros mapeadores objeto/relacionales usan una implementación diferente de "una tabla por subclase". Si usted desea usar una columna discriminadora con la estrategia de "una tabla por subclase". Una tabla por subclase. </joined-subclass> </class> Se requieren 4 tablas. </join> </subclass> <subclass name="ChequePayment" discriminator-value="CHEQUE"> <join table="CHEQUE_PAYMENT" fetch="select"> <key column="PAYMENT_ID"/> . que sí requiere una columna discriminadora en la tabla de la superclase... </joined-subclass> <joined-subclass name="CashPayment" table="CASH_PAYMENT"> <key column="PAYMENT_ID"/> . 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"/> .1.html <joined-subclass name="CreditCardPayment" table="CREDIT_PAYMENT"> <key column="PAYMENT_ID"/> <property name="creditCardType" column="CCTYPE"/> . 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 asociación de-uno-a-uno). 9.. El enfoque adoptado por Hibernate es mucho más difícil de implementar... 9.1. </join> </subclass> <subclass name="CashPayment" discriminator-value="CASH"> <join table="CASH_PAYMENT"> <key column="PAYMENT_ID"/> .3. pero probablemente más correcto desde el punto de vista relacional.Persistencia Relacional para Java Idiomático http://www.

mapéela con abstract="true". una asociación polimórfica a la clase raíz Payment se mapea usando <many-to-one>. </union-subclass> <union-subclass name="CashPayment" table="CASH_PAYMENT"> . usando polimorfismo implícito Un enfoque alternativo es usar polimorfismo implícito: <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. es que si la propiedad está mapeada en la superclase. </subclass> <subclass name="ChequePayment" discriminator-value="CHEQUE"> ..HIBERNATE . La estrategia de generador de identidad no está permitida para una herencia que esté usando union-subclass.. hay tres clases involucradas. Una tabla por clase concreta Con la estrategia de "una tabla por clase concreta" podríamos proceder de dos maneras.hibernar. 9.. <class name="Payment"> <id name="id" type="long" column="PAYMENT_ID"> <generator class="sequence"/> </id> <property name="amount" column="AMOUNT"/> .... (Podemos relajar este requisito en versiones futuras de Hibernate).org/documentacion_es/castellano. .. La limitación de este abordaje. el nombre de la columna debe ser el mismo en todas las tablas de subclases....1. se necesita una tabla adicional (por defecto sería PAYMENT en el ejemplo anterior) para almacenar instancias de la superclase.. Una tabla por cada clase concreta.m.. Por supuesto. <many-to-one name="payment" column="PAYMENT_ID" class="Payment"/> 9. dado que la clave primaria debe ser compartida por todas las subclases de la jerarquía participantes en la unión. La primera es usar <unionsubclass>. </union-subclass> </class> Para las subclases.. Cada tabla define columnas para todas las propiedades de la subclase.Persistencia Relacional para Java Idiomático http://www.. </join> </subclass> <subclass name="CashPayment" discriminator-value="CASH"> . Lógico. <union-subclass name="CreditCardPayment" table="CREDIT_PAYMENT"> <property name="creditCardType" column="CCTYPE"/> . </subclass> </class> Para cualquiera de estas estrategias de mapeo.html <id name="id" type="long" column="PAYMENT_ID"> <generator class="native"/> </id> <discriminator column="PAYMENT_TYPE" type="string"/> <property name="amount" column="AMOUNT"/> . incluso las propiedades heredadas.6. Si su superclase es abstracta..1. </union-subclass> <union-subclass name="ChequePayment" table="CHEQUE_PAYMENT"> . <subclass name="CreditCardPayment" discriminator-value="CREDIT"> <join table="CREDIT_PAYMENT"> <property name="creditCardType" column="CCTYPE"/> . si no es abstracta..5.

7. ¡cada una de las subclases podría fácilmente ser parte de otra jerarquía de clases! (y aún se podrían usar consultas polimórficas contra la interfaz Payment). Como cada una de las subclases está mapeada en su propio elemento <class> (y dado que Payment sólo es una interfaz)..hibernar.. Según esta estrategia de mapeo. es que Hibernate no generará SQL UNIONs cuando ejecute consultas polimórficas. </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"/> . <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. La desventaja de este enfoque.Persistencia Relacional para Java Idiomático http://www.org/documentacion_es/castellano..html </id> <property name="amount" column="CREDIT_AMOUNT"/> .. </class> Nótese que no mencionamos explícitamente en ningún lado 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"/> ...1.HIBERNATE . </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"/> . <joined-subclass name="CashPayment" table="CASH_PAYMENT"> <key column="PAYMENT_ID"/> <property name="amount" column="CASH_AMOUNT"/> . una asociación polimórfica a Payment sería normalmente mapeada usando <any>. Si se quiere evitar la duplicación. [ <!ENTITY allproperties SYSTEM "allproperties. en el mapeo).. También nótese que las propiedades de Payment están mapeadas en cada una de las subclases.xml"> ] en la declaración de DOCTYPE y &allproperties. considere usar entidades XML (por ejemplo.. Mezclar polimorfismo implícito con otras estrategias de mapeo de herencia Hay una cosa más que resaltar. acerca de este mapeo. ... <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> <joined-subclass name="ChequePayment" table="CHEQUE_PAYMENT"> 104 de 198 17/02/2009 09:25 a..m.

En otras palabras.get(Payment. Y ésta es una forma muy natural de manejar la persistencia en una aplicación de Java. los programadores en Hibernate siempre deberían pensar en términos del estado de sus objetos.m. 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.1.html <key column="PAYMENT_ID"/> <property name="amount" column="CHEQUE_AMOUNT"/> .2.get(Payment. Una comparación de las limitaciones de ambas estrategias se muestra en la tabla siguiente: Tabla 9.hibernar. De esto se encarga Hibernate.org/documentacion_es/castellano. </joined-subclass> </class> De nuevo no necesitamos mencionar la interfaz Payment explícitamente. id) inverse="true" a-muchos> only) una tabla por clase <any> concreta (polimorfismo implícito) not supported not supported <manyto-any> s. 9. Limitaciones Hay ciertas limitaciones del abordaje a la estrategia "una tabla por clase concreta" usando polimorfismo implícito.createCriteria(Payment. Hibernate devuelve automáticamente instancias de. Restrictions.idEq(id) ). que también implementan Payment.uniqueResult() Capítulo 10. sino que ofrece manejo del estado de sus objetos.. Características de los mapeos de herencia polimórfica Estrategia de polimórfica polimórfica polimórfica de-muchosherencia de-muchos-a-uno de-uno-a-uno de-uno-a-muchos a-muchos una tabla por jerarquía de clase load()/get() polimórficos <de-muchosa-uno> <de-unoa-uno> <de-unoa-muchos> <de-muchoss.class. id) a-muchos> <de-muchosa-uno> <de-unoa-uno> <de-unoa-muchos> (for <de-muchoss. por ejemplo. y no necesariamente en términos de qué comandos SQL están siendo ejecutados. Trabajar con objetos Hibernate es un dispositivo completo de mapeo objeto/relacional.HIBERNATE . que no sólo escuda al programador contra los detalles de gestión del sistema de base de datos subyacente.class.Persistencia Relacional para Java Idiomático http://www. 10. . CreditCardPayment y sus subclases.get(Payment.1. pero no instancias de NonelectronicTransaction. Y hay limitaciones un tanto menos restrictivas para los mapeos que usan <union-subclass>.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. y sólo es relevante para el programador cuando se trate de ajustar la perfomance del sistema.class. al contrario de los comandos SQL en las capas usuales de persistencia JDBC/SQL.

a menos que exista una constraint NOT NULL en una columna de clave foránea.2. persist() convierte una instancia transitoria en persistente.Persistencia Relacional para Java Idiomático http://www. No tiene representación persistente en la base de datos y no se le ha asignado ningún identificador. Aunque recién haya sido cargada o grabada. pk.html Transitorio (en inglés. en el ejemplo anterior). Con ella. una unidad del trabajo desde el punto de vista del usuario. 10. Si Cat tiene un identificador asignado externamente. DomesticCat pk = new DomesticCat(). Esto es indeseable en conversaciones largas. usted no debe preocuparse por estos detalles. pero sí se puede llegar a violar una constraint NOT NULL si se les aplica save() a los objetos en el orden incorrecto. pero cuya sesión ha sido cerrada. usted terminará usando la característica de Hibernate llamada persistencia transitiva para grabar los objetos asociados automáticamente. y no está asociado con una sesión de Hibernate. persistent): una instancia persistente ya tiene una representación en la base de datos. muy probablemente. y la instancia desprendida puede incluso ser modificada en este estado.setName("PK"). persist() también garantiza que nos ejecutará un comando INSERT si es llamado fuera de los límites de una transacción. Si hay que ejecutar un INSERT (por ejemplo. Persistente (en inglés. dicho identificador se genera y se le asigna a cat cuando save() sea llamado. save() sí garantiza la devolución de un identificador. con un contexto de sesión/persistencia extendido. La persistencia transitiva se discute más 106 de 198 17/02/2009 09:25 a. Las instancias transitorias serán destruidas por el recolector de basura (garbage collector). fritz. Esta característica es ideal para programar unidades de trabajo largas. Esto es útil para conversaciones de largo aliento.GINGER). Normalmente. sin importar si se está dentro o fuera de una transacción. Ahora discutiremos los estados y las transiciones entre ellos (así como los métodos de Hibernate que disparan estas transiciones) con más detalle. esto es. y un valor de identificador. con la semántica definida en el borrador temprano de EJB3. (por ejemplo. dicho identificador debería serle asignado a cat antes de invocar save(). detached): un objeto desprendido es un objeto que era persistente. Se puede usar persist() em lugar de save().setName("Fritz"). transient): un objeto es transitorio cuando ha sido instanciado usando el operador new . con un contexto de sesión/persistencia extendido. Alternativamente.setColor(Color. Use la sesión de Hibernate para volver persistente un objeto (y deje que Hibernate se encargue de los comandos SQL que sean necesarios para dicha transición). pk.addKitten(fritz).setSex('M'). Las llamamos transacciones "de la aplicación".setColor(Color. gatitos. porque el generador es "identity" y no "sequence") el INSERT ocurre inmediatamente. el programador no necesita ejecutar comandos UPDATE ni DELETE manualmente. volviéndola persistente de nuevo (junto con todas las modificaciones que haya sufrido). pk. Pero no garantiza que el identificador le vaya a ser asignado a la instancia inmediatamente: la asignación puede ocurrir al aplicársele "flush" a la sesión. . Si el objeto que se hace persistente tiene objetos asociados. si la aplicación ya no tiene ninguna referencia a ellas.org/documentacion_es/castellano. Hibernate detectará cualquier cambio que se efectúe sobre un objeto en estado persistente. Si el objeto persistente es tranformado en transitorio. pk. y sincronizará su estado con el de la base de datos cuando la unidad de trabajo se complete.setKittens( new HashSet() ). Una instancia desprendida puede ser reasociada a una nueva sesión en el futuro. Desprendido (en inglés. pk.save(fritz). El riesgo de violar una constraint de clave foránea no existe. Volver persistente un objeto Las instancias recientemente creadas de una clase son consideradas transitorias por Hibernate. new Long(1234) ). Si Cat tiene un identificador autogenerado. que necesiten darle a la aplicación tiempo para "pensar". Podemos convertir una instancia transitoria en persistente asociándola con una sesión: DomesticCat fritz = new DomesticCat(). la colección "kittens". Long generatedId = (Long) sess. La referencia al objeto aún es válida. dado que.save( pk. por definición ya está inscripta en el alcance de la sesión.m. fritz.TABBY). sess.setSex('F'). se puede asignar el identificador usando una versión sustituida (overloaded) de of save(). dichos objetos pueden ser hechos persistentes en cualquier orden. fritz. Hibernate se hace cargo de todo. o una clave compuesta.HIBERNATE .hibernar. ni siquiera las violaciones de NOT NULL ocurren.

getKittens(). new Long(id) ). load() simplemente devuelve un proxy no inicializado. el cual consulta la base de datos inmediatamente y devuelve null si no existe una fila correspondiente. a menos que se especifiquen los valores lock o all en el parámetro de mapeo "cascade". 10. Para la creación programática de consultas. Cuando no se esté seguro de que exista una fila correspondiente. Se puede recargar un objeto y todas sus asociaciones an cualquier momento.org/documentacion_es/castellano.refresh(cat). “Estrategias de captura (fetch)”.hibernar. sess. Dese cuenta de que load() lanzará una excepción irrecuperable si no existe la fila de base de datos correspondiente. . se necesita una consulta (query). Hibernate soporta un lenguaje para consultas poderoso pero fácil de usar: HQL (las siglas en inglés de "Hibernate Query Language"). sess.Persistencia Relacional para Java Idiomático http://www. Esto es muy útil cuando se están usando triggers de DB para inicializar algunas de las propiedades del objeto. se puede cargar estado en una instancia ya existente: Cat cat = new DomesticCat(). // cargar el estado identificado por la clave primaria en Cat sess. inicializada en el momento. Cat fritz = (Cat) sess. sess. Este comportamiento es muy útil si se desea crear una asociación con un objeto.usualmente se plantea una cuestión: ¿Cuánto carga Hibernate de la base de datos?¿Cuántos SQL SELECTs se usan? Esto depende de la estrategia de captura (fetching strategy) y se explica en la Sección 19. en estado persistente. debería usarse el método get().UPGRADE). id. //relee el estado (luego de que el trigger se ejecuta) Llegados a este punto.load(Cat. usndo el método refresh().get(Cat.class. Cargar un objeto El método load() de Session provee una manera de capturar una instancia persistente. Consultas Si no se conocen los identificadores de los objetos que se está buscando. si ya se conoce su identificador. Si la clase es mapeada con un proxy. if (cat==null) { cat = new Cat(). También permite cargar múltiples instancias en lotes. Hibernate soporta dos clases muy sofisticadas.class.HIBERNATE .3. respectivamente).flush()..class. Vea la documentación de la API para más información. y cargará el estado en una nueva instancia de esa clase. generatedId). Cat cat = (Cat) sess. Note que ni las instancias asociadas ni las colecciones contenidas son seleccionadas FOR UPDATE (con el propósito de ser modificadas).get(Cat. Set kittens = cat. new Long(pkId) ). } return cat. // se necesita "envolver" los identificadores de tipos primitivos long id = 1234.save(cat). usando LockMode. load() acepta un objeto Class.save(cat. id).m. //fuerza el SQL INSERT sess. sin realmente cargarlo desde la base de datos. si batch-size está definido para la clase.load( cat. 107 de 198 17/02/2009 09:25 a. DomesticCat pk = (DomesticCat) sess. LockMode. Criteria y Example (a veces referidos como QBC y QBE. Cat cat = (Cat) sess. id). Alternativamente. por "query by criteria" y "query by example".4. y no hay contacto con la base de datos hasta que realmente se invoque un método del proxy. Incluso se puede cargar un objeto usando un SQL SELECT .load( DomesticCat. FOR UPDATE..1. con soporte opcional de conversión de su resultado en objetos. También se puede expresar la consulta en el lenguaje nativo de su base de datos. 10.class.html adelante en este capítulo.

en cuyo caso cada t-upla se devuelve como un array. // no necesitamos procesar el resto break.mother mother") .Qux q order by q.HIBERNATE . Cat mother = (Cat) session.hasNext() ) { Qux qux = (Qux) iter. date) .mother as mother where cat. Siempre se obtiene el Query a partir la sesión actual.hibernate.calculateComplicatedAlgorithm() ) { // borrar la isntancia actual iter.2.setEntity(0.birthdate < ?") . name) . El método uniqueResult() ofrece un atajo si usted ya sabe que la consulta devolverá un solo objeto.1.likeliness").createQuery("from eg.next(). List mothers = session.list().createQuery( "from Cat as cat where cat.m.hasNext() ) { Object[] tuple = (Object[]) kittensAndMothers.createQuery( "select kitten. manejo de resultsets. Consultas que devuelven T-uplas Las consultas de Hibernate a veces devuelven t-uplas de objetos. } } 10.name = ?") .Persistencia Relacional para Java Idiomático http://www. // captura de ids Iterator iter = sess. Una consulta normalmente se ejecuta invocando list().1. izi) . Iterar resultados Ocasionalmente.4.iterator(). Note que las consultas que hacen uso de "captura ansiosa" (eager fetching). Iterator kittensAndMothers = sess.list().next(). Si no están en el caché.list(). 10. List kittens = session. pk) . while ( iter. List cats = session. o en el caché de 2do nivel.kittens").html 10.1. // captura de un objeto // alguna comprobación complicada que no podíamos expresar en la consulta if ( qux.org/documentacion_es/castellano.]] Query mothersWithKittens = (Cat) session.mother from Cat as cat where cat = ?") .iterate(). Estos duplicados se pueden eliminar.uniqueResult().createQuery( "select mother from Cat as cat join cat. Ejecutar consultas Las consultas en HQL y en SQL nativo son representadas por una instancia de org. y N SELECTs adicionales que inicializan las instancias propiamente dichas.1.4. while ( kittensAndMothers.remove(). iterate() será más lento que list(). normalmente devuelven duplicados del objeto raíz. el resultado de la consulta será cargado completamente en una colección en memoria. y la ejecución de la consulta misma. 108 de 198 17/02/2009 09:25 a.hibernar.mother = ?") .4.Query. Set uniqueMothers = new HashSet(mothersWithKittens.list() .createQuery( "select mother from Cat as mother left join fetch mother. con sus colecciones inicializadas.setEntity(0. simplemente usando un Set.setDate(0.createQuery( "from Cat as cat where cat. y es posible que requiera varios viajes a la base de datos para una simple consulta: normalmente 1 SELECT inicial que sólo devuelve los identificadores.createQuery( "select cat. mother from Cat kitten join kitten.list()). Esta interfaz ofrece métodos para vincular parámetros. Las entidades de instancia que son devueltas están en estado persistente. es posible que se obtenga una mejor performace si se ejecuta la consulta usando el método iterate().setString(0. Esto es normalmente cierto si se espera que las instancias de entidad devueltas por la consulta ya estarán en la sesión. .

HIBERNATE - Persistencia Relacional para Java Idiomático

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 cláusula 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. Parámetros vinculados
En Query se proveen métodos para vincular valores con parámetros nombrados, o parámetros ? al estilo JDBC. Al contrario que con JDBC, Hibernate numera los parámetros empezando de 0. Los parámetros nombrados son identificadores con la forma :name en la caden de la consulta. Las ventajas de los parámetros nombrados son: los parámetros nombrados son independientes del orden en que ocurren en la cadena de la consulta pueden ocurrir varias veces en la misma consulta son autodocumentados
//parámetro nombrado (la forma preferida) Query q = sess.createQuery("from DomesticCat cat where cat.name = :name"); q.setString("name", "Fritz"); Iterator cats = q.iterate(); //parámetro posicional Query q = sess.createQuery("from DomesticCat cat where cat.name = ?"); q.setString(0, "Izi"); Iterator cats = q.iterate(); //lista de parámetros 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. Paginación
Si se necesita establecer límtes en el resultset (el máximo número de filas que se quiere capturar / desde qué fila se desea obtener datos), deberían usarse los siguientes métodos de la interfaz Query:
Query q = sess.createQuery("from DomesticCat cat"); q.setFirstResult(20); q.setMaxResults(10); List cats = q.list();

Hibernate sabe cómo traducir este límite al el SQL nativo de su base de datos.

109 de 198

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

HIBERNATE - Persistencia Relacional para Java Idiomático

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

10.4.1.6. Iteración navegable
Si su driver de JDBC soporta ResultSets navegables, la interfaz Query puede ser usada para obtener un objeto ScrollableResults, el cual permite una navegación 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 página de una lista alfabética 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 página de gatos pageOfCats = new ArrayList(); cats.beforeFirst(); int i=0; while( ( PAGE_SIZE > i++ ) && cats.next() ) pageOfCats.add( cats.get(1) ); } cats.close()

Nótese que para esta funcionalidad se requiere una conexión abierta a la base de datos. y un cursor. Use setMaxResult()/setFirstResult() si necesita funcionalidad de paginación desconectada.

10.4.1.7. Externalizar consultas nombradas
Se puede definir consultas nombradas (named queries) en el documento de mapeo. Recuerde usar una sección CDATA si su consulta contiene carateres que podrían ser interpretados como caracteres reservados de XML).
<query name="ByNameAndMaximumWeight"><![CDATA[ from eg.DomesticCat as cat where cat.name = ? and cat.weight > ? ] ]></query>

La vinculación de parámetros y la ejecución se hacen programáticamente.
Query q = sess.getNamedQuery("ByNameAndMaximumWeight"); q.setString(0, name); q.setInt(1, minWeight); List cats = q.list();

Note que el código 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 colocándolas en archivos de mapeo. También note que la declaración dentro de un elemento <hibernate-mapping> requiere un nombre globalmente único para la consulta, mientras que la declaración de una consulta dentro de un elemento <class> se vuelve única automáticamente al afijarle el nombre enteramente calificado de la clase, por ejemplo, eg.Cat.PorNombreYPesoMaximo.

10.4.2. Filtrar colecciones
El filtro de una colección es un tipo especial de consulta que puede aplicársele a una colección persistente, o a un array. La cadena de la consulta puede hacer uso de this, refiriéndos el elemento actual de la colección.
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 Idiomático

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

La colección devuelta se considera una bag, y es una copia de a colección dada. La colección 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 cláusula FROM (aunque pueden tenerla si es necesario). Los filtros no están 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 vacía es útil, por ejemplo para cargar un subconjunto de elementos en una colección 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 dinámicamente, 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 más detalle en Capítulo 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 parámetros nombrados o posicionales, al igual que las consultas de Hibernate. Se puede encontrar más información sobre las consultas SQL nativas en Capítulo 16, SQL Nativo.

10.5. Modificar objetos persistentes
Las instancias persistentes transaccionales (esto es, los objetos cargados, grabados, creados o consultados por las sesión) pueden ser manipulados por la aplicación, y cualquier cambio a su estado de persistencia será persistido cuando se le aplique "flush" a la sesión (como se discute más adelante en este capítulo). No hay necesidad de invocar ningún método en particular (como por ejemplo update(), que sirve para otra cosa) para que las modificaciones se vuelvan persistentes. Así que la manera más sencilla y directa de actualizar el estado de un objeto es cargarlo con load(), y luego manipularlo directamente, mientras la sesión esté abierta.
DomesticCat cat = (DomesticCat) sess.load( Cat.class, new Long(69) ); cat.setName("PK"); sess.flush(); // los cambios se detectan y son persistidos automáticamente

111 de 198

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

11.6. sin embargo..lock(izi. 10.HIBERNATE .lock(fritz. luego reasocie sess. Puede ser.update(cat).setMate(potentialMate).UPGRADE). // actualiza cat secondSession. se habría producido una excepción.save(potentialMate).org/documentacion_es/castellano. dado que requeriría tanto un SQL SELECT (para cargar el objeto) como un SQL UPDATE (para persistir su estado modificado) en la misma sesión. Procesamiento en lotes para posibles trucos de operación en lote. merge() si usted desea consolidar sus modificaciones en cualquier momento. Use update() si usted está seguro de que la sesión no contiene una instancia que ya es persistente con el mismo id.html A veces. por supuesto.lock(pk. catId). LockMode.merge(): // en la primera sesión Cat cat = (Cat) firstSession.READ). usando persistencia transitiva. Véase Capítulo 13. la noción de "operaciones en masa" entra en conflicto con el mapeo objeto/relacional para las aplicaciones orientadas al procesamiento de transacciones en línea. Hibernate soporta este modelo. Otros modelos para unidades largas de trabajo se discuten en Sección 11. Por lo tanto.m. normalmente usan datos versionados para garantizar aislamiento durante la "larga" unidad de trabajo.3. FOR UPDATE. //primero verifique la versión usando SELECT . En otras palabras. usando instancias desprendidas: Note que Hibernate no expone una API propia para ejecutar comandos UPDATE o DELETE directamente. El método lock() también le permite a la aplicación reasociar un objeto con una sesión nueva. se puede obtener una conexión de JDBC en cualquier momento invocando session.update() o Session. // en una capa más alta de la aplicación cat. //mate=pareja // luego.hibernar. Cat potentialMate = new Cat(). Las aplicaciones que usan este tipo de estrategia en entornos de alta concurrencia. que o bien grabe una instancia transitoria (generando 112 de 198 17/02/2009 09:25 a. y grabar sus cambios en una nueva transacción. “Persistencia transitiva”. Modificar objetos desprendidos Muchas aplicaciones necesitan capturar un objeto en una transacción.. LockMode.connection(). Hibernate es un servicio de manejo de persistencia. en una nueva sesión secondSession. “Control de concurrencia optimista”.7. firstSession.NONE). Note que lock() puede ser usado con varios LockModes. vea la documentacíón de la API y el capítulo sobre manejo de transacciones para más informacíón. update() es normalmente el primer método que se invocará en una sesión nueva. mandarlo a la capa de interfaz de usuario para su manipulación. independientemente del estado de esa instancia en la sesión. // actualiza mate Si el Cat con identificador catId ya hubiera sido cargado por la segunda sesión (secondSession) cuando la sesión trataba de reasociarlo.Persistencia Relacional para Java Idiomático http://www.update(mate). LockMode. garantizando que la reasociación de las instancias desprendidas sea la primera operación que ocurra. Reasociar no es el único uso que lock() tiene. que versiones futuras de Hibernate provean funciones especiales para procesamiento en masa. Esto puede ser automatizado.class. y no se lo debe concebir en términos de qué comandos ejecuta. . si y sólo si desea que su estado también sea actualizado. vea la Sección 10. La aplicación debería aplicarles update() a las instancias desprendidas dependientes de la instancia desprendida en cuestión. este modelo de programación es ineficiente. JDBC es una API perfectamente adecuada para ejecutar comandos SQL. Detección de estado automática Los usuarios de Hibernate han solicitado un método de uso general.load(Cat. Hibernate ofrece un abordaje alternativo. proveyendo "reasociación" de entidades desprendidas usando los métodos Session. Más aún. la instancia desprendida no debe haber sido modificada! //simplemente reasocia sess. ¡Sin embargo. luego reasocie sess. //primero verifique la versión. 10.

Por supuesto. // en una capa más alta de la aplicación Cat mate = new Cat(). sin temor de causar violaciones de clave foránea. // luego. Es mejor pensar que delete() está convirtiendo una instancia persistente en transitoria. a menos que se esté intentando usar instancias de una sesión en otra sesión nueva. se devuelve la instancia persistente la instancia dada (como parámetro) no se vuelve asociada con la sesión. intenta cargarla de la base de datos. o crear una nueva instancia persistente.8.load(Cat. El método saveOrUpdate() implementa tal funcionalidad: // en la primera sesión Cat cat = (Cat) firstSession. Pero sí es 113 de 198 17/02/2009 09:25 a. se invoca save() si el identificador del objeto es asignable. o bien actualice/reasocie las instancias desprendidas asociadas con el identificador actual. si no hay ninguna instancia asociada con la sesión. copia el estado del objeto dado en la instancia persistente.HIBERNATE . si el objeto es versionado (por una <version> o <timestamp>). y le ha sido recientemente asignado a una instancia recién creadam se invoca save().Persistencia Relacional para Java Idiomático http://www. no hace nada si ya hay otro objeto asociado con la sesión con el mismo identificador. se produce una excepción si el objeto no tiene una valor de identificador. cat. permanece desprendida. saveOrUpdate().m. Hay aplicaciones enteras que jamás utilizarán ninguno de estos métodos. // actualice el estado existente (cat tiene un id no nulo) // grabe la instancia nueva (mate tiene un id nulo) El uso y semántica de saveOrUpdate() les parece confuso a los nuevos usuarios.hibernar.saveOrUpdate(cat).saveOrUpdate(mate). catID).setMate(mate). Se puede borrar objetos en cualquier orden que se desee. ni merge(). su aplicación podría aún contener una referencia al objeto quitado.delete() quitará el estado de un objeto de la base de datos. se invoca update() y merge() es muy distinto si ya hay una instancia persistente con el mismo identificador asociada con la sesión. En primer lugar. se invoca save() en cualquier otro caso.html un identificador nuevo). y la propiedad versión es el mismo valor asignado a un objeto recién instanciado.org/documentacion_es/castellano. secondSession.class. no hay necesidad de usar update().delete(cat). Usualmente. Borrar objetos persistentes Session. sess. update() o saveOrUpdate() se usan en el siguiente escenario: la aplicación carga un objeto en la primera sesión 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 lógica de negocios la aplicación persiste estas modificaciones invocando update() en una segunda sesión saveOrUpdate() hace lo siguiente si el objeto ya es persistente en esta sesíón. en una nueva sesión secondSession. 10. .

Este proceso llamado el "nivelado" o "desagote" de la sesión (en inglés.org/documentacion_es/castellano.commit().Persistencia Relacional para Java Idiomático http://www.OVERWRITE: sobrescribir cualquier identificador. ocurre por defecto en los siguientes puntos: antes de algunas ejecuciones de consultas en org.EXCEPTION: lanzar una excepción si ya existe una fila en la base de datos que tenga el mismo fila si su número de versión es más antiguo que el del objeto. Cat cat = session1. dar marcha atrás (rollback) con cambios hechos durante transacciones carentes de integridad transaccional (non-ACID).9.replicate(cat. y muchos más. actualizar la información de configuración del sistema durante la actualización de un producto. "Flush" de la sesión De tanto en tanto la sesión ejecutará los comandos SQL que sean necesarios para sincronizar el estado de la conexión JDBC con el estado de los objetos mantenidos en la memoria. ReplicationMode.openSession(). El ReplicationMode determina cómo el método replicate() lidiará con conflictos que puedan existir con filas existentes en la base de datos.hibernate. 10.close().class. sin tener que regenerar los valores de los identificadores.LATEST_VERSION: sobrescribir la En caso contrario.beginTransaction().beginTransaction(). fila existente en la base de datos que tenga el mismo ReplicationMode.close(). modificaciones e inserciones de elementos en las colecciones todas las inserciones de colecciones todos los borrados de entidades. Transaction tx1 = session1. session2. //reconciliar con la segunda base de datos Session session2 = factory2.openSession().hibernar. identificador. ignorar. .commit().get(Cat.commit() en Session. Replicar un objeto entre dos repositorios de datos distintos Ocasionalmente.m. en el mismo orden en que los objetos hayan sido borrados usando 114 de 198 17/02/2009 09:25 a. es útil poder tomar un árbol de instancias persistentes y hacerlas persistentes en otro repositorio de datos distinto. ReplicationMode.Transaction.IGNORE: ignorar el objeto cuando exista una fila de base de datos con el mismo identificador. 10. catId).html posible violar constraints NOT NULL aplicadas a la columna de clave foránea. Algunos casos de uso para esta característica incluyen: reconciliar datos ingresados en dos instancias distintas de base de datos. por ejemplo si se borra al padre antes que al hijo. flush).HIBERNATE .save() todas las actualizaciones a entidades todos los borrados de colecciones todos los borrados. ReplicationMode.10. session2.flush() Los comandos SQL son ejecutados en el siguiente orden todas las inserciones de entidades. tx2. en el mismo orden en que los objetos hayan sido grabados con Session. Transaction tx2 = session2. ReplicationMode. //obtener un cat de la base de datos Session session1 = factory1. tx1. session1.LATEST_VERSION).

si una operación de creación de datos viola una constraint). “Sesión extendida y versionado automático”). refresh(). los hijos "value type" son grabados también. Durante el "flush". Un caso común es el de la relación padre/hijo..beginTransaction(). evict().2. saveOrUpdate(). Hibernate garantiza que Query. o nunca provocar el "flush" menos que flush() sea invocado explícitamente. sólo acerca del orden en que serán ejecutados. en donde la sesión se mantiene abierta y desconectada por largo tiempo (véase la Sección 11. El valor por defecto. id). eso se debe indicar en el documento de mapeo.load(Cat. sess. // ¡el cambio a izi no ha tenido "flushing"! . y por defecto no hay propagación en cascada de una entidad a sus entidades asociadas. <one-to-one name="person" cascade="persist. // flush occurs sess. Considere el siguiente ejemplo: Si los hijos en una relación padre/hijo fuesen de la índole "value type" (por ejemplo una colección de direcciones. .html Session. // podría devolver datos rancios sess. La clase FlushMode define tres modos diferentes: sólo provocar el "flush" al momento de llamar "commit" (y esto sólo en una transacción de la API de Hibernate). delete().setFlushMode(FlushMode. 115 de 198 17/02/2009 09:25 a. Este último modo es útil para unidades de trabajo largas. Cuando el padre es grabado. su ciclo de vida dependería del padre. especialmente si se está lidiando con un árbol de objetos asociados.commit(). Es posible cambiar el comportamiento por defecto para que el "flush" ocurra menos frecuentemente. e Hibernate lo borrará de la base de datos. no hay absolutamente ninguna garantía acerca de cuándo los llamados JDBC serán ejecutados por la sesión.org/documentacion_es/castellano.3. cascade="none".find("from Cat as cat left outer join cat. Sin embargo. 10. soportan referencias compartidas (así que quitar a una referncia de una colección no significa que pueda ser borrada). lo discutiremos en el Capítulo 11..delete() (una excepción es que los objetos que usen la generación de identificador native serán insertados al invocar save). especifica que ninguna operación debe ser propagada. Como el manejar excepciones involucra algún conocimiento del comportamiento transaccional de Hibernate.class. incluyendo: persist().close(). Las entidades tienen su propio ciclo de vida. puede ocurrir una excepción (por ejemplo.Persistencia Relacional para Java Idiomático http://www. sess = sf. merge(). y no haría falta hacer nada para que la propagación en cascada se efectuare de manera adecuada ante cambios de estado. replicate() hay un estilo de propagación en cascada correspondiente.) nunca devolverá datos rancios. Transaction tx = sess. ya no tiene razón se ser.COMMIT).kittens kitten").lock"/> Incluso se puede usar cascade="all" para indicar que todas las operaciones deben ser propagadas en dirección de esa asociación. Se se quiere que una operación sea propagada en cascada en la dirección de una asociación. como los "value types" no pueden tener referencias compartidas.list(. Ahora considere el mismo escenario. lock(). Por ejemplo: <one-to-one name="person" cascade="persist"/> Los estilos de propagación en cascada pueden ser combinados. categorías e items.11. // permite que las consultas devuelvan datos rancios Cat izi = (Cat) sess. Para cada operación básica de la sesión de Hibernate.m. izi.setName(iznizi). a los hijos también. pero con objetos padre e hijos siendo entidades. Transacciones y concurrencia. no "value types" (por ejemplo. Esto inclusive funciona para operaciones como el borrado de un hijo de una colección: Si un "value type" hijo es borrado de una colección. o gata y gatitos). A excepción de cuando se invoque flush() explícitamente.delete. o de cadenas). provocar el "flush" automáticamente usando la rutina explicada. Persistencia transitiva Es bastante engorroso grabar.openSession(). Hibernate no implementa el el concepto de persistir todo lo que esté al alcance (persistence by reachability) por defecto. cuando se borra al padre. etc. borrar o reasociar objetos individuales. tx.hibernar..HIBERNATE .

HIBERNATE . Mapear una asociación (ya sea de un solo valor. Si un hijo transitorio o desprendido empieza a ser referido por un padre persistente. Normalmente no tiene sentido habilitar la propagación en cascada para asociaciones <many-to-one> o <manyLa propagación es usualmente útil para asociaciones <one-to-one> y <one-to-many>.save-update".html Un tipo especial de propagación en cascada.isCollectionType() ) { 116 de 198 17/02/2009 09:25 a. Todas las operaciones. 10.. Cat fritz = . y quiere ahorrarse algo de tecleo. Pero si usted calcula que deberá trabajar a menudo con el padre y los hijos en la misma transacción. "value types" inmutables y. update() o saveOrUpdate().. todos sus hijos serán también pasados a saveOrUpdate().getClassMetadata(Cat. puede que usted no necesite usar cascade en absoluto.org/documentacion_es/castellano. Un hijo a quien el padre deje de hacer referencia no es automáticamente borrado. save-upate y delete-orphan son transitivas hacia las entidades asociadas cuando ocurre el "flush" de la sesión. o de una colección) con cascade="all" marca la asociación como "del estilo padre/hijo".. una mera referencia a un hijo desde un padre persistente resultará en la grabación/actualización del hijo.. De tanto en tanto. en donde una grabación/actualización/borrado del padre resulta en una grabación/actualización/borrado de los hijos. conviértalo en un objeto de ciclo de vida especificando cascade="all. delete-orphan. si están habilitadas. todos sus hijos serán también pasados a persist() Si se le pasa un padre a un merge(). Usar metadatos Hibernate requiere un modelo muy frondoso. Si el ciclo del vida del hijo está ligado al del padre.delete-orphan". i<propertyNames.hibernar. todos sus hijos serán también pasados a merge() Si se le pasa un padre a un save(). posiblemente. Hibernate expone metadatos mediante las interfaces ClassMetadata y CollectionMetadata. sin embargo. entidades asociadas). En cualquier otro caso. for ( int i=0. Por ejemplo.class). se aplica sólo a las asociaciones de-uno-a-muchos. ClassMetadata catMeta = sessionfactory. no pasa nada en especial: la aplicación debería borrar el hijo explícitamente si hace falta (a menos que haya cascade="delete-orphan". y la jerarquía de Type.m. se le pasa a saveOrUpdate() si un padre es borrado.length. este modelo le es muy útil a la aplicación misma. Object[] propertyValues = catMeta. todos sus hijos le son pasados a delete() Si un hijo deja de ser referido por un padre persistente.merge. Más aún. a un meta-nivel. String[] propertyNames = catMeta. Sin embargo. considere usar cascade="persist. excepto en el caso de una asociación de-uno-a-muchos mapeada con cascade="delete-orphan". Por último. se propagan en cascada hacia todas las entidades que estén a su alcance cuando la operación es ejecutada. Lo inverso no se da. "value types" mutables) y cuáles no (por ejemplo.getPropertyValues(fritz). de todas sus entidades y "value-types".getPropertyTypes(). La semántica exacta de la relación padre/hijo es como sigue: Si se le pasa un padre (como parámetro) a un persist(). e indica que la operación delete() debe ser aplicada a cualquier hijo cuyo padre haya sido borrado.Persistencia Relacional para Java Idiomático http://www. Recomendaciones: to-many>. en cuyo caso la clase el hijo que se ha vuelto huérfano será borrado). la aplicación podría usar los metadatos de Hibernate para implementar un algoritmo inteligente de "copia profunda" (deep copy) que entienda cuáles objetos deben ser copiados (por ejemplo.isEntityType() && !propertyTypes[i]. Instancias de las interfaces de metadatos se obtienen de la SessionFactory.12. note que la propagación de operaciones en cascada se le puede aplicar a un objeto al momento de invocarlo o al momento de efectuar "flush".getPropertyNames(). // obtiene un Map de todas las propiedades que no sean colecciones o asociaciones Map namedValues = new HashMap(). Type[] propertyTypes = catMeta. .. i++ ) { if ( !propertyTypes[i]..

Le recomendamos que pase un buen tiempo revisando la documentación sobre JDBC. es "una sesión por cada solicitud" (sessionper-request) .1. Hibernate no efectúa "lock" de objetos en memoria. usando la sintaxis SELECT FOR UPDATE.org/documentacion_es/castellano. gracias a la sesión.1. para reducir las posibilidades de conflictos de "lock" en la base de datos. La sesión y el alcance (scope) de las transacciones La fábrica de sesiones (SessionFactory) es un objeto seguro en cuanto al acceso por threads múltiples (thread-safe).m. Si aplicación puede esperar el comportamiento que esté definido por el nivel de aislamiento de sus transacciones de base de datos. dado que es improbable que un conjunto de muchas pequeñas transacciones tenga mejor performance que una unidad de trabajo claramente definida. casi nunca es una buena idea. Además de versionar para lograr un control de concurrencia optimista. Note que. es decir. Hibernate usa directamente las conecciones JDBC y los recursos de JTA sin agregar ningún mecanismo adicional de "locking".HIBERNATE . El patrón más común. Se la concibió para ser compartida por todos los threads de la aplicación. se discuten más adelante en este capítulo. y son agrupados en unidades de trabajo atómicas. y consultas de entidad (no consultas "de reporte" que devuelvan valores escalares). los llamdos a la base de datos son hechos en un orden planificado.Persistencia Relacional para Java Idiomático http://www. ni una fuente de datos (Connection. y cómo funciona el aislamiento de transacciones en su base de datos en particular. Datasource) a menos que sea necesario. Por tal motivo. no consume recursos mientras no es usada. Hibernate inhabilita el auto-commit inmediatamente. ¿Cuál es el alcance de una unidad de trabajo? ¿Una simple sesión de Hibernate puede abarcar varias transacciones de base de datos. y esta API. Hibernate provee lecturas repetibles para la búsqueda por identificadores. Una sesión no intentará obtener una conexión de JDBC. para una interacción simple o "request" (una sola solicitud. El control de concurrencia optimista. o sus alcances son similares y con una relación uno a uno? ¿Cuándo se debe abrir y cerrar una sesión. 11.html namedValues.hibernar. Una sesión individual (Session). Las transacciones de base de datos nunca son opcionales. no abra y cierre una sesión para cada llamado a la base de datos en un mismo thread! En una aplicación. esta modalidad de trabajo es más acorde con trabajo ad-hoc en una consola SQL. toda comunicación con la base de datos debe ocurrir dentro de una transacción. y la sesión. la fábrica de sesiones (SessionFactory). Por lo tanto. así como las transacciones de base de datos y las conversaciones largas. propertyValues[i] ). Se espera que sea usada una sola vez. ANSI. Hibernate también ofrece una API (mínima) para efectuar un "lock" de filas pesimista. que es también un caché con alcance a la transacción. Una transacción de base de datos debe ser lo más corta posible. y no es segura en cuanto al acceso por múltiples threads (no es "threadsafe"). en una aplicación cliente/servidor multiusuario. ya sea para escribir o para leer datos. Transacciones y concurrencia El punto más importante acerca de Hibernate y el control de concurrencia. es que es muy fácil de entender. (Nótese que esto también significa que tener la conexión en auto-commit después de cada comando SQL es inútil en una aplicación. el comportamiento "auto-commit" debe evitarse. Las transacciones largas impiden que la aplicación sea "escalable" (es decir. a partir de una instancia de Configuration. o espera que el servidor de aplicaciones lo haga). que se adapte con facilidad a una mayor demanda y tamaño). y cómo se demarcan los límites de una transacción de base de datos? 11. una sola "conversación" o "unidad de trabajo"). normalmente durante el arranque de la aplicación. Para completar este panorama se debe pensar también en las transacciones de base de datos. y es costosa de crear. } } Capítulo 11. por no poder soportar una mayor carga de demandas concurrentes.1. mantener una transacción abierta mientras el usuario "piensa" y hasta que la unidad de trabajo se complete. es barata de crear. Esta última es también más flexible y extensible. Se la crea una sola vez. . una solicitud o "request" del cliente se envía al servidor (en donde está ejecutándose la 117 de 198 17/02/2009 09:25 a. no emplee la práctica desaconsejada (antipattern) de una-sesión-por-operación. Según este modelo. Unidad de trabajo ¡Antes que nada. Como se dijo anteriormente. en cambio.put( propertyNames[i]. y luego sea descartada. Comenzaremos la discusión sobre el control de concurrencia en Hibernate involucrando los conceptos de configuración (Configuration).

sessionFactory. es comenzar una transacción cuando haya que procesar una solicitud (request) al servidor. y manejar lo que se considera la "sesión actual". y garantizar aislamiento y atomicidad. etc.5. antes de que la presentación de ninguna view hubiere comenzado. que abarque varios ciclos solicitud/respuesta). Hibernate ya trae un sistema incluido que se puede usar para simplificar el uso de este patrón. dado que la transacción se completará tras el return de los métodos de los EJBs. Una vez que el trabajo se haya completado (y la respuesta para el cliente se haya preparado). Muchos procesos de negocios requieren toda una serie de interacciones con el usuario. no es aceptable que una transacción de base de datos dure a lo largo de toda la interacción con el usuario. Extender la transacción de base de datos hasta que la "view" sea presentada es fácil si se implementa un interceptor propio. especialmente si se utilizan las ventajas que provee Hibernate: Versionado automático: Hiebernate puede efectuar automáticamente por usted un control de concurrencia optimista. prefiérase la API de Transaction de Hibernate. puede detectar automáticamente si ocurrió una modificación durante el tiempo que el usuario se tomó para reaccionar.html capa de persistencia Hibernate). Esto se puede lograr de varias maneras: las soluciones más comunes son: -un filtro (ServletFilter) -un interceptor basado en AOP. Hay varias maneras de implementar esto en su aplicación. El desafío radica en la implementación. Será atómica si sólo una de dichas transacciones (la última) es la que almacena los datos modificados. Conversaciones largas El patrón "una-sesión-por-solicitud" (session-per-request) no es el único concepto útil que puede usarse para diseñar unidades de trabajo. una práctica a evitar o "anti-patrón" (antipattern). se abre una nueva sesión. El código de su aplicación puede acceder a la "sesión actual" para procesar una request. los datos que ve el usuario han sido cargados en una sesión y transacción de base de datos en particular. Si se decide usar la demarcación de transacciones programática. . una conversación (o transacción de la aplicación). todas las otras simplemente leen datos (por ejemplo.getCurrentSession() A veces es conveniente extender los alcances de la sesión y de la transacción de base de datos hasta que la vista o "view" le haya sido presentada al usuario. las cuales utilizan una fase separada de presentacíón posterior al procesamiento de la solicitud o "request". esto sólo se verifica al final de la conversación. que es fácil y portátil. y tan a menudo como haga falta. Considere el siguiente ejemplo: Aparece la primera ventana de diálogo. Siempre se obtendrá una sesión que estará dentro del alcance o "scope" de la transacción de base de datos actual. Una manera estándar de implementar aspectos que conciernen de una misma forma a varios niveles y áreas de la aplicación (en inglés. por supuesto. respectivamente. el cual puede implementar transacciones de una manera declarativa y manejada por el contenedor mismo (CMT).m. y que no puedan haber ocurrido otras modificaciones conflictivas. la sesión sufre un "flush" y se cierra. El usuario es libre de modificar los objetos. La relación entre sesión y transacción es una a una. entretejidas con accesos a la base de datos. A esto le llamamos una "unidad de trabajo". es usar un contenedor de EJB.2. En las aplicaciones de web y corporativas. Esto es especialmente útil en aplicaciones basadas en servlets. en una ventana de diálogo tipo "paso a paso" o "wizard". "cross-cutting aspects"). 11. simplemente invocando en cualquier lugar. ya sea para entornos de recursos locales o para JTA (véase la Sección 2. Sin embargo. También se usaría una sola transacción de base de datos para atender la solicitud del cliente. y espera que sus modificaciones sean hechas persistentes. dado que los conflictos de lock no le permitirán a nuestra aplicación adaptarse a una mayor demanda por usuarios concurrentes. mantener un aislamiento entre los procesos de negocio se vuelve en parte responsabilidad de la capa de la aplicación. Esto tiene que ser configurado. comenzándola y efectuando "commit" cuando se abra y cierre la conexión. Visite el sitio de web de Hibernate para consejos y ejemplos acerca de este patrón Open Session in View. Esto es. Todo lo que el programador debe hacer. -un contenedor de proxies/intercepciones. lo cual ejerce un "lock" sobre la base de datos para impedir modificaciones concurrentes.1. En este caso. El usuario pulsa "Grabar" luego de 5 minutos. y este modelo es perfectamente adecuado para muchas aplicaciones. Claramente. que tenga sus "pointcuts" en los métodos del servicio. también espera haber sido la única persona que haya editado esa información. “Sesiones contextuales”. no es fácil de hacer si uno se apoya en un EJBs con transacciones CMT. Usualmente. debemos usar varias transacciones de BD para implementar la conversación. Esto es más fácil de implementar de lo que parece. y finalizar la transacción antes de que la respuesta le sea enviada al cliente.HIBERNATE .hibernar. Una simple conversación normalmente abarca varias transacciones de base de datos. 118 de 198 17/02/2009 09:25 a. y todas las operaciones de base de datos son ejecutadas e esta unidad de trabajo. desde el punto de vista del usuario. Una primera implementación ingenua sería manetner la sesión y la transacción de base de datos abiertas durante el tiempo que el usuario se tome para pensar.Persistencia Relacional para Java Idiomático http://www.org/documentacion_es/castellano.

Sólo necesitan poder establecer.HIBERNATE . Este patrón se conoce como una-sesión-por-conversación y hace que la reasociación de objetos sea innecesaria. Las cosas que se supone funcionen en forma concurrente. (esto es.html Objetos desprendidos: si se decide usar el patrón una sesión por solicitud (session-per-request) ya discutido. Asegúrese de que entiende las implicancias de la decisión de diseño que tome. Esto puede ocurrir incluso en lugares insólitos. todas las instancias cargadas se convertirán en "desprendidas" (detached) durante el tiempo que el usario se tome para pensar. Hibernate le permite reasociar estos objetos y persistir las modificaciones. Las discutiremos más adelante. Los atributos de las "claves de negocio" no necesitan ser tan estables como las claves primarias de una base de datos. 11. dado que garantizar la identidad sólo a nivel de unidades de trabajo en un thread simple no requiere un costoso "lock" ni otros medios de sincronización. Ambos patrones. los session beans. . Dentro de una sesión. use una "clave de negocios". usando el enfoque optmista. que representen la misma fila) pero no la misma identidad JVM. e implementar su propia noción de igualdad entre objetos.org/documentacion_es/castellano. y a la sesión no se le permite hacer "flush" automático. Note que los problemas que listamos a continuación pueden aparecer incluso si se están usando los patrones que sí recomendamos. una combinación única y normalmente inmutable de atributos. en el contexto del control de concurrencia optimista.getId() ) Identidad de JVM foo==bar Entonces.1. La aplicación no necesita sincronizar ningún objeto. como las HTTP requests. la aplicación puede usar == tranquilamente para comparar objetos. si se colocan dos instancias desprendidas en el mismo Set. Si la sesión de Hibernate está contenida en una sesión de HTTP 119 de 198 17/02/2009 09:25 a. hay dos nociones diferentes de identidad: Identidad de base de datos foo.m. una aplicación que use == fuera de una sesión.4.1. En este caso la identidad persistente o de base de datos existe. 11.equals( bar. puede haber raras excepciones a esta regla). También provee la mejor "escalabilidad". También note que éste no es un problema de Hibernate. Una sesión (Session) no es segura en cuanto a acceso concurrente por múltiples threads (no es "thread-safe"). este patrón se llama una-sesiónpor-solicitud-con-objetos-desprendidos. existe la posibilidad de que ambas tengan la misma identidad de base de datos (es decir. Para aislar modificaciones concurrentes se usa versionado automático.Persistencia Relacional para Java Idiomático http://www. Sin embargo. causarían condiciones de conflicto por recursos conocidas como "race conditions" si la instancia de una sesión de Hibernate fuese compartida.3. si la aplicación accede en forma concurrente al mismo dato. Estos conflictos se resuelven a nivel usando versionado automático (cuando ocurren los "flush"/"commit"). de manera estable. Este enfoque deja que Hibernate se preocupe por la concurrencia. sino explícito. Pero una instancia de una clase persistente nunca se comparte entre dos instancias de Session. los objetos son "diferentes". e Hibernate garantiza que la identidad JVM equivale a la identidad de BD. Sólo una advertencia: nunca use el identificador de base de datos para implementar igualdad. pero la identidad de JVM no. El programador debe sustituir los métodos equals() y hashCode() en las clases persistentes. Sin embargo. puede ocurrir que la misma identidad persistente esté contenida en dos instancias de objeto en dos sesiones distintas. y reconectada cuando ocurra una nueva solicitud del cliente. una-sesión-por-spolicitud y una-sesión-por-conversación tienen ventajas y desventajas. para objetos asociados a una sesión en particular. siempre y cuando se atenga a que se usará un solo thread por sesión. en el mismo alcance o "scope" de una sesión) las dos nociones son equivalentes. Problemas comunes Nunca use los anti-patrones una-sesión-por-cada-interacción-con-el-usuario ni una-sesión-para-toda-la-aplicación (por supuesto. por ejemplo. diferencias o igualdad entre los objetos que estén en un Set.hibernar. Vea el sitio de web de Hibernate para una discusión más detallada sobre este tema. Para aislar modificaciones concurrentes se usa versionado automático. Por lo tanto. sino la manera en que los objetos de Java implementan identidad e igualdad. se puede topar con resultados inesperados. Sesión larga (o "extendida"): la sesión de Hibernate puede desconectarse de la conexión JDBC subyacente luego de que la transacción haya ejecutado su commit. cambiar el hashcode rompe el contrato del Set. Si la instancia transitoria es almacenada en un Set.getId(). Considerar la identidad de los objetos Una aplicación puede aceder en forma concurrente al mismo estado persistente en dos sesiones diferentes. o los workers de Swing workers.

se debería considerar el sincronizar el acceso a la sesión HTTP. 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. pero no hay ninguna desventaja ni se puede dar ninguna razón en contra de demarcar explícitamente. No puede ocurrir ninguna comunicación con la base de datos si no es dentro de una transacción. incluso al leer datos. En tal caso. El programador tiene que establecer los limites de las transacciones manualmente (en otras palabras. pero lo que más probablemente se debería considerar es un procedimiento de base de datos almacenado (stored procedure) si se necesitan operaciones masivas de datos. Siempre deben emplearse límites de transacción claros. la cual se discute más adelante). es invocar clear() y evict() para manejar el caché de la sesión. ciertamente tendrá mucha mejor performance que múltiples pequeñas transacciones.html (HttpSession. debe detenerse la aplicación. De otra manera. . incluso para las operaciones de lectura. a menos que el código esté en un session bean. Dependiendo del niverl de aislamiento y de las posibilidades de la base de datos. Sin embargo. Un entorno "administrado". las coneiones a la base de datos usualmente son manejadas por un "pool" de conexiones simple (es decir. esto puede no ser obligatorio. Procesamiento en lotes. la demarcación manual o "programática" de las transacciones no es necesaria. Esta API es opcional.2. Una aplicación de Hibernate puede ser ejecutada en un entorno "no manejado". En un entorno "no manejado". La sesión almacena en su caché cada objeto que esté en estado persistente (habiendo vigilado y comprobado Hibernate si su estado es "sucio"). significa que hay que desandar (rollback) la transacción de base de datos. pero recomendamos usarla siempre. y también en entornos J2EE "administrado" (managed environments). commit y rollback de las transacciones él mismo). 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.Persistencia Relacional para Java Idiomático http://www. no una DataSource) del cual Hibernta obtiene las 120 de 198 17/02/2009 09:25 a.hibernar.. Demarcación de transacciones de base de datos La demarcación de las transacciones de base de datos (o de sistema) siempre es necesaria. Usualmente. Mantener una sesión abierta durante toda la interacción con el usuario también aumenta la probabilidad de que los datos se vuelvan "rancios". Esto significa que crecerá para siempre.m. "no administrado" (es decir.2. autosuficiente. Una única transacción de base de datos. 11. y cerrar la sesión inmediatamente (como se discute luego en más detalle).1.HIBERNATE . siempre. Si Hibernate produce una excepción. Hibernate normalmente es responsable por su propio "pool" de conexiones. normalmente provee transacciones administradas por el contenedor ("container-managed transactions o CMT por sus siglas en inglés).en ambos casos. una simple aplicación de web o Swing). ahora le daremos una mirada más detallada a la demarcación de transacciones y al manejo de excepciones. Entornos no administrados Si la capa de persistencia e Hibernate se ejecuta en un entorno no-administrado. Algunas soluciones se muestran en el Capítulo 13. dentro de un servidor con CMT.org/documentacion_es/castellano. es probable que termine usando la misma sesión (de Hibernate) en dos threads ejecutándose en forma concurrente. invocar los métodos begin. Si la sesión está asociada a la aplicación. porque las excepciones no son recuperables. a veces es deseable mantener la capa de persistencia portátil entre entornos administrados y no administrados. Efectuar un "rollback" de la transacción no restaura los objetos de negocio al estado en el que estaban antes de que la transacción ocurriese. y de todos modos es necesario comenzar todo de nuevo luego de un "rollback". (Esto parece confundir a algunos programadores acostumbrados a trabajar siempre en modo "auto-commit"). finalizar una sesión involucra las siguientes fases: invocar el "flush" de la sesión invocar "commit" en la transacción de base de datos cerrar la sesión manejar las excepciones que hayan podido ocurrir Efectuar el "flush" de la sesión ha sido discutido antes. tanto en un entorno administrado como no administrado. hasta provocar un error de memoria (OutOfMemoryException) si se la deja abierta por mucho tiempo o simplemente se le cargan demasiados datos. cualquier usuario que cliquee "reload" lo suficientemente rápido. los límites de una transacción. con la disposición de las tranascciones definida declarativamente en los archivos de descripción de despliegue o "deployment descriptors" de los session beans EJB. por ejemplo. 11. Una solución para esto. Utilizar la demarcación programática se puede usar.

el código que ejecuta los llamados a Hibernate. Transaction tx = null. El estilo de manejo de sesión/tranascción se ve así: // Non-managed environment idiom Session sess = factory. de sistema. El "manejo de contexto actual" hecho por Hibernate puede simplificar este diseño considerablemente..2.html conexiones que necesite. Usar JTA Si la capa de persistencia se ejecuta en un servidor de aplicaciones (por ejemplo.transaction. tx. Un llamado a close() marca el fi de la sesión. Hibernate ofrece dos estrategias para integración con JTA: Si se usan tranascciones manejadas por beans (bean-managed transactions o BMT por sus siglas en inglés). // efectuar algo de trabajo .getTransaction().hibernate.JDBCTransactionFactory (el valor pord efecto). try { 121 de 198 17/02/2009 09:25 a. Este código Java es portátil. y.rollback(). } No hace falta invocar el "flush" de la sesión explícitamente: el llamaod a commit() dispara automáticamente la sincronización (dependiendo del Modo de "flush" para la sesión. throw e.rollback().beginTransaction().close(). Hibernate le dirá al servidor de aplicaciones que empiece y finalice una transaccción BMT si se usa la API de Transaction API. En otras plabras.. y usarla sin EJB. y puede ejecutarse tanto en entornos administrados como no administrados.openSession(). throw e. // efectuar algo de trabajo . deberían ser capturadas en la capa superior.getTransaction(). le código e manejo de transacciones para un entorno no administrado es idéntico al de un entorno administrado.getCurrentSession(). el valor "thread" para hibernate.commit().getCurrentSession(). El manejo de excepciones se discute más adelante en este capítulo. en la capa de persistencia. .HIBERNATE . } catch (RuntimeException e) { if (tx != null) tx.org/documentacion_es/castellano.beginTransaction(). Una solución muchio más flexible (que ya viene incorporad en Hibernate).commit(). cada conexión de base de datos obtenida por Hibernate será automáticamente parte de la transacción global JTA. // o mostrar un mensaje de error } finally { sess. y el código que maneja las RuntimeExceptions (y normalmente hace las tareas de limpeza y salida) están en capas diferentes. También se puede instalar una implementación JTA autónoma. La implicancia más importante de close() es que la conexión JDBC será cedidad por la sesión. detrás de EJB session beans). // o mostrar un mensaje de error } Se podrán encontrar fragmentos de código como éstos en cualquier aplicación normal..current_session_context_class.openSession(). } catch (RuntimeException e) { factory. De este modo. Note que debería seleccionarse org.getCurrentSession(). 11. Las excepciones fatales. try { tx = sess..m. // Estilo para un entorno no-administrado con getCurrentSession() try { factory.hibernar.Persistencia Relacional para Java Idiomático http://www. como se describión anterioromente. factory. Transaction tx = null. todo lo que se necesita es accedeso a la SessionFactory. // estilo BMT Session sess = factory. es el manejo del contexto de "sesión actual". para el segundo ejemplo.2.

.CMTTransactionFactory en un session bean CMT.hibernate. // o mostrar un mensaje de error } finally { sess.. La operación getCurrentSession() tiene una desventaja en un entorno JTA:.hibernate. no se hace programáticamente.). Cuando se elige la fábrica (factory) de transacciones.html tx = sess. // efectuar algo de trabajo . } catch (RuntimeException e) { tx. factory.2.getCurrentSession().).commit().persist(. la mayoría de las aplicaciones pueden fácilmente evitar usar en absoluto scroll() o iterate() en el código JTA o CMT). Hay una advertencia sobre el uso del modo de liberación de conexiones after_statement.rollback()..load(.. Así que el código queda reducido a: // estilo CMT Session sess = factory. invocar Session. Usted debe liberar el cursor de base de datos subyacente invocando explícitamente cursor by calling ScrollableResults.rollback(). es decir.hibernar. se debería efectuar un rollback de la transacción de base de datos inmediatamente. Más aún.begin(). Esto significa que no hace falta usar la API de Transaction API de Hibernate en absoluto con BMT or CMT. tx. (Por supuesto. En un entorno CMT/EJB incluso el rollback ocurre automáticamente. asegúrese de que su hibernate.. e igualmente se obtiene propagación automática de la sesión "actual" asociada a la transacción. tx.. // efectuar algo de trabajo .HIBERNATE . 11. } Si se desea usar la sesión asociada a una transacción. Ninguna excepción generada por Hibernate puede ser tratada 122 de 198 17/02/2009 09:25 a. } catch (RuntimeException e) { if (tx != null) tx.m.close() o Hibernate.current_session_context_class ha sido o bien eliminado (por compatibilidad hacia a trás o "backwards compatibility"). throw e. Manejo de excepciones Si la sesión provoca una excepción (incluida cualquier SQLException). note que debería elegirse org. la funcionalidad getCurrentSession() para una más fácil propagación del contexto.commit().Persistencia Relacional para Java Idiomático http://www.getCurrentSession().close(Iterator) en el bloque finally..JTATransactionFactory si se usa JTA directamente (BMT).lookup("java:comp/UserTransaction"). la demarcación de transacciones se hace en los descriptores de despliegue (dployment descriptors) del session bean.close(). tx. el cual es el valor por defecto.getCurrentSession(). para Hibernate no es posible limpiar automáticamente instancias no cerrada de ScrollableResults o Iterator que hayan sido devueltas por scroll() o iterate(). // efectuar algo de trabajo con la sesión asociada a la transacción factory.3.beginTransaction(). .transaction. puesto que una RuntimeException no capturada emitida por el método de un session bean le dice al contenedor que efectúe rollback en la transacción global. se debe usar la API de JTA UserTransaction directamente: // estilo BMT con getCurrentSession() try { UserTransaction tx = (UserTransaction)new InitialContext() . o bien puesto a "jta". Debido a una tonta limitación de la especificación JTA. y debería usarse org.org/documentacion_es/castellano.close() y descartar la instancia de la sesión. Algunos métodos de Session no dejarán a la sesión en un estado consistente.transaction. // o mostrar un mensaje de error } Con CMT. throw e..

. un error en la comunicación con la JDBC subyacente un error sintáctico o gramatical con el SQL emitido alguna forma de violación de una constraint de integridad ConstraintViolationException: indica LockAcquisitionException: indica un error al adquirir el nivel de "lock" necesario para efectuar la operación solicitada.getCause(). Pero es posible enchufar una implementación a medida (ver los javadocs para la clase SQLExceptionConverterFactory por detalles).rollback(). la cual nunca es provista por un entorno no administrado.html como recuperable. Note que Hibernate puede también emitir otras exceptiones. Éstas son. sess. GenericJDBCException: una excepción genérica que no cae en ninguna de las otras categorías. En nuestra opinión. } Note que setTimeout() no puede ser llamada desde un bean en CMT. Control optimista de concurrencia 123 de 198 17/02/2009 09:25 a. De hecho. En la mayoría de los sistemas. Los subtipos estándar de JDBCException son: JDBCConnectionException: indica SQLGrammarException: indica HibernateException. y se debe adoptar las medidas apropiadas para lidiar con ellas. En un entorno administrado.. es una excepción del tipo "unchecked" (esto es. sess. Sin embargo. el SQLExceptionConverter es definido de acuerdo al dialecto SQL elegido.setTimeout(3).Persistencia Relacional para Java Idiomático http://www.openSession(). Hibernate convierte las SQLException en subclases apropiadas de JDBCException usando el conversor SQLExceptionConverter que está asociado a la fábrica SessionFactory.HIBERNATE . como EJB. // do some work . las excepciones "unchecked" son manejadas en uno de los primeros "marcos" de la pila de invocaciones a métodos (es decir. no se debería forzar al programador a capturar excepciones de bajo nivel en la capa de persistencia. La SQLException subyacente está siempre disponible via JDBCException. de nuevo.getTransaction(). Session sess = factory. No lo era en versiones anteriores de Hibernate. o se adopta algún otro curso de acción apropiado. puede al menos controlar las operaciones de acceso a datos. es la expiración de las transacciones. POr defecto.hibernar.getTransaction(). Asegúrese de que la sesión será cerrada invocando close() en el bloque finally. Expiración de transacciones Una característica extremadamente importante provista por un entorno aministrado.m.getTransaction(). try { //set transaction timeout to 3 seconds sess. Hibernate no puede proveer esta funcionalidad en forma completa. Fuera de un entorno administrado (JTA). 11. en las capas más "altas" de la aplicación). Hibernate puede delegar el "timeout" de las transacciones en JTA. no recuperables.4. // or display error message } finally { sess.2. . y se le presenta un mensaje de error al usuario de la aplicación.getTransaction(). la cual envuelve la mayoría de los errores que ocurren en la capa de persistencia de Hibernate. Hibernate envuelve las excepciones SQLException generadas al interactuar c con la base de datos en una JDBCException. además de HibernateException. o "transaction timeout". asegurándose de que los "puntos muertos" (deadlocks) y las consultas con resultados enormes estén limitadas a un tiempo definido.3. throw e. Hibernate intentará convertir la excepción en una subclase de JDBCException que tenga más sentido.begin(). Los "timeouts" de las transacciones que ninguna trnasacción "rebelde" ocupe indefinidamente los recursos del sistema sin devolverle respuesta alguna al usuario.commit() } catch (RuntimeException e) { sess. Esta funcionalidad es abstraída por el objeto Transaction de Hibernate. que no requiere captura obligatoriamente en tiempo de compilación).close(). 11.org/documentacion_es/castellano. en donde los "timeouts" de las transacciones son definidos declarativamente.

Esta estrategia es la más eficiente en términos de acceso a la base de datos.close().commit(). para detectar adtualizaciones conflictivas (y evitar que se pierdan modificaciones).3. A menudo hay que chequear no sólo instancias simples. Este enfoque fuerza a la aplicacíón a efectuar su propio chequeo de versiones.beginTransaction(). y no se requiere un chequeo de versiones. el chequeo manual de versiones sólo es factible en circunstancias muy triviales. Chequeo de versión hecho por la aplicación En una implementación sin mucha ayuda de Hibernate. int oldVersion = foo.commit().load( foo. session. se puede usar este abordaje pero saltearse el chequeo de versiones. La propiedad version se mapea usando <version>. Hibernate chequea las instancias de las versiones cuando ocurre el "flush".org/documentacion_es/castellano. session. dado que pueden experimentar pérdidas de actualizaciones sin mensajes de error.3.getVersion(). o sufrir la posibilidad de conflictos cuando los cambios se sincronicen.close(). El chequeo de versiones usa números de versión. session. Sesión extendida y versionado automático Una sola instancia de sesión y sus clases persistentes son usadas por toda la conversación (lo cual se conoce como una-sesión-por-conversación).hibernar. (N. son locuciones que se usan en inglés como ejemplos de nombres para cualquier cosa. o timestamps. Claramente. y el programador es responsable de recargar todas las instancias persistentes desde la base de datos antes de manipularlas.m. e Hibernate incrementará el número automáticamente durante el "flush" si la entidad está sucia. cada interacción con la base de datos ocurre en una nueva sesión.openSession(). es el control de concurrencia optimista con versionado. ni tiene que recargar instancias en cada transacción de base de datos.T):"foo" y "bar".beginTransaction(). Hibernate ofrece chequeo automático de versión. . // foo es una instancia cargada por una sesión previa session = factory. o "instancais desprendidas". t.del. Los casos de uso que mostraremos ocurren en el contexto de una conversación larga.html El único abordaje consistente con una alta concurrencia y un alta "escalabilidad".getVersion() ) throw new StaleObjectStateException(). La aplicación no necesita preocuparse por chequear versiones o reasociar instancias desprendidas.getKey() ). comienza la transac foo. session. Transaction t = session. La sesión es desconectada de toda conexión JDBC subyacente mientras se espera que el usuario complete su interacción.flush(). foo. // sólo para la última transacción de la conversación // tambien devuelve la conexión JDBC // sólo para la última transacción de la conversación 124 de 198 17/02/2009 09:25 a. si se opera en un entorno de baja concurrencia de datos.Persistencia Relacional para Java Idiomático http://www. 11. Tenga en cuenta que esto puede confundir a los usuarios de la aplicación.2. // obtiene una nueva conexión JDBC. 11.setProperty("bar"). y en la mayoría de las aplicaciones no es práctico. En tal caso. de origen incierto. Hibernate ofrece 3 enfoques distintos para escribir una aplicación que use concurrencia optimista. pero el chequeo de versiones tiene la ventaja de también prevenir la pérdida de modificaciones en transacciones de base de datos simples.1. // foo es una instancia cargada anteriormente por una sesíón anterior Transaction t = session.setProperty("bar"). Por supuesto. para asegurar el aislamiento en al conversación transaccional. t. El capturar y manejar estas excepciones queda a cargo del programador (opciones comunes que se le dan al usuario son: sincronizar los cambios manualmente. Este abordaje es el menos eficiente en términos de acceso a la base de datos. especialmente en el ámbito de la computación. o recomenzar la conversación de negocios con datos que no estén "rancios"). y es el más parecido a los "entity beans" de EJB. sino todo un árbol de objetos modificados. la estrategia por defecto para conversaciones largas será "el último commit es el que gana".HIBERNATE . emitiendo una excepción si se detecta modificaciones concurrentes. usando uno de estos paradigmas de diseño: "sesión extendida". // cargar el estado actual if ( oldVersion != foo. Si se usa "foo" como nombre en un ejemplo. casi siempre se espera que el siguiente nombre sea "bar". foo.

y usar LockMode. // use merge() si "foo" puede haber sido cargada anteriormente t.beginTransaction(). // foo es una instancia cargada en una sesión previa foo.setProperty("bar"). Se puede también invocar lock() en lugar de update(). El patrón de "sesión extendida" una-sesión-por-conversación. es más difícil de implementar con control automático del contexto de sesión actual. lanzando una excepción si han ocurrido actualizaciones conflictivas. Objetos desprendidos y versionado automático Cada interacción con el repositorio persistente ocurre en una nueva sesión. Sin embargo.HIBERNATE . Session.saveOrUpdate(foo).update(). conceptualmente.saveOrUpdate(). las mismas instancias persistentes son reusadas para cada interacción con la DB. Para forzar un chequeo de versión sin un mapeo de versión o timestamp. orignialmente cargadas en otra sesión. sólo esta última transacción de BD incluiría la operación flush(). si Hibernate puede comparar el estado nuevo con el viejo. simepre y cuando los cambios que hayan sido efectuados no se superpongan.html El objeto foo todavía sabe en qué sesión fue cargado. Hibernate chequeará ls versiones de instancia al ocurrir el "flush". session. Hibernate no incrementará más las versiones. Por eso. y comenzar y terminar una transacción tiene el mismo efecto). Note que esto sólo funciona. La aplicación manipula el estado de las instancias desprendidas.READ (efectuando un cheque de versión. se puede invocar Session. Por ejemplo. Tras la reconexión.close().merge(). U otras aplicaciones pueden estar accediendo a dichas base de datos. De nuevo. en realidad. (Note que versiones anteriores de Hibernate requerían que la sesión se conectara y desconectara explícitamente.lock() con LockMode. session. En otras palabras. or Session.4. En ambos casos. Dichos métodos ahora son obsoletos (deprecated). Este patrón es problemático si la sesión es demasiado grande para como para ser almacenada durante el tiempo que el usuario se toma para reaccionar.3. Efectuar un "commit" de una transacción de base de datos desconecta una sesión de la coinexión JDBC y devuelve la conexión al "pool". una HttpSession debería mantenerse tan chica como sea posible. con una comparación del estado de todos los campos en una fila. y lyego las reasocia usando Session. y contiene todos los objetos cargados. probablementa sólo podamos usar esta estrategia en uns pocos ciclos solicitur/respuesta. Como la sesión es también el caché de primer nivel.m. sin saber cómo manejar números de versiones ni incluso timestamps. . y no la transfiera al entorno de web (ni siquiera la serialice para transferirla a otra capa separada) para almacenarla en una HttpSession. Para esto se necesita proveer una implementación a medida de CurrentSessionContext. se le debe asignar FlushMode. Una sesión debería usarse para una sola conversación. de manera que. También note que se debería mantener la sesión desconectada cerca de la capa de persistencia. sólo a la última transacción de base de datos se le permita persistir todas las modificaciones hechas durante esa conversación. si se usa una sola sesión larga y no una-sesión-por-solicitud-con-objetosdesprendidos. session = factory.org/documentacion_es/castellano. Vea la Wiki de Hibernate para ejemplos: 11. Si se asigna optimistic-lock="dirty" al mapear la <class>. Comenzar una nueva transacción de base de datos en una sesión vieja. dado que pronto contendrá datos "pasados". habilite optimistic-lock="all" en el mapeo de <class>. Crear un método a medida para el versionado automático Se puede inhabilitar el incremento automático de versión de Hibernate para propiedades y colecciones específicas. eludiando todos los cachés) si se está seguro de que el objeto no ha sido modificado.MANUAL a una sesión extendida. para forzar un chequeo de versión en los datos que no se estén actualizando.hibernar.openSession().commit(). A veces la modificacion concurrente puede ser permitida. Usted no necesita un "lock" sobre cualquier dato que usted esté actualizando.3. si la propiedad está sucia. Usualmente. obtiene una nueva conexión y reanuda la sesión. Hibernate sólo comparará los campos sucios 125 de 198 17/02/2009 09:25 a. asignándole al atributo de mapeo optimistic-lock el valor false. 11.Persistencia Relacional para Java Idiomático http://www. use un "stateful session bean" de EJB para contener la sesión en un entorno de tres capas. y luego también el llamado de la sesión a close() para cerrar la conversación. es decir. Transaction t = session.READ en cualquier objeto que pueda haber sido actualizado por otra transacción. el versionado no puede basarse en una columna en particular de una tabla.3. Los sistemas de base de datos anticuados a menudo son estáticos y no pueden ser modificados.

Session.UPGRADE adquiere automáticamente cuando Hibernate actualiza o inserta una fila. especificando un LockMode.4.x introdujo la sesión de "modos de liberación de conexiones".. Modos de liberación de conexiones El antiguo comportamento de Hibernate (2. ser adquirido ante una solicitud explícita del usuario. Un lock se obtiene por los mecanismos siguientes: LockMode. Un llamado a Query. FOR UPDATE). Un llamado a Session. se usa SELECT . asignando select-before-update="true" em el mapeo de <class>. y luego se aferraba a dicha conexión hasta que la sesión se cerrara. LockMode. FOR UPDATE.setLockMode(). LockMode. usando SELECT . Hibernate usará un modo alternativo apropiado (en lugar de emitir una excepción). ¡nunca "lock" de objetos en memoria! La clase LockMode define los distintos niveles de "lock" que pueden ser adquiridos por Hibernate. o con comparación completa/de campos sucios. UPGRADE o UPGRADE_NOWAIT.m. 11. Si la base de datos no soporta el lock mode solicitado.READ es adquirido automáticamente cuando Hibernate lee datos bajo los niveles de aislamiento "Repeatable Read" o "Serializable".html cuando ocurra el "flush".. Hibernate usa un solo comando UPDATE (con una cláusula WHERE apropiada) por entidad para ejecutar el chequeo de versión y actualizar la información. Hibernate invoca lock() para dicho objeto. Esto normalmente no es un problema. Hibernate siempre usará el mecanismo de lock de la base de datos. No obstante. antes de actualizar la fila. sólo es pertinente para conexiones provistas a través de un ConnectionProvider.HIBERNATE . cuando no se les ha efectuado ningún cambio a las instancias desprendidas. Esto asegura que la aplicación sea portátil..load(). FOR UPDATE en una base de datos que soporte dicha sintaxis. forzando a Hibernate a practicar un SELECT de la instancia para asegurarse de que realmente hayan ocurrido cambios. Los objetos asociados con la sesión a través de un llamado a update() o saveOrUpdate() también comienzan en este modo de "lock". "Lock" pesimista La idea no es que los programadores inviertan demasiado tiempo preocupándose por estrategias de "lock".lock() preactica un chequeo del número de versión si el "lock" especificado es READ. Todos los objetos pasan a este modo de lock al final de una transacción.lock(). los programadores avanzados probablemente deseen a veces obtener "locks" pesimistas exclusivos.x) en relación con el manejo de conexiones JDBC era que un sesión obtenía una conexión cuando se necesitaba por primera vez.5. La "solicitud (request) explícita del usuario" se expresa de alguna de las siguientes maneras: Un llamado a Session. usando SELECT . 11..WRITE se LockMode.. FOR LockMode. es suficiente que se especifique un nivel de asilamiento para las conexiones JDBC y después simplemente dejar que la base de datos haga todo el trabajo. Si se desa usar persistencia transitiva para la reasociación en cascada de entidades relacionadas. Se puede personalizar este comportamiento más a medida. Normalmente. pero puede que se ejecuten triggers on update en la base de datos.. el objeto es cargado usando SELECT . Note que la discusión siguiente.Persistencia Relacional para Java Idiomático http://www.. y el objeto requerido aún no había sido cargado por la sesión. Si se invoca load() para un objeto que ya está cargado. Puede ser readquirido por solicitud específica del usuario.hibernar.load() es invocado con UPGRADE o UPGRADE_NOWAIT.NONE representa la ausencia de "locks". (En el caso de UPGRADE o UPGRADE_NOWAIT. o recapturar locks al comienzo de una transacción nueva. .org/documentacion_es/castellano. Hibernate 3. En ambos casos. es posible que Hibernate ejecute algunos UPDATEs innecesarios. Los diferentes modos de liberación se identifican con valores enumerados de 126 de 198 17/02/2009 09:25 a.. sea con columnas dedicadas de versión/timestamp. las conexiones provistas por el usuario quedan afuera del horizonte de esta discusión. puede ser adquirido ante una solicitud explícita del usuario. Si Session. con un "lock" menos restrictivo que el que se está pidiendo.UPGRADE_NOWAIT puede UPDATE NOWAIT bajo Oracle.

Interceptores y eventos A menudo es útil que la aplicación reaccione a ciertos eventos que ocurren dentro de Hibernate. devuelve ConnectionReleaseMode. import java. AFTER_STATEMENT (también conocida como "liberación agresiva"): dice que las conexiones se liberen luego de la ejecución de todos y cada uno de los comandos.Iterator.AFTER_TRANSACTION. o bien en entornos con auto-commit en donde no importa si es la misma conexión la que nos es devuelta. permitiéndole a la aplicación inspeccionar y/o manipular propiedades de un objeto persistente antes de grabarlo.Serializable. Se puede o bien implementar Interceptor directamente.hibernate.org/documentacion_es/castellano. Este valor es seguro sólo en entornos en donde se puede o bien recapturar la misma conexión JDBC subyacente cada vez que hacemos un llamado a ConnectionProvider.ConnectionReleaseMode: el comportamiento anticuado descrito anteriormente. Esto permite la implementación de ciertos tipos de funcionalidad genérica. package org.AFTER_TRANSACTION. La sesión de Hibernate obtiene una conexión cuando es necesario efectuar algún acceso a JDBC. Por ejemplo. Con JTATransactionFactory.test. las conexiones serán liberadas como si el modo de liberación fuera AFTER_STATEMENT. import org. Este valor se conserva por compatibilidad hacia atrás.connection.ON_CLOSE.Transaction se haya completado.TransactionFactory. porque las fallas en relación con este valor normalmente indican errores de programación (bugs) o suposiciones incorrectas en el código. pero su uso se desaconseja.AFTER_STATEMENT.EmptyInterceptor.html org.hibernate.transaction.ScrollableResults. devuelve ConnectionReleaseMode. import org.util. También note que.hibernar.Transaction. 12. el ConnectionProvider que esté configurado es consultado para comprobar si soporta este valor (supportsAggressiveRelease()).1. Adicionalmente. import java. Casi nunca es buena idea cambiar el comportamiento por defecto. y extender la funcionalidad de Hibernate. con ConnectionReleaseMode.m. el interceptor siguiente asigna automáticamente la propiedad createTimestamp cuando se crea un Auditable. 127 de 198 17/02/2009 09:25 a. El parámetro de configuración hibernate. y retiene dicha conexión hasta que la sesión se cierre. Si no. y actualiza la propiedad lastUpdateTimestamp cuando un Auditable es actualizado. .util. Interceptores La interfaz Interceptor provee métodos de retorno o "callbacks" desde la sesión a la aplicación. actualmente la única situación en la que esto ocurre es cuando se usa un org.release_mode se usa para especificar qué modo de liberación usar. si una sesión se considera que está en modo auto-commit.io.Date. escribir información de seguimiento/auditoría. import java.AFTER_TRANSACTION. Capítulo 12.Persistencia Relacional para Java Idiomático http://www.getDefaultReleaseMode().HIBERNATE .hibernate. Este valor no debería ser usado en entornos JTA.hibernate.hibernate. AFTER_TRANSACTION: dice ON_CLOSE: es esencialmente que se liberen las conexiones una vez que la org. Un uso posible de esto es. after_statement: indica que se usa ConnectionReleaseMode.AFTER_STATEMENT.hibernate.hibernate. o (preferentemente) extender EmptyInterceptor.getConnection(). Esta liberación agresiva es omitida si el comando deja recursos abiertos que aún estén asociados con la sesión actual. con JDBCTransactionFactory. on_close: indica que se use ConnectionReleaseMode. el modo de liberación es reinicializado a ConnectionReleaseMode. Los valores posibles son: auto (el valor por defecto): esta opción le delega la decisión al modo de liberación recibido por el método org.AFTER_TRANSACTION. after_transaction: indica que se use ConnectionReleaseMode.

length. i < propertyNames.openSession() que acepta un Interceptor como parámetro. loads=0.org/documentacion_es/castellano.equals( propertyNames[i] ) ) { currentState[i] = new Date(). } public boolean onLoad(Object entity. } public boolean onSave(Object entity. } public void afterTransactionCompletion(Transaction tx) { if ( tx. dado que su código será (potencialmente) usado por varias sesiones al mismo tiempo. private int loads.equals( propertyNames[i] ) ) { state[i] = new Date(). T if ( entity instanceof Auditable ) { creates++. public void onDelete(Object entity. public class AuditInterceptor extends EmptyInterceptor { private int updates. Object[] state. String[] propertyNames. Object[] state. Ty // no hace nada } public boolean onFlushDirty(Object entity. Serializable id.length. String[] propertyNames. } } Los interceptores vienen en dos variantes: Con alcance de sesión (session-scoped). y con alcance de toda la fábrica de sesiones (sessionfactory-scoped). Actualizaciones: " + updates. Type[] types) { if ( entity instanceof Auditable ) { updates++. El código de los interceptores de alcance de SessionFactory debe ser seguro en cuando a acceso concurrente (thread-safe).HIBERNATE . Object[] pre String[] propertyNames. String[] propertyNames. Object[] state.openSession( new AuditInterceptor() ). creates=0.println("Creaciones: " + creates + ". } } } return false. for ( int i=0. Serializable id. for ( int i=0. } } } return false. "Cargas: } updates=0. Serializable id. private int creates. 128 de 198 17/02/2009 09:25 a. new Configuration(). Object[] currentState.Persistencia Relacional para Java Idiomático http://www.hibernar. i++ ) { if ( "createTimestamp". } return false. return true.type.m. Esto es cierto. Session session = sf. T if ( entity instanceof Auditable ) { loads++.wasCommitted() ) { System.html import org. Asegúrese de no almacenar estado específico de una sesión. En este caos. a menos que se use una sesión que haya sido abierta especificando explícitamente otro interceptor.Type. i++ ) { if ( "lastUpdateTimestamp". el interceptor provisto será a aplicado a todas las sesiones abiertas por esa fábrica de sesiones. return true. Serializable id.out. Un interceptor con alcance de sesión se especifica cuando la sesión se abra usando uno de los métodos adicionales (overloaded) SessionFactory. Un interceptor con alcance de SessionFactory se registra con el objeto Configuration antes de consctruir la SessionFactory. i<propertyNames. .hibernate.setInterceptor( new AuditInterceptor() ).

Los listeners a medida pueden ser registrados programáticamente a través del objeto Configuration. indicándole a Hibernate que use este listener. De fábrica y por defecto.html 12. un FlushEvent.hibernate. lo cual significa que serán compartidos entre solicitudes de clientes. cfg. event.. Los listeners registrados declarativamente no pueden compartir instancias.setLoadEventListeners(stack).eg.2. se vuelve fácil habilitar/inhanilitar los listeners a medida durante la cofiguración. etc. que implemente alguna de la interfaces correspondientes (por ejemplo. Al tener que especificar también el tipo durante el registro. LoadEventListener[] stack = { new MyLoadListener().LoadType loadType) throws HibernateException { if ( !MySecurity. <event type="load"> <listener class="com.properties").m. <hibernate-configuration> <session-factory> .3. } } } También se necesita una entrada de configuración. A los efectos prácticos.org/documentacion_es/castellano. se debe usar la forma programática de registrarlos. 12.HIBERNATE .hibernate. o especificados declarativamente en el archivo de configuración XML de Hibernate (no se soporta la configuración declarativa mediante el archivo ". y/o extender una de las clases utilitarias de base (o incluso los listeners que ya vienen incluidos en Hibernate. Un listener a medida debería implementar la interfaz apropiada para el evento que quiera procesar. Esencialmente todos los métodos de la interfaz Session están correlacionados con un evento.Persistencia Relacional para Java Idiomático http://www. Cuando se invoca uno de estos métodos. (consulte la DTD del archivo de configuración XML o el paquete org.getEntityId() ) ) { throw MySecurityException("Unauthorized access"). De todos modos.EventListeners(). o en reemplazo de ellos.DefaultLoadEventListener"/> </event> </session-factory> </hibernate-configuration> O se lo puede registrar programáticamente: Configuration cfg = new Configuration(). se puede hacer uso de la arquitectura de eventos de Hibernate3. además del listener por defecto. Hay un LoadEvent. public class MyLoadListener implements LoadEventListener { // éste es el único método definido por la interfaz LoadEventListener public void onLoad(LoadEvent event. los "listeners" deben ser considerados singletons. en cuyo caso la implementación es la que se vuelve responsable de procesar todo llamado a load() que la sesíón haga. Se se necesita la capacidad de compartir instancias de listener entre distintos tipos de listener. usted es libre de crear listener a medida. la sesión de Hibernate genera el evento apropiado y lo pasa a los "listeners" (escuchas) de eventos que hayan sido configurados para ese tipo. Si la misma clase es usada por muchos elementos <listener/>.getEntityClassName().event para una lista completa de los tipos de evento definidos). Seguridad declarativa de Hibernate 129 de 198 17/02/2009 09:25 a. .def. y no deberían almacenar estado como variables de instancia. el evento LoadEvent es procesado por una implementación registrada de la interfaz LoadEventListener interface). ¿Por qué impementar una interfaz y también definir un tipo específico durante la configuración? Porque una implementación de listener puede estar implementando más de una interfaz. new DefaultLoadEventListener() }.hibernar. He aquí un ejemplo de un listener a medida para el evento "load". dado que fueron declarados como no-finales con ese propósito). El sistema de eventos puede ser usado por añadidura a los interceptores.MyLoadListener"/> <listener class="org. LoadEventListener.. Sistema de eventos Si se tiene que reaccionar a eventos específicos de la capa de persistencia. esos "listeners" implementan el mismo procesamiento en el que esos métodos habrían resultado.isAuthorized( event.event. cada referencia resultará en una instancia separada de esa clase.

commit(). Transaction tx = session. digamos. para habilitar el uso de autorizaciones JAAS. es indispensable habilitar el uso del procesamiento en lotes JDBC.. Inserciones en lotes Cuando se persisten los objetos. Transaction tx = session. Tal vez se quiera realizar este tipo de trabajo en un proceso en donde la interacción con el caché de 2do nivel esté completamente inhabilitada: hibernate.000 filas en una base de datos podría verse así: Session session = sessionFactory.cache.m.JACCPreInsertEventListener"/> <listener type="pre-load" class="org.secure. construida encima de la arquitectura de eventos. 13.HIBERNATE ."> <listener class=".. Ésta es una funcionalidad opcional.batch_size 20 Note que Hibernate inhabilita la inserción por lotes a nivel de JDBC en forma transparente si se está usando un generador de identificadores identiy. para controlar el tamaño del caché de 1er nivel.org/documentacion_es/castellano. y luego clear() con regularidad. dado que se puede inhabilitar el CacheMode específicamente.save(customer).. Primero se deben configurar los listeners de eventos.JACCPreDeleteEventListener"/> <listener type="pre-update" class="org.hibernate. <listener type="pre-delete" class="org. 130 de 198 17/02/2009 09:25 a.secure.."/> es simplemente una forma abreviada de <event type=". Session session = sessionFactory..update.. Procesamiento en lotes Un abordaje ingenuo al problema de insertar 100. Esto se debe a que Hibernate guarda todas las instancias de Customer en el caché de sesión a medida que las va insertando. "batch processing"). for ( int i=0. i++ ) { Customer customer = new Customer(. provocando un OutOfMemoryException más o menos alrededor de la línea número 50. a algunas acciones se les puede asignar permisos vía JACC.jdbc.1. Luego."/></event> para cuando hay exactamente un listener para un tipo de evento en particular.html La seguridad declarativa de Hibernate usualmente se maneja en una capa de "fachada de sesión" (session façade).openSession(). si se está usando procesamiento en lotes (en inglés. En este capítulo le mostramos cómo evitar este problema.hibernate. todavía en hibernate.JACCPreLoadEventListener"/> Note que <listener type=".secure. .beginTransaction().Persistencia Relacional para Java Idiomático http://www. hibernate." class="...).cfg.close().hibernar.secure. y se pueden autorizar vía JAAS. A partit de Hibernate3..JACCPreUpdateEventListener"/> <listener type="pre-insert" class="org. } tx.read"/> <grant role="su" entity-name="User" actions="*"/> Los nombres de los roles son aquéllos que sean comprendidos por su proveedor JACC.. se vinculan los permisos a roles: <grant role="admin" entity-name="User" actions="insert. Pero primero. se debe efectuar el flush() de la sesión. para anular la interacción con el caché de 2do nivel.use_second_level_cache false Pero esto no es absolutamente necesario. session.openSession(). de 10 a 50.hibernate. si se pretende alcanzar una performance razonable.beginTransaction(). i<100000.hibernate.0000. Esto fallaría. session.xml.. Asígnele un valor razonable al tamaño del lote JDBC. Capítulo 13..

Se considera que las operaciones insert().hibernar.beginTransaction(). Las operaciones que se efectúen usando una sesión sin estado nunca se propagan en cascada.close(). ScrollableResults customers = session.. lo cual resulta en la ejecución inmediata de un SQL INSERT. 131 de 198 17/02/2009 09:25 a.HIBERNATE . session. saveOrUpdate() y delete() definidas por la interfaz Session. no tiene un caché de 1er nivel ni interactúa con un caché de 2do nivel. No implementa un write-behind transaccional ni chequeo automático de datos "sucios"..clear().. Hibernate provee una API orientada a comandos. i<100000.updateStuff(.close(). igual que el tamaño del lote JDBC //aplicarle "flush" a un lote de inserts y liberar memoria session.2. para consultas que devuelvan muchas filas de datos.next() ) { Customer customer = (Customer) customers.setCacheMode(CacheMode.update(customer). 13.next() ) { Customer customer = (Customer) customers. 13. customer..m. if ( i % 20 == 0 ) { //20. session. UPDATE o DELETE.scroll(ScrollMode.IGNORE).get(0). dado que carecen de caché de 1er nivel. } } tx. session. if ( ++count % 20 == 0 ) { //aplicarle "flush" a un lote de actualizaciones y liberar memoria session. int count=0. Session session = sessionFactory.flush().getNamedQuery("GetCustomers") ..getNamedQuery("GetCustomers"). .commit().get(0).save(customer).FORWARD_ONLY). se necesita usar scroll() para tomar ventaja de los cursores que existan del lado del servidor de BD. ScrollableResults customers = session.).3. update() y delete() definidas por la interfaz StatelessSession son operaciones directamente a nivel de fila de la base de datos. Transaction tx = session. while ( customers.html for ( int i=0. muy cercana a la JDBC subyacente. las instancias de Customer (cliente) devueltas por la consulta son automáticamente desprendidas. Por esto.close(). en este ejemplo de código.. customer. La interfaz StatelessSession Alternativamente. respectivamente. Una StatelessSession (sesión sin estado) no tiene un contexto de persistencia asociado ni provee mucha de la semántica de alto nivel respecto del ciclo de vida.).).commit(). que sí proveen las sesiones normales. Nunca están asociadas con ningún contexto de persistencia.flush()..Persistencia Relacional para Java Idiomático http://www. } } tx. que puede ser usada por datos que fluyan desde y hacia la base de datos en forma de objetos desprendidos. i++ ) { Customer customer = new Customer(. } tx. StatelessSession session = sessionFactory..openSession().clear(). session.beginTransaction(). Las sesiones sin estado ingoran las colecciones y los modelos de eventos e interceptores. while ( customers. Una sesión sin estado es una abstracción de más bajo nivel. Note que.org/documentacion_es/castellano. en particular. Actualizaciones en lotes Para capturar y modificar data se aplican las mismas ideas.openStatelessSession(). Transaction tx = session. su semántica es muy diferente de las operaciones save(). También son vulnerables a los efectos de "data aliasing". Adicionalmente.updateStuff(. session. session. session.commit().

Operaciones del tipo "Lenguaje de Modificacion de Datos" (DML-style) Como se discutió anteriormente.org/documentacion_es/castellano.executeUpdate() (el método se bautizó en honor al método de JDBC PreparedStatement.executeUpdate()): Session session = sessionFactory. Esto se logra agregando la palabra VERSIONED luego de UPDATE keyword. UPDATE.beginTransaction(). Si lo tiene. where_conditions)?. newName ) . tx. entonces es ilegal que las propiedades estén calificadas.UserVersionType) no se permiten en conjunción con comandos update versioned. A modo de ejemplo: para ejecutar un HQL UPDATE.openSession().name = :oldName".usertype.createQuery( hqlUpdate ) .setString( "oldName".executeUpdate(): Session session = sessionFactory. ésta puede tener un alias. entonces cualquier referencia a propiedades debe estar calificada usando dicho alias. String hqlUpdate = "update Customer c set c.executeUpdate().hibernar. tx. Para ejecutar un HQL DELETE.createQuery( hqlDelete ) .name = :oldName". session. y estas subconsultas sí pueden contener joins. Esto significa que el estado de un objeto dado está disponible en memoria.setString( "newName". Transaction tx = session. La cláusula "where" también es optativa. 132 de 198 17/02/2009 09:25 a. // o también: String hqlUpdate = "update Customer set name = :newName where name = :oldName". opcionalmente. por lo que manipular la BD directamente usando comandos SQL del tipo "operaciones de modificación de datos" (data modification language o DML por sus siglas en inglés: es decir. session.createQuery( hqlUpdate ) .commit().openSession(). tx. Session session = sessionFactory. el mapeo automático objeto/relacional automático y transparente se ocupa de la administración del "estado" de los objetos. Por defecto. se puede forzar a Hibernate a reinicializar adecuadamente los valores de las propiedades version y timestamp usando un a "actualización versionada" (versioned update).m. ni explícito).executeUpdate(). oldName ) .beginTransaction(). use el mismo método Query. Sin embargo. llamada "modificación de datos en masa" o "bulk-style DML". oldName ) . los comandos UPDATE. INSERT.commit(). no afectan las propiedades version ni timestamp de las entidades involucradas. DELETE) no afectará el estado en memoria. La pseudo-sintaxis para os comandos UPDATE y DELETE es: ( UPDATE | DELETE ) FROM? NombreDeLaEntidad (WHERE Algunos puntos a destacar: en la cláusula "from". // o también: String hqlDelete = "delete Customer where name = :oldName". Sí se pueden usar subconsultas (subqueries) en la cláusula "where".4. el lenguaje HQL de Hibernate provee métodos para este tipo de ejecución de comandos de modificación de datos.html 13.commit(). .close(). int updatedEntities = s. oldName ) .close().beginTransaction(). Note que los tipos de versión a medida (org. session. la palabra FROM es optativa Sólo se puede nombrar una entidad en la cláusula "from".HIBERNATE . String hqlDelete = "delete Customer c where c.setString( "oldName". int deletedEntities = s. esto es consistente con la especificación de EJB3.close(). String hqlVersionedUpdate = "update versioned Customer set name = :newName where name = :oldName".executeUpdate().setString( "oldName". Transaction tx = session. newName ) . De todos modos. Si la entidad no tiene alias.hibernate.openSession(). Véase HQL.setString( "newName". En estas consultas HQL de "modificación en masa" no se puede especificar ningún joins (ni implícito. int updatedEntities = s. use el método Query.name = :newName where c.Persistencia Relacional para Java Idiomático http://www. Transaction tx = session.

Transaction tx = session.hibernate.type. se consideran "generadores residentes en memoria" org. un comando DELETE ejecutado contra una de las subclases podría resultar en borrados no sólo en la tabla a la cual la subclase está mapeada. porque no expone una manera facitble de obtener sus valores en un comando "select".type.org/documentacion_es/castellano. Por ejemplo.VersionType). org. sólo las propiedades que estén definidas directamente en ese nivel de clase en particular pueden ser usadas en la lista_de_propiedades: las propiedades de la superclase no están permitidas. Relevancia de mayúsculas y minúsculas En las consultas. el comando de inserción ofrece dos opciones. Note.beginTransaction(). De modo que SeLeCT es lo mismo que sELEct y lo mismo que SELECT.openSession(). 14.id.TableHiLoGenerator tampoco se puede usar. Se puede o bien especificarla explícitamente 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). y las de subclases no tienen sentido.id. con la precaución de que los tipos de retorno deben corresponder con los tipos esperados por el insert.hibernate.. El número devuelto indica el número real de entidades afactadas por el comando.. Una operación HQL en masa puede resultar en la ejecución de múltiples comandos SQL (para las joined-subclass.Persistencia Relacional para Java Idiomático http://www.executeUpdate().. por ejemplo). el uso de mayúsculas o minúsculas es irrelevante.SequenceGenerator (y sus subclases).TimestampType. name) select c. VALUES . session. En relación a la propiedad id. La pseudo-sintaxis de los comandos INSERT es: INSERT INTO NombreDeLaEntidad lista_de_propiedades comando_select. Considere que esto puede corresponder o no con el número de filas afectadas en la base de datos.commit(). String hqlInsert = "insert into DelinquentAccount (id. Aunque cuenta con una sintaxis deliberadamente parecida a SQL. .DateType y org.HIBERNATE .type.close(). pero org. para Hibernate no son iguales los tipos org. la forma INSERT INTO . capaz de entender nociones como herencia. el comando_select puede ser cualquier consulta válida de selección HQL. y potencialmente en otras tablas de joined-subclass más abajo en la jerarquía de herencias. Para las propiedades mapeadas como version o timestamp. Algunos puntos a destacar: Sólo se soporta la forma INSERT INTO .. los comandos INSERT son inherentemente polimórficos. SELECT .createQuery( hqlInsert ). Capítulo 14. HQL es totalmente orientado a objetos. Volviendo al ejemplo de la joined-subclass. En otras palabras. no.hibernate.hibernate.hibernate..name from Customer c wh int createdEntities = s. que esto podría causar problemas entre tipos que Hibernate considere o no "equivalentes" más que "iguales".. esto es verificado durante la compilación. y cualquier implementación de org.id. tx.hibernate.PostInsertIdentifierGenerator.id. polimorfismo y asociación.m. . el comando INSERT da dos opciones: se puede o bien especificarlas explícitamente 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. sin embargo.FOO no es lo 133 de 198 17/02/2009 09:25 a. sino también borrados en la tabla "raíz".executeUpdate() indica el número de entidades afectadas por la operación.. c. Para entidades que estén involucradas en una herencia mapeada. La especificación de la lista_de_propiedades es análoga a la especificación de columnas en un comando SQL INSERT.eg.hibernate.. Para los efectos de esta discusión. intentar usarla con generadores del tipo "residente en memoria" causará una excepción durante el parsing del comando.1. en lugar de relegar dicho chequeo a la base de datos. Un ejemplo de ejecución del comando HQL INSERT: Session session = sessionFactory. HQL: El lenguaje de consultas de Hibernate Hibernate está equipado con un lenguaje de consultas extremadamente potente: HQL.hibernar. Actualmente. Esta última opción está disponible solamente cuando se usen generadores de id que operen dentro de la base de datos.html El valor int devuelto por el método Query. aunque la base de datos no diferencie entre ambos o sea capaz de manejar la conversión entre ambos. excepto por los nombres de propiedades y clases de Java.

html mismo que org. La palabra as es optativa. y foo. o incluso a elementos de una colección de valores.hibernar. 14.HIBERNATE . 14. Parameter from Formula as form.eg. . Así que casi siempre escribimos: from Cat La mayoría de las veces hará falta asignarle un alias. Normalmente no necesitamos calificar el nombre de la clase de esta manera. dado que el valor por defecto es auto-import. resultando en un producto cartesiano o "cross join". La cláusula "from" La consulta de Hibernate más simple tiene esta forma: from eg.org/documentacion_es/castellano.mate as mate left outer join cat. de manera que podamos usar dicho alias más adelante en la consulta. A algunos usuarios les parece que las consultas escritas todas en mayúsula son más legibles.barSet no es lo mismo que foo.parameter param Los tipos de join son un préstamo de la especificación ANSI de SQL.kittens as kittens from Formula form full join form.3.kittens as kitten from Cat as cat left join cat. Parameter as param Se considera una práctica buena el nombrar los alias en las consultas usando una minúscula inicial. usando la palabra join.mate as mate 134 de 198 17/02/2009 09:25 a. también podríamos escribir: from Cat cat Pueden aparecer varias clases.hibernate. Este manual usa minúsculas para las palabras HQL.mate.Cat. en concordancia con los estándares de nombrado para variables locales en Java. pero a nosotros esta convención nos parece fea cuando está inserta en código Java. from Cat as cat inner join cat. Asociaciones y "joins" Se les puede asignar alias a entidades asociadas.m.Foo.Cat la cual simplemente devuelve todas las instancias de la clase eg. left outer join and right outer join pueden abreviarse así: from Cat as cat join cat.2.Persistencia Relacional para Java Idiomático http://www. (por ejemplo domesticCat). 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. from Formula. inner join left outer join right outer join full join (el cual normalmente no es muy útil) Las frases inner join.BARSET.

La forma implícita no usa la palabra "join". where). con instrumentación bytecode.m. Tampoco se debe usar fetch junto con condiciones "with" ad hoc. porque los objetos asociados que devuelve no deberían ser usados en la cláusula "where". Si se está usando captura haragana (lazy fetching) a nivel de las propiedades. Un join implícito se traduce en "inner joins" en el comando SQL resultante.kittens child left join fetch child. hay 2 maneras de referirse a la propiedad indentificadora de una entidad: 135 de 198 17/02/2009 09:25 a. from Cat as cat inner join fetch cat. Al efectuar un join tipo "fetch" con más de una colección. efectivamente reemplaza los "outer joins" y las inicializaciones haraganas (lazy) del archivo de mapeo para asociaciones y colecciones. un join calificado con la palabra "fetch" (captura) permite que las asociaciones o colecciones de valores sean inicializados junto con sus objetos padres. note que las construcciones full join fetch y right join fetch no tienen sentido. from Cat as cat where cat.html left join cat. es si se está usando un join tipo "fetch" recursivo a otra colección más. . usando fetch all properties.mate.kittens A un join del tipo "fetch" normalmente no se le asignan alias.bodyWeight > 10. Formas de la sintaxis de los "joins" HQL soporta dos formas de asociación por "joins": implícita y explícita.kittens as kitten Y se pueden especificar condiciones adicionales del join. Esto es particularmente útil en el caso de las colecciones. Las consultas mostradas en la sección anterior usan todas la forma explícita en donde la palabra "join" es explícitamente usada en la cláusula "from". en cambio. Referirse a la propiedada identificadora En general. las asociaciones son "des-referidas" (dereferenced) usando la notación de puntos.org/documentacion_es/castellano. da a menudo resultados inesperados con los mapeos de "bag".1. el cual normalmente contendrá duplicados debido a esta "captura ansiosa".Persistencia Relacional para Java Idiomático http://www.5. además. from Document fetch all properties order by name from Document doc fetch all properties where lower(doc. usando un solo SELECT.name) like '%cats%' 14. se puede acceder a ellos a través del objeto padre. es posible forzar a Hibernate para que capture esas propiedades haraganas inmediatamente en la primera consulta. y por lo tanto la cantidad de filas no será la que se espera. “Estrategias de captura (fetch)” para más información. los objetos asociados no son devueltos directamente en el resultado de la consulta.kittens as kitten with kitten. así que tenga cuidado en este caso. from.kittens Note que la construcciones con fetch no deben ser usadas en consultas que luego invoquen iterate() (aunque sí se puede con scroll()).name like '%s%' 14. Por último. La única razón por la que se podría necesitar un alias. así que tenga cuidado acerca de cómo formula sus consultas en este caso.0 Adicionalmente. es posible crear un producto cartesiano.4. dado que dichas operaciones se basan en el número de filas del resultado. Los joins implícitos pueden aparecer en cualquiera de las cláusulas HQL (select. ni en ninguna otra cláusula.hibernar. Vea la Sección 19.HIBERNATE . usando la palabra with: from Cat as cat left join cat. from Cat as cat inner join fetch cat. Además.mate left join fetch cat. Usar joins "fetch" con múltiples colecciones. Ésta es la forma que se recomienda.mate left join fetch cat. En lugar de eso. Tampoco debería usarse fetch con consultas que usen setMaxResults() o setFirstResult() (los métodos de paginación).

HIBERNATE . la propiedad identificadora compuesta sólo puede ser referida por el nombre asignado.name) from DomesticCat as mother inner join mother. En realidad. Las referencias a identificadores compuestos siguen las mismas relgas. mate.mate from Cat cat Las consultas pueden devolver propiedades de cualquier tipo de valor. id siempre hacía alusión a la propiedad identificadora. se puede expresar esta consulta de una forma más compacta. La cláusula "select" La cláusula select elige qué objetos y propiedades serán devueltos como conjunto de resultados o "resultset". En versiones anteriores. mate.name like 'fri%' select cust.name from DomesticCat as mother inner join mother. offspr) from DomesticCat as mother join mother.m. Sea: select mate from Cat as cat inner join cat.mate as mate left outer join mother. se puede usar dicho nombre. incluidos valores de tipo "componente": select cat. cuando había propiedades no-identificadoras llamadas id.name. Si la entidad tiene una propiedad no-identificadora llamda "id". seguro en cuanto a tipo (typesafe) select new Family(mother. "compañeros") de otros Cats.firstName from Customer as cust Las consultas pueden devolver múltiples objetos.mate as mate left outer join mother.name from DomesticCat cat where cat. 14.mate as mate left join mother.org/documentacion_es/castellano. Si la entidad define una propiedad indentificadora con nombre. como: select cat.2.hibernar.Persistencia Relacional para Java Idiomático http://www. . offspr. mate. en un array Object[].kittens as offspr o como una List. offspr.kittens as offspr o como un verdadero objeto Java. sin importar el verdadero nombre.2. las consultas no podían referirse a ellas.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. se puede usar la propiedad especial id para referirse a la propiedad identificadora.6. select new list(mother. count(*) as n from Cat cat Esto es de lo más util cuando se usa en conjunción con select new map: 136 de 198 17/02/2009 09:25 a.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 también llamada "id". En caso contrario. select mother.mate as mate Esta consulta seleccionará los mates (en inglés. Nota: esto ha cambiado significativamente a partir de la versión 3. A consecuencia de esto. min(bodyWeight) as min.

sum(cat. 14. min(.) En la cláusula "select" se pueden usar operadores aritméticos.hibernar.. Las consultas de Hibernate pueden nombrar cualquier clase o interfaz Java en la cláusula from. 14. select distinct cat. cat.. uno puede referirse a las propiedades por su nombre: 137 de 198 17/02/2009 09:25 a.) count(*) count(. y que no se puede usar Query. Consultas polimórficas Una consulta como: from Cat as cat devuelve no sólo instancias de Cat.name = m.weight + sum(kitten... Esto implica que un cláusula order by no ordenaría correctamente la totalidad del conjunto de resultados.weight select firstName||' '||initial||' '||upper(lastName) from Person Las palabras distinct y all pueden ser usadas.8.9.weight) from Cat cat join cat. La siguiente consuta devuelve todos los objetos persistentes: from java. Funciones agregadas Las consultas HQL incluso pueden devolver los resultados de funciones agregadas que fueran aplicadas a propiedades: select avg(cat. max(cat. concatenación..name Note que las dos últimas consultas requerirán más de dos comandos SQL SELECT.).m..org/documentacion_es/castellano.).).. . max(. count(*) as n ) from Cat cat Esta consulta devuelve un Map de los alias a los valores seleccionados.).scroll() para navegarlos.weight).weight)..kittens kitten group by cat.HIBERNATE ..Persistencia Relacional para Java Idiomático http://www. sum(. y con la misma semántica que en SQL.name). Si no hay alias.Object o Sea una interfaz Named.name from Cat cat select count(distinct cat. La consulta devolverá las instancias de todas las clases persistentes que extiendan o implementen dicha clase o interfaz. y funciones SQL reconocidas: select cat...7. la cláusula "where" La cláusula where permite acotar la lista de instancias devueltas.. implementada por varias clases persistentes: from Named n. count(distinct . sino también de las subclases como DomesticCat.. count(all. count(cat) from Cat cat 14. count(cat) from Cat cat Las funciones agregadas que se soportan son: avg(.weight)..id.html select new map( max(bodyWeight) as max. Named m where n.). min(bodyWeight) as min.lang.

véase la Sección 14.5. “Componentes” para más información.name is not null Esta consulta se traduciría en un comando SQL con varios (inner) joins. Considere: from Cat cat where cat. Supongamos que Person tiviera un identificador compuesto que consistiese en country y medicareNumber.mate = rival.class = DomesticCat Tambiém se pueden usar componentes.owner. Cat mate where cat. Si se escribiera algo como esto: from Foo foo where foo.mate. El operador = puede usarse para comparar no sólo propiedades.startDate = bar. from Cat as cat where cat. (de nuevo.Persistencia Relacional para Java Idiomático http://www. la segunda consulta no requiere "joins" Del mismo modo.id = 123 from Cat as cat where cat. Un nombre de clase de Java incrustado en la cláusula "where" será traducido como su valor de discriminador.address.id = 69 La segunda consulta es eficiente.id.html from Cat where name='Fritz' si hay un alias.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. en caso de que se esté usando persistencia polimórfica. También se pueden usar propiedades de los identificadores compuestos.medicareNumber = 123456 Nuevamente.country = 'AU' and person.owner.customer. puede usarse para hacer referencia al identificador único de un objeto.mate.country = 'AU' and account.mate select cat. mate from Cat cat. la propiedad especial class accede al valor discriminador de una instancia. o las propiedades de dichos tipos de componentes/tipos. Vea la Sección 14.5. select foo from Foo foo.medicareNumber = 123456 from bank.Person person where person. Cat rival where cat. úsese un nombre de propiedad calificado: from Cat as cat where cat.id.baz.HIBERNATE . 138 de 198 17/02/2009 09:25 a.id.id. o tipos a medida compuestos. Bar bar where foo.17.Account account where account.m. . Las expresiones con "path" compuesto hacen que la cláusula "where" sea extremadamente poderosa. no requiere joins. “Referirse a la propiedad identificadora” para más información acerca de referirse a las propiedades identificadoras): from bank.bar.org/documentacion_es/castellano.hibernar. from Cat cat where cat. sino también instancias: from Cat cat. “Referirse a la propiedad identificadora” para más información.city is not null en SQL se acabaría con una consulta que requeriría 4 joins de tablas.mate = mate La propiedad id (en minúscula).name='Fritz' devuelve las instancias de gatos llamados 'Fritz'. Véase la Sección 14.

is empty. any..hibernar.Persistencia Relacional para Java Idiomático http://www.. all.... like operaciones lógicas and. la función HQL index().. 'Bar'.10. minelement(). 6. sin() parámetros ppsicionales al estilo JDBC parámetros nombrados: :name. <>. sqrt(). :x1 expresiones SQL literales 'foo'. trim(). then . else .0: substring()...)... que se aplica a los alias de una coleción asociada indexada. para indicar agrupamientos in. maxelement().org/documentacion_es/castellano... . funciones HQL que aceptan expresiones tipo "path" con valor de colección: size().. -.. / operadores de comparación binaria =.Color. "Simple" case... cualqiuer función escalar SQL soportada por la base de datos. end.item. 14.) si la base de datos subyacente soporta las funciones ANSI cast() y extract().).. bit_length(). or concat(.. from . is not null. not paréntesis ( ). case when . abs()...0' constantes public static final de java eg.66E+2..html Un tipo "any" tiene las propiedades especiales id y class. las cuales pueden ser cuantificadas usando some.id Note que.HIBERNATE . not in. Payment payment where log.. !=.||. y la forma de "case" llamada "searched".. locate().. upper().. Expresiones Las expresiones que se permiten en la cláusula where incluyen la mayoría de las que se podría escribir en SQL: operadores matemáticos +.class se estarían refiriendo a valores de columnas completamente diferentes de la base de datos. y extract(.).)....item. is not empty.. end concatención de cadenas . trunc(). in.. year(. 'Baz' ) y la forma negada puede ser escrita: 139 de 198 17/02/2009 09:25 a. junto con las funciones especiales elements() e indices.. as .. length(). else . minute(.. log. *.. 69. exists.class = 'Payment' and log. en donde el segundo argumento es el nombre de un tipo de Hibernate.) current_date(). then .). mod() coalesce() y nullif() str() para convertir valores numéricos o temporales en una cadena legible cast(. >=. member of and not member of la forma de "case" simple.. case .). minindex(). Cualquier función u operador definido por EJB-QL 3. que permiten expresar un join de la siguiente manera (en donde AuditLog..RAYADO in y between pueden ser usados como sigue: from DomesticCat cat where cat. <=.. between... como sign().. rtrim(). '1970-01-01 10:00:01.name between 'A' and 'B' from DomesticCat cat where cat. or.class y payment.m... :start_date. month(. lower().item. day(. en la consulta precedente. current_timestamp() second(. when .item es una propiedad mapeada con <any>): from AuditLog log. maxindex().. hour(.). current_time()..name in ( 'Foo'. is null.id = payment.

HIBERNATE . from Calendar cal where maxelement(cal. from Order order where order.kittens) from Player p where 3 > all elements(p. Order order 140 de 198 17/02/2009 09:25 a. from Cat cat where cat.acts) Note que las construcciones: size. Calendar calendar where calendar.alive = true Se puede chequear el tamaño de la colección con la propiedad especial size.hibernar.kittens) select p from NameList list.id = 11 select item from Item item.scores) from Show show where 'fizard' in indices(show. maps) por índice (sólo en la clausula "where"). minelement. is null y is not null pueden ser usadas para chequear valores nulos.Persistencia Relacional para Java Idiomático http://www. maxelement sólo pueden ser usadas en la cláusula "where" en Hibernate3 Uno se puede referir a los elementos en las colecciones indexadas (arrays. false 0</property> Esto reemplazará las palabras true y false con los valores literales 1 y 0 en el SQL traducido desde este HQL. select mother from Cat as mother.deliveredItemIndices[0] ] = item and order.substitutions">true 1.kittens) > 0 Para las colecciones indexadas. all. 'Bar'. maxindex.m.calendar = calendar select item from Item item.kittens. indices. 'Baz' ) Del mismo modo. Cat as kit where kit in elements(foo. minindex.holidays['national day'] = person. lists. . exists. se puede aludir a los elementos mínimo y máximo de una colección de un tipo básico utilizando las funciones minelement y maxelement. Person p where p. o el resultado de una subconsulta (véase abajo).size > 0 from Cat cat where size(cat. o con la función especial size().items) > 10000 Las funciones SQL any. Análogamente. Se puede usar fácilmente valores booleanos.items[ order. declarando sustituciones de consulta HQL en la configuración de Hibernate: <property name="hibernate. in se soportan cuando se les pasa como parámetro el conjunto de elementos o índices de una colección (éstas son las funciones elements e indices).query.names) from Cat cat where exists elements(cat. from Cat cat where cat.nationality.items) > 100 from Order order where minelement(order. some. Order order where order.name not in ( 'Foo'.items[0]. elements.name not between 'A' and 'B' from DomesticCat cat where cat.holidays) > current_date from Order order where maxindex(order.html from DomesticCat cat where cat. es preferible referirse a los valores mínimos y máximos usando las funciones minindex y maxindex.org/documentacion_es/castellano.birthDay and person.id = 1234 select person from Person person.name = some elements(list.

cust. o una colección de valores. 'Sydney' ) and prod = all elements(cust.id = ALL( SELECT item. Store store inner join store.prod_id FROM line_items item.name in ( 'Melbourne'. stores store.hibernar. cat. algo como: SELECT cust.loc_id = loc.Persistencia Relacional para Java Idiomático http://www. select item from Item item. La cláusula "group by" Una consulta que devuelva valores agregados. .name) like 'FRI%' Si todo esto aún no lo ha convencido.id = 11 La expresión dentro de [] puede incluso ser una expresión aritmética.name = 'widget' and store. 14. para elementos de una asociación de-uno-a-muchos.12.current_order = o.items) . locations loc.html where order.color.location.items item where index(item) < 5 Pueden ser usadas las funciones SQL escalares que la DB subyacente soporte: from DomesticCat cat where upper(cat. index(item) from Order order join order. La cláusula "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 = 'widget' AND store.items[ size(order.phone. puede ser agrupada por cualquier propiedad de las clases o componentes devueltos.customers cust where prod.m.org/documentacion_es/castellano.color 141 de 198 17/02/2009 09:25 a.id AND sc. product prod WHERE prod.name asc. sum(cat.name.id.weight desc.address. cat. Order order where order.id ) 14.weight). orders o WHERE item.cust_id = cust.id AND prod. cust.name IN ( 'Melbourne'. select item.lineItems) Para que se dé una idea. piense cuánto más largo y menos legible habría sido esta consulta en SQL: select cust from Product prod.currentOrder. 'Sydney' ) AND sc. count(cat) from Cat cat group by cat.11. cust.HIBERNATE .store_id = store. store_customers sc.current_order FROM customers cust.id AND loc.1 ] = item HQL también trae una función index() ya incorporada.items) ] = item and order.birthdate Las palabras opcionales asc o desc indican orden ascendente o descendente respectivamente.items[ maxindex(order. cust. select cat.id AND cust.order_id = o.

muy similares a las que he usado en un proyecto reciente.Persistencia Relacional para Java Idiomático http://www.14. el poder del lenguaje de consultas es una de las características más "vendedoras" de Hibernate.mate = cat ) from DomesticCat as cat where cat. 14.nickName from Name as name ) select cat. MySQL no). cat. avg(name).weight). select cat from Cat cat join cat.color having cat. “Constructor del valor de fila” para más detalles.properties having avg(kitten. eg. 14.nickName from Name as name ) from Cat as cat where not exists ( from Cat as mate where mate.hibernar.org/documentacion_es/castellano.other. (select max(kit. sum(kitten. from Cat as fatcat where fatcat. De hecho.13.names name group by foo.weight) desc Note que ni la cláusula group by ni la order by pueden contener expresiones aritméticas. Y también 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.id También se permite la cláusula having: select cat.id.Color. Note que las subconsultas también pueden utilizar sintaxis de constructor del valor de fila (row value constructor). max(name) from Foo foo join foo.m. dentro de having se permiten funciones SQL. Ejemplos de HQL Las consultas en Hibernate pueden llegar a ser bastante potentes y complejas.weight) > 100 order by count(kitten) asc. ¡Note que la mayoría de las consultas que usted escribirá serán mucho más simples que éstas! 142 de 198 17/02/2009 09:25 a.Color.TABBY. count(cat) from Cat cat group by cat.18.html select foo.weight) from cat.kitten kit) from Cat as cat Note que las subconsultas HQL pueden ocurrir sólo en las cláusulas "select" o "where". hay que listar todas las propiedades no-agregadas explícitamente.id.weight) from DomesticCat cat ) from DomesticCat as cat where cat.HIBERNATE .kittens kitten group by cat. Incluso se permiten subconsultas correlacionadas (subconsultas que hagan referencia a un alias en la consulta exterior. cat. Hibernate soporta subconsultas dentro de una consulta.id.weight > ( select avg(cat.name.BLACK) si la base de datos subyacente lo soporta (por ejemplo. Vea la Sección 14.name not in ( select name. Subconsultas Para las base de datos que soporten subconsultas (subqueries). cat. sum(cat. y dentro del order by se permiten funciones agregadas. He aquí algunas consultas de ejemplo.color. . Una subconsulta debe estar rodeada por paréntesis (a menudo por un llamado a una función SQL agregada).color in (eg.name = some ( select name.

Se traduce en una consulta SQL con 2 inner joins y una subconsulta correlacionada. status. status.product = product and catalog.customer = :customer and price.AWAITING_APPROVAL or ( statusChange.product = product and catalog = :currentCatalog group by order having sum(price. .name <> PaymentStatus. Catalog as catalog join catalog.status.payment = payment ) and statusChange.name from Payment as payment join payment.sortOrder 143 de 198 17/02/2009 09:25 a. Catalog as catalog join catalog.currentStatus as status join payment.HIBERNATE . status. ORDER_LINE. status. count(item) from Order as order join order. CATALOG y PRICE tiene 4 "inner joins" y una subconsulta (no correlacionada).id. en la vida real no soy muy amigo de las subconsultas.user <> :currentUser group by status.lineItems as item join item. El SQL resultante. la consulta habría sido mucho más fácil de escribir.currentStatus as status where payment. el número de items y el valor total de todas las órdenes impagas por un cliente en particular.statusChanges as statusChange where payment. ordenando los resultados por valor total.timeStamp) from PaymentStatusChange change where change.customer = :customer and price.hibernar.sortOrder order by status.AWAITING_APPROVAL or payment.Persistencia Relacional para Java Idiomático http://www.user <> :currentUser ) group by status. así que mi consulta quedó más bien de esta manera: select order.effectiveDate < sysdate ) group by order having sum(price. contra las clases PAYMENT.org/documentacion_es/castellano. usa el catálogo actual.effectiveDate from Catalog as cat where cat.timeStamp = ( select max(change.prices as price where order.amount) > :minAmount order by sum(price.name <> PaymentStatus.paid = false and order. PAYMENT_STATUS y PAYMENT_STATUS_CHANGE. select order.effectiveDate < sysdate and catalog. Para determinar los precios. y dado un valor total mínimo. PRODUCT. select count(payment).prices as price where order.sortOrder Si yo hubiera mapeado la colección statusChanges collection como una lista. efectuado contra las tablas ORDER.amount) > :minAmount order by sum(price.html La siguiente consulta devuelve el id de la orden.amount) desc ¡Qué monstruo! En realidad.name from Payment as payment join payment.name.m.name.statusChanges) ]. sum(price. count(item) from Order as order join order.product as product.amount). select count(payment).statusChanges[ maxIndex(payment.status.product as product.amount).id. sum(price.sortOrder order by status.lineItems as item join item.amount) desc La consulta siguiente cuenta el número de pagos en cada estado.effectiveDate >= all ( select cat. exceptuando los pagos que figuren como "aprobación pendiente" (AWAITING_APPROVAL) en donde el cambio de estado más reciente haya sido efectuado por el usuario actual.paid = false and order.

id.sortOrder..size=:size").id.users) and PaymentStatus. Se traduce en un SQL con tres inner joins.html La siguiente consulta usa la función isNull() de MS SQL Server para devolver todas las cuentas y pagos no efectuados a la organización a la cual pertenece el usuario actual. Consejos y trucos Se puede contar el número de resultados de una consulta sin necesidad de devolver todo el resultado: ( (Integer) session. usr.16.15.next() ). PAYMENT.name. usr. payment from Account as account left outer join account. en la cláusula "where" de su consulta.payments as payment where :currentUser in elements(account.iterate().type.sortOrder..name having count(msg) >= 1 Como esta solución no puede devolver a un User que tenga 0 mensajes a causa del inner join.messages as msg group by usr. 14.UNPAID) order by account. payment from Account as account join account.name from User as usr left join usr..intValue() Para ordenar un resultado de acuerdo al tamaño de las colecciones de hijos. .id.createQuery("from foo Foo as foo where foo.").m..payments as payment where :currentUser = user and PaymentStatus. debemos deshacernos del subselect correlacionado..currentStatus. 144 de 198 17/02/2009 09:25 a.HIBERNATE .holder.UNPAID) order by account.accountNumber.messages as msg group by usr. PaymentStatus..id. ORGANIZATION y ORG_USER.4. select account. PAYMENT_STATUS. ACCOUNT_TYPE. la siguiente forma también es útil: select usr.users as user left outer join account.name. account.name order by count(msg) Si su base de datos soporta subselects. from User usr where size(usr.UNPAID = isNull(payment. account. “Operaciones del tipo "Lenguaje de Modificacion de Datos" (DML-style)” para más detalles. se puede poner una condición en cuanto al tamaño de la selección.dueDate En algunas DB.name from User usr. use la consulta siguiente: select usr. un outer join y un subselect contra las tablas the ACCOUNT. payment. usr.org/documentacion_es/castellano.messages) >= 1 si su base de datos no soporta subconsultas. PaymentStatus.id. usr. select account.holder. payment.accountNumber.type.hibernar.name=:name and foo. delete e insert ..name having count(msg) = 0 Se pueden asociar las propiedades de un JavaBean a parámetros nombrados de una consulta: Query q = s.dueDate 14.messages msg group by usr. usr..name from User as usr left join usr. Vea la Sección 13.createQuery("select count(*) from .id.currentStatus.UNPAID = isNull(payment. usr. use la consulta siguiente: select usr.Persistencia Relacional para Java Idiomático http://www.name join usr. Actualizaciones y borrados en masa HQL ahora soporta comandos update. select .

"order by this.name from Person p order by p. típicamente asociadas con componentes.setProperties(fooBean). Pueden aparecer en la cláusula "select": select p.name.hibernar. 14.first = :firstName Los componentes también pueden ser usados en cláusulas "order by": from Person p order by p..createQuery("select count(*) from .last='Jingleheimer-Schmidt' Esta sintaxis es válida. // el filtro trivial q.list().18. Se puede averiguar el tamaño de una colección sin inicializarla: ( (Integer) session.list().m.name=('John'.type.first Otro uso común de los componentes.intValue(). Considérese una entidad "Person".setFirstResult(PAGE_SIZE * pageNumber). // fooBean has getName() and getSize() List foos = q.name = :name from Person p where p. 'Jingleheimer-Schmidt') También sería útil especificar esto en la cláusula "select": select p.amount" ). List page = q..name.first='John' and p.17. casi en cualquiera de las mismas formas en que se puede usar "value types" simples. Los componentes también pueden ser usados en cláusulas "where": from Person p where p. Componentes En HQL. Nos estamos refiriendo a a comparaciones multi-valores. que define un componente "name": from Person p where p.first from Person p en donde la propiedad "name" de Person es un componente. count(this) group by this. incluso aunque la base de datos subyacente no soporte este concepto.next() ).filter( collection.type" ). Los elementos de las colecciones pueden ser ordenados o agrupados usando un filtro de consultas: Collection orderedCollection = s. q. usando la interfaz Query más un filtro: Query q = s. es en los constructores de valor de fila.filter( collection. 14.name from Person p select p."). Sería bueno poder hacerla un poco más concisa y usar la sintaxis de "constructor de valor de fila": from Person p where p..iterate(). aunque un tanto locuaz. "" ). a veces también llamada sintaxis de "t-upla".name.createFilter( collection. Collection counts = s. "select this.name.name.setMaxResults(PAGE_SIZE). . Las colecciones se pueden volver paginables.HIBERNATE . 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). se pueden usar componentes.org/documentacion_es/castellano.name from Person p 145 de 198 17/02/2009 09:25 a.html q.Persistencia Relacional para Java Idiomático http://www.

add( Restrictions.add( Restrictions.HIBERNATE . Consultas Criteria Hibernate posee una API para consultas "criteria" (por criterios).name. 15.add( Restrictions. "Fritz%") ) .createCriteria(Cat. de Hibernate que denomina a este tipo de consultas. se llama "Criteria".m. Acotar el resultado (N.1.list(). crit. . "criterio" se dice "criterion".add( Restrictions. new Integer(2) ) ) ) ) . Crear una instancia de Criteria La interfaz org.createCriteria(Cat.eq("age". es que la consulta será dependiente del orden de las sub-propiedades del componente en los metadatos. cat.isNull("age") ) . new String[] { "Fritz". new Integer(1) ) ) . new Integer(0) ).add( Restrictions.isNull("age") ) ) . en un paquete del mismo nombre. "Pk" } ) ) .add( Restrictions.T):en inglés. pero uno en especial permite especificar SQL directamente: 146 de 198 17/02/2009 09:25 a.html Otro momento en que la sintaxis de constructor de valor de fila puede ser beneficiosa.add( Restrictions. casi nunca son usados directamente por el programador.criterion. Hay un buen rango de tipos de "criterion" que ya vienen incluidos (subclases de Restrictions).class) . Criteria crit = sess. List cats = sess. es "criteria". "Izi". intuitiva y extensible.add( Restrictions. Restrictions.like("name".or( Restrictions.eq( "age".Restrictions define métodos "fábrica" para obtener ciertos tipos de Criterion que ya vienen incluidos. "Fritz%") ) .hibernate.createCriteria(Cat.between("weight".list(). List cats = sess. La interfaz.class).eq("age".Criteria representa una consulta contra una clase persistente en particular.org/documentacion_es/castellano.add( Restrictions.createCriteria(Cat. La sesión actúa como fábrica de instancias de Criteria.color ) in ( select cat.disjunction() .Persistencia Relacional para Java Idiomático http://www. Una interfaz mucho menos conocida. y en plural.eq("age".del.criterion. Capítulo 15. porque le son agregados a un "Criteria" ente bambalinas. 15. Las "Restrictions" (restricciones) pueden ser agrupadas lógicamente.color from DomesticCat cat ) Una cosa a considerar.hibernate.Criterion.2. maxWeight) ) . La clase org. muy usada.add( Restrictions.in( "name". new Integer(0) ) ) .like("name".name.class) .hibernate.list().hibernar.setMaxResults(50). Una "criterion" individual es una instancia de la interfaz org. List cats = sess.list(). es cuando se usen subconsultas que necesiten comparar contra valores múltiples: from Cat as cat where not ( cat. al decidir si se quiere usar esta sintaxis. cat.class) . "Criterion". List cats = crit. minWeight.

name) like lower(?)".forName("age").4.Order.html List cats = sess.STRI .add( Property.list().createCriteria(Cat. "Izi".list().list().hibernar. Se puede crear una Property invocando Property.createCriteria(Cat.createAlias("mate".like("F%") ) .hibernate.name") ) . 15. Property age = Property.forName("age").) Note que las colecciones de "kittens" (gatitos) contenidas en las instancias de Cat devueltas por las dos consultas anteriores.sqlRestriction("lower({alias}.class) .class) .eq( new Integer(0) ) ) .createCriteria(Cat.forName("name").desc("age") ) .add( Restrictions. navegando a través de asociaciones usando createCriteria(). Hibernate.isNull() ) .addOrder( Order.like("name".setMaxResults(50) . debe usar un ResultTransformer.in( new String[] { "Fritz".add( age.class) . "Fritz%".add( Restrictions.eq( new Integer(1) ) ) .name".forName(). (createAlias() no crea una instancia nueva de Criteria.desc() ) .HIBERNATE .add( age.add( age. note que el segundo createCriteria() devuelve una instancia nueva de Criteria.eqProperty("kt.list().asc() ) . 15. El comodín {alias} será reemplazado con el alias de fila de la entidad consultada.m. "kt") .eq( new Integer(2) ) ) ) ) .forName("name"). ¡no están pre-filtradas por el Criteria! Si desea obrener sólo los "kittens" que cumplen con el Criteria.addOrder( Order. "F%") ) . List cats = sess.list(). "mt") .Persistencia Relacional para Java Idiomático http://www.class) .3. List cats = sess.createAlias("kittens".disjunction() .createCriteria(Cat.setMaxResults(50) . La siguiente forma alternativa es útil en ciertas circunstancias: List cats = sess. Asociaciones Se puede especificar constraints en entidades relacionadas. "F%") . List cats = sess.list().class) .add( Restrictions.add( Restrictions.createCriteria(Cat. List cats = sess.addOrder( Property. Ordenar el resultado Se puede ordenar los resultados usando org. Un camino alternativo para obtener un "criterion" es obtenerlo a partir de una instancia de Property.class) .add( Restrictions. la cual se refiere a los elementos de la colección kittens. "Pk" } ) ) .criterion.forName("name").createCriteria("kittens") . "mt.like("name". "F%") ) .createCriteria(Cat. List cats = sess.add( Restrictions.class) 147 de 198 17/02/2009 09:25 a. .org/documentacion_es/castellano.addOrder( Property.createCriteria(Cat.add( Property.like("name".add( age.asc("name") ) .

iterator().excludeProperty("color") //excluir una propiedad llamada "color" .setProjection( Projections. List cats = sess.html .hibernate.get(Criteria.add( Example. cat. List results = session.criterion.add( Restrictions.class) .createCriteria(Cat. 15. Esta consulta capturará tanto mate como kittens mediante un "outer join".list().createCriteria(Cat. Le aplicamos una proyección a una consulta llamando a setProjection().createCriteria(Cat.Projections (proyecciones) es una fábrica de instancias de la clase Projection.create(cat) ) . FetchMode.ALIAS_TO_ENTITY_MAP) .class) .7. agregado y agrupamiento La clase org.ROOT_ALIAS).list().class) .next(). cat.hibernate. "F%") ) .list(). while ( iter.excludeZeroes() //excluir las propiedades con valor cero .setSex('F'). identificadores y asociaciones son ignoradas. } 15. 148 de 198 17/02/2009 09:25 a.create(cat) ) .BLACK).BLACK) ) .eq("name".get("kt"). Se puede incluso usar Examples para ubicar criteria en objetos asociados: List results = session.1.createCriteria("mate") . Proyecciones. Captura dinámica de asociaciones Se puede especificar semántica de asociaciones en tiempo de ejecución.list(). FetchMode. "Fritz%") ) . //usar "like' para las comparaciones de cadenas List results = session.setFetchMode("kittens".create( cat.org/documentacion_es/castellano. Cat kitten = (Cat) map.add( Example.class) .createCriteria(Cat.class) .EAGER) . Por defecto. Cat cat = new Cat(). Iterator iter = cats.EAGER) .Example permite construir consultas "criterion" a partir de una instancia dada.5. . Consultas "Example" La clase org. las propiedades con valor nulo son excluidas. Vea la Sección 19.enableLike().hibernar. Se puede ajustar cómo el Example se aplica: Example example = Example. Las propiedades versión.Persistencia Relacional para Java Idiomático http://www.createCriteria("kittens". "kt") .HIBERNATE .list().add( Restrictions.ignoreCase() //efectuar comparaciones de cadenas sin importar mayúsculas/minúscul .m.create(cat) .like("name". usando setFetchMode().eq("color".add( Restrictions.rowCount() ) .add(example) .add( Example. “Estrategias de captura (fetch)” para más información. Cat cat = (Cat) map. Color.setFetchMode("mate".getMate() ) ) .criterion.hasNext() ) { Map map = (Map) iter.setColor(Color.list().6. List results = session.setResultTransformer(Criteria.createCriteria(Cat. 15.

List results = session. Optativamente se le puede asignar un alias a la proyección. En una consulta de tipo Criteria.add( Property.createCriteria(Cat. "color" ) ) . "colr" ) ) .avg("weight") ) .setProjection( Property.name").add( Property.add( Projections.org/documentacion_es/castellano.rowCount().add( Projections.list().createAlias("kittens".class) . También se pueda usar Property.createCriteria(Cat.forName("color").class) .list().forName("weight").addOrder( Order.rowCount().setProjection( Projections.HIBERNATE .add( Projections.groupProperty("color") ) ) .createCriteria(Domestic.class) .class) . List results = session.setProjection( Projections.groupProperty("color"). "catCountByColor" ) .forName("weight").setProjection( Projections.class) .createCriteria(Cat.m.desc("catCountByColor") ) .asc("colr") ) .add( Property.list().as("maxWeight") ) .alias( Projections.asc("colr") ) .eq(Color.createCriteria(Cat.forName("color").add( Projections.max("weight") ) . He aquí dos maneras de hacer esto: List results = session.addOrder( Order.8. List results = session. "kit") .add( Projections.group(). Los métodos alias() y as() simplemente envuelven una instancia de Projection dentro de otra instancia de Projection con alias.addOrder( Order.class) . "catName" ) .createCriteria(Cat. "cat") .list().add( Projections.groupProperty("color").projectionList() .list().groupProperty("color").list().as("avgWeight") ) .addOrder( Order.projectionList() .add( Projections. Consultas y subconsultas desprendidas (detached) 149 de 198 17/02/2009 09:25 a.add( Projections. "kitName" ) ) .desc("catCountByColor") ) .add( Projections.forName("name") ) . .desc("avgWeight") ) .avg("weight"). Como atajo.BLACK) ) .add( Projections.list().max("weight").as("color" ) ) . de manera que las Restrictions y los Orders se puedan referir a él.rowCount() ) .projectionList() .hibernar. "maxWeight" ) . se puede asignar un alias al agregar la proyección a una lista de proyecciones: List results = session.addOrder( Order.class.max(). Algunos tipos de proyección son las denominadas proyecciones agrupadoras (grouping projections) las cuales aparecen en el SQL como cláusulas group by.add( Property.name").setProjection( Projections.setProjection( Projections.html List results = session.as("colr") ) . "avgWeight" ) .addOrder( Order.as("catCountByColor") ) .setProjection( Projections. 15.addOrder( Order.forName() para expresar proyecciones: List results = session.createCriteria(Cat.property("cat.avg().asc("catName") ) .addOrder( Order.add( Projections.asc("kitName") ) . no es necesario que haya explícitamente "group by"s.projectionList() .property("kit.desc("avgWeight") ) .Persistencia Relacional para Java Idiomático http://www.

forName("weight"). List results = query. Una DetachedCriteria también puede usarse para expresar una subconsulta.gt(avgWeightForSex) ) .eqProperty("cat. A continuación.avg() ) .avg() ).naturalId() permite hacer un uso más eficiente del algoritmo de caché.createCriteria(User.class) . "cat2") .list().class) . Incluso son posibles las subconsultas correlacionadas: DetachedCriteria avgWeightForSex = DetachedCriteria. DetachedCriteria avgWeight = DetachedCriteria. y habilitando el caché de 2do nivel. Session session = .eq('F') ).setMaxResults(100). .createCriteria(Cat. Primero se debe mapear la clave natural de su entidad usando <natural-id>. txn. "gavin") 150 de 198 17/02/2009 09:25 a.sex") ).sex").beginTransaction().forName("weight") ).forClass(Cat... La API de Criteria posee disposiciones especiales para este caso de uso.forName("weight"). hay que habilitar el caché de consultas de Hibernate..forClass(Cat. <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. 15. session. porque la invalidación del caché ocurre con demasiada frecuencia.commit().setProjection( Property.forName("weight").add( Subqueries.forClass(Cat.createCriteria(Cat.add( Property.setProjection( Property.list().class) .forClass(Cat. session.9.add( Property.getExecutableCriteria(session). En algunas aplicaciones. Restrictions. Pero hay un tipo especial de consulta con la cual se puede optimizar el algoritmo de invalidación: la búsqueda por clave natural constante.class.hibernar. el caché de consultas no es muy eficiente.geAll("weight". Consultas por identificador natural Para la mayoría de las consultas.list(). session.set("name".html La clase DetachedCriteria permite crear una consulta por fuera del alcance de una sesión.class) .. este tipo de consulta ocurre frecuentemente. session.add( Property. DetachedCriteria weights = DetachedCriteria.Persistencia Relacional para Java Idiomático http://www.forName("cat2.forName("weight").setProjection( Property.class) . incluidas las consultas Criteria.add( Restrictions. session.createCriteria(Cat.list().naturalId() .m.org/documentacion_es/castellano. DetachedCriteria query = DetachedCriteria.class. weights) ) . Transaction txn = session. y más tarde ejecutarla usando alguna sesión arbitraria.gt(avgWeight) ) . Instancias de Criterion que involucren subconsultas pueden ser obtenidas via subconsultas o Property.close().HIBERNATE . "cat") .forName("sex"). Finalmente.class) .add( Property.

addScalar("BIRTHDATE").1. es posible modificarlo a medida.m.set("org". 16.createSQLQuery("SELECT * FROM CATS") . Esto es útil si se quiere utilizar características particulares de una base de datos.setCacheable(true) .addScalar("NAME". Consultas con entidades 151 de 198 17/02/2009 09:25 a. a partir del resultado subyacente. BIRTHDATE FROM CATS").1. o la palabra CONNECT en Oracle.Persistencia Relacional para Java Idiomático http://www.LONG) . Consultas escalares La consulta SQL más básica consiste en obtener una lista de valores escalares. Cómo los java.hibernar.addScalar("BIRTHDATE". sess.createSQLQuery(). SQL nativo También se puede expresar consultas en el dialecto SQL nativo de su base de datos. Hibernate3 permite especificar SQL escrito a mano (incluyendo procedimientos almacenados o "stored procedures") para todas las operaciones de creación. "hb") ). borrado y carga. Usar un SQLQuery La ejecución de SQL nativo se controla a través de la interfaz SQLQuery. mientras que el tipo de ID se especifica explícitamente. Hibernate usará ResultSetMetadata para deducir el orden y tipo de los valores escalares devueltos.STRING) .Types devueltos del ResultSetMetaData se mapean a Hibernate. sess. Capítulo 16. Si un tipo en particular no está mapeado o no se resuelve en el tipo esperado. Hibernate. pero ahora no usará ResultSetMetadata sino que obtendrá explícitamente las columnas ID.DATE). Hibernate. Esto tambíen significa que sólo serán devueltas esas 3 columnas. NAME. usando llamados a registerHibernateType en el dialecto.uniqueResult(). .1. incluso cuando la consulta esté usando * y pueda devolver más columnas que las 3 listadas. A continuación se describe cómo usar esta API para consultar: 16. Es posible omitir la información de tipo para algunos o todos los escalares: sess. NAME and BIRTHDATE como un Long. es controlado por el dialecto. Para evitar el gasto extra de llamar ResultSetMetadata.2. pero ahora se usa ResultSetMetaData par decidir el tipo de NAME Y BIRTHDATE.addScalar("NAME") . la cual se obtiene invocando Session.createSQLQuery("SELECT ID. También provee un estadio de migración claro desde una aplicación basada en SQL/JDBC hacia Hibernate.addScalar("ID". modificación.createSQLQuery("SELECT * FROM CATS").addScalar("ID".org/documentacion_es/castellano. Esta consulta especificó: la cadena SQL de la consulta las columnas y tipos a devolver Esto aún devolverá un array de Objetcs.HIBERNATE .list().createSQLQuery("SELECT * FROM CATS") .1. sess. se puede usar addScalar(). Ésta es esencialmente la misma consulta que antes. Hibernate.html .list().sql. Estas dos consultas devolverán una List de arrays de Objects (Object[]) con valores escalares para cada columna de la tabla CATS.LONG) . Hibernate. como "hints" en las consultas. o simplemente para se más explícito acerca de qué se devuelve. 16. respectivamente. una String y un Short.

si el Cat tuviera varios Dogs asociados de-uno-a-muchos. Cat. es necesario devolver también eso al efectuar la consulta nativa.createSQLQuery("SELECT c. Llegados a este punto. BIRTHDATE. Devolver múltiples entidades En los ejemplos precedentes. etc.class). 16. sess. 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.ID") Lo que se intenta es que esta consulta devuelva dos instancias de Cat por fila: un gato y su madre. Si la entidad está mapeada a otra entidad con una asociación many-to-one (de-muchos-a-uno). BIRTHDATE.1.addEntity("cat".dog").html Las consultas precedentes consistían todas en devolver valores escalares. El problema comienza cuando se devuelven múltiples entidades del mismo tipo.class). las 2 consultas precedentes devolverán una List en la cual cada elemento es una entidad Cat.addEntity(Cat.MOTHER_ID = c.addJoin("cat.Persistencia Relacional para Java Idiomático http://www.getDog() funcione correctamente. "c.addEntity("cat". Las columnas adicionales serán devueltas automáticamente cuando se use la notación *. DOG_ID. Es posible hacer este mismo tipo de join "ávido" para colecciones. a través de addEntity().4. Esto puede ser problematico cuando las consultas SQL tiene "joins" entre varias tablas. DOGS d WHERE c.createSQLQuery("SELECT ID. se necesita inyectar el alias de columna: sess. lo cual no coincide con las 152 de 198 17/02/2009 09:25 a.class). sess. los alias de columna devueltos muy probablemente tendrán la forma "c.I . CATS m WHERE c. .addEntity("mother". Esto permitirá que cat. básicamente devolviendo los valores "crudos" desede el resultset. los Cats devueltos tendrán su propiedad dog enteramente inicializada.3. con las columnas ID. D_NAME FROM CATS c. Esta consulta especificó: la cadena SQL de la consulta la entidad devuelta por la consulta Suponiendo que Cat esté mapeado como clase. NAME. En el ejemplo siguiente (que muy probablemente fallará).addEntity(Cat. dado que pueden aparecer los mismos nombres de columna en más de una tabla. Esto fallará. BIRTHDATE. Cat. pero se prefiere la forma explícita.org/documentacion_es/castellano.hibernar. Cat.ID". D_ID. CAT_ID FROM CATS c. de otro modo ocurrirá un error específico de base de datos del tipo "columna no encontrada". Esto se hace usando el método addJoin().class) . BIRTHDATE FROM CATS").NAME". y.class) . NAME.* . 16. se asume que los nombres de columna del resultado son los mismos que los nombres de columna especificados en el documento de mapeo. el cual permite efectuar el vínculo con asociaciones o colecciones.. FROM CATS c.createSQLQuery("SELECT c.addJoin("cat.addEntity(Cat.createSQLQuery("SELECT * FROM CATS"). D_ID. A continuación se muestra cómo obtener objetos de entidad desde una consulta nativa. m.1. Cat. DOG_ID FROM CATS").createSQLQuery("SELECT ID. porque están mapeados a los mismos nombres de columna. NAME.ID. o cuando los alias/nombres de columna empleados por defecto no son suficientes. por ejemplo. En este ejemplo.m.class).addEntity("cat". NAME. como en el siguiente ejemplo en donde tenemos una relación 'de-muchos-a-uno' con un Dog: sess. NAME y BIRTHDATE. DOGS d WHERE c . sess.class) .*. D_NAME. dado que hay un conflicto de nombres.createSQLQuery("SELECT ID. Note que hemos agregado un nombre de alias ("cat") para poder especificar la propiedad de destino del join. sin necesitad de un viaje adicional de ida y vuelta a la BD. en algunas bases de datos.dogs").HIBERNATE . sess. antes de empezar a mejorar su SQL para que sean usables en Hibernate. casi hemos alcanzado el límite de lo que se puede hacer con consultas nativas.

1. .[componentname].ID") Esta consulta especificó: la cadena de la consulta SQL.name} {coll. Cat.class) .*}. FROM CATS c.id} XID as {coll. 16. Cat. {mother.class} {[aliasname]. Tabla 16.class).createSQLQuery(sql) .addEntity("mother".element. obtenemos los Cats (gatos) y sus madres desde una tabla diferente (cat_log) a la declarada en los metadatos de mapeo. [propertyname]} {[aliasname].addEntity("cat". {mother.currency}.element.birthDate}. Nombres de inyección de alias Descripción Una propiedad simple Una propiedad compuesta El discriminador de una entidad Todas las propiedades de una entidad Una clave de colección El id de una colección El elemento de una colección Una propiedad de elemento en la colección Todas las propiedades del elemento en la colección Sintaxis {[aliasname].element} NAME as {coll.hibernar.*} usada anteriormente es taquigrafía por "todas las propiedades".1. [propertyname]} {[aliasname].[propertyname] {[aliasname]. El parámetro de sustitución para un alias de columna es simplemente el nombre de la propiedad calificado por el alias de la tabla.*} {item.element} {[aliasname]. MOTHER_ID as {c. La forma siguiente no es vulnerable a esta duplicación del nombre de columna: sess. inyección de alias es todo lo que se necesita.id} {[aliasname].m. Cat.id}. hay algunos alias específicos que Hibernate debe usar para preservar el correcto funcionamiento de la inyección de alias.list().*} y {mother. String sql = "SELECT ID as {c.value} DISC as {item. CATS m WHERE c.HIBERNATE .MOTHER_ID = c. List loggedCats = sess. como discriminadores de herencia o propiedades compuestas.org/documentacion_es/castellano.element.*} .name}. Alternativamente. VALUE as {item. con parámetros de sustitución (placeholders) para que hibernate inyecte los alias de columna las entidades devueltas por la consulta La notación con {cat. NAME as {c.Persistencia Relacional para Java Idiomático http://www.key} {[aliasname].amount.class). Nota: los nombres de alias en el resultado son ejemplos.class) .*} {[aliasname]. En el ejemplo siguiente.name} CURRENCY as {item.html columnas especificadas en el mapeo ("ID" y "NAME").addEntity("cat".addEntity("mother".*} 153 de 198 17/02/2009 09:25 a.*} ORGID as {coll.key} EMPID as {coll. " + "BIRTHDATE as {c. Note que incluso se puede usar los alias de propiedad en la cláusula "where" si se quiere. Alias y referencias a propiedades Par la mayoría de los casos. Cat. pero incluso en ese caso dejamos que Hibernate inyecte los alias de columna SQL para cada propiedad. Pero para consultas relacionadas con mapeos más complejos.mother}. se puede listar las columnas explícitamente.*} " + "FROM CAT_LOG c.element.amount.createSQLQuery("SELECT {cat. CAT_LOG m WHERE {c.1. cada alias tendrá un nombre único y probablemente diferente cuando se use. La tabla siguiente muestra las diferentes posibilidades al usar inyección de alias.ID".mother} = c.4.class} Ejemplo A_NAME as {item.

BIRTHDATE FROM CATS") .NAME AS {person. y para definir consultas que inicialicen colecciones. namePattern) .org/documentacion_es/castellano. no necesitamos invocar addEntity(). person.HIBERNATE . <sql-query name="personsWith"> <return alias="person" class="eg.age}.setString("name".m.setString("namePattern". 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.SEX AS {person.setResultTransformer(Transformers.aliasToBean(CatDTO.html Descripción Todas las propiedades de la colección Sintaxis {[aliasname]. Manejar herencia Las consultas de SQL nativas que consulten entidades que estén mapeadas como parte de una herencia.2.addEntity(Cat.sex} FROM PERSON person WHERE person. En este caso. por ejemplo.AGE AS {person. 16. 16.1. person. Los elementos <return-join> y <load-collection> se usan.Person"/> <return-join alias="address" property="person.6. List pusList = query. permitiendo.name}.mailingAddress"/> 154 de 198 17/02/2009 09:25 a.5.list().createSQLQuery("SELECT * FROM CATS WHERE NAME like :name"). <sql-query name="persons"> <return alias="person" class="eg.1. sess.class)) La consulta especificó: la cadena SQL de la consulta un transformador de resultado (result transformer) La consulta precedente devolverá una lista de CatDTO.list().getNamedQuery("persons") .Person"/> SELECT person.1.addEntity(Cat. . Parámetros Las consultas SQL nativas soportan parámetros tanto nombrados como posicionales: Query query = sess. para asociaciones de tipo "join".class). la cual habrá sido instanciada y habrá inyectado los valores de NAME y BIRTHNAME en las propiedades o campos correspondientes.*} Ejemplo 16. Devolver entidades no administradas Es posible aplicarles un ResultTransformer a las consultas SQL nativas. query = sess.hibernar.setMaxResults(50) .NAME LIKE :namePattern </sql-query> List people = sess.setString(0.Persistencia Relacional para Java Idiomático http://www.list(). "Pus%"). devolver entidades no-manejadas.createSQLQuery("SELECT NAME. deben incluir todas las propiedades para la clase base y las subclases. respectivamente. "Pus%"). 16.class).7.createSQLQuery("SELECT * FROM CATS WHERE NAME like ?"). List pusList = query.*} {coll.

org/documentacion_es/castellano.list(). address.PERSON_ID AND address.STREET AS {address.NAME AS {person. person.AGE AS {person.zip} FROM PERSON person JOIN ADDRESS address ON person. 16. . List cats = sess.TYPE='MAILING' WHERE person. address.STATE AS {address.STATE AS {address.mother = cat.2.AGE AS age. address.SEX AS {person.name}. p.CITY AS {address. person.1.NAME LIKE :namePattern </sql-query> Alternativamente. mapeando información en un elemento <resultset> para reutilizarlo.TYPE='MAILING' WHERE person.NAME LIKE 'Hiber%' </sql-query> Se puede externalizar el resultado.Person"/> <return-join alias="address" property="person.SEX AS {person. se puede usar la información de mapeo del resultset contenida en los archivos hbm.age}.sex}.ZIP AS {address.Persistencia Relacional para Java Idiomático http://www.ID = address. cats kitten where kitten.PERSON_ID AND address.sex}. 155 de 198 17/02/2009 09:25 a. address. ya sea en otras consultas nombradas.city}.street}.Person"> <return-property name="name" column="myName"/> <return-property name="age" column="myAge"/> <return-property name="sex" column="mySex"/> </return> SELECT person. Usar return-property para especificar nombres de columna/alias explícitamente Con <return-property> se le puede deicr a Hibernate explícitamente qué alias de columna usar.STREET AS {address.html SELECT person.NAME LIKE :namePattern </sql-query> Una consulta SQL nombrada puede devolver un valor escalar.m. <sql-query name="mySqlQuery"> <return alias="person" class="eg.*} from cats cat.city}.ZIP AS {address. directamente en el código Java.NAME AS {person.NAME AS myName. FROM PERSON p WHERE p. address. person. en lugar de usar la sintaxis {} para dejar que Hibernate inyecte sus propios alias. o a través de la API setResultSetMapping(). <resultset name="personAddress"> <return alias="person" class="eg.CITY AS {address.ID = address.street}. 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.zip} FROM PERSON person JOIN ADDRESS address ON person.state}. address.setResultSetMapping("catAndKitten") . address.age}.id" ) . person. {kitten.NAME AS name.HIBERNATE .hibernar. address.state}.name}.mailingAddress"/> </resultset> <sql-query name="personsWith" resultset-ref="personAddress"> SELECT person.createSQLQuery( "select {cat.AGE AS {person.*}.

EID AS {emp. EMPLOYER. <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. RETURN st_cursor.id}.org/documentacion_es/castellano. END. .SEX AS mySex.endDate}. ENDDATE AS {emp. 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 combinación con la sintaxis {} para inyectar. Para usar esta consulta en Hibernate. STARTDATE AS {emp. a fin de poder trabajar con Hibernate. VALUE. ENDDATE. REGIONCODE.AGE AS myAge. BEGIN OPEN st_cursor FOR SELECT EMPLOYEE. A continuacíón. REGIONCODE as {emp. La mayoría de la documentación que sigue es equivalente para ambos.HIBERNATE . <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.html person. Esto soluciona la limitación de la sintaxis {}.hibernar. la cual no permite un control tan minucioso de las propiedades multicolumna. hay que mapearla con una consulta "nombrada". person. El procedimiento/función debe devolver un conjunto resultado o "resultset" como primer parámetro de salida.employer}. CURRENCY FROM EMPLOYMENT. FROM PERSON person WHERE person. VALUE. Si su mapeo tiene un discriminador. 16.2.2. debe usarse <return-discriminator> para especificar la columna discriminadora.startDate}.m. EID. EMPLOYER AS {emp. permitiéndole al usuario decidir cómo prefiere referirse a columnas y propiedades.NAME LIKE :name </sql-query> <return-property> también funciona con múltiples columnas. un ejemplo de función en Oracle 9 o superior: CREATE OR REPLACE FUNCTION selectAllEmployments RETURN SYS_REFCURSOR AS st_cursor SYS_REFCURSOR.employee}. STARTDATE. Usar procedimientos almacenados para efectuar consultas Hibernate 3 introduce soporte para consultas vía procedimientos almacenados (stored procedures) y funciones.regionCode}.Persistencia Relacional para Java Idiomático http://www.

Los procedimientos almacenados no pueden ser paginados con setFirstResult()/setMaxResults(). 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 (?.) generadas en tiempo de configuración. usar SQL específico de una base de datos reducirá la "portabilidad" de su aplicación. Note que. Los llamdos nativos no se soportan. hay que ejecutarlos via session. Por supuesto. Si aún se desea usar estos procedimientos incompatibles. consulte la literatura de Oracle. pero esto no es obligatorio. ?)}</sql-insert> <sql-delete callable="true">{? = call deletePerson (?)}</sql-delete> <sql-update callable="true">{? = call updatePerson (?.HIBERNATE . como estos servidores son capaces de devolver múltiples resultsets y contadores de actualización. Reglas y limitaciones en el uso de procedimientos almacenados Para usar procedimientos almacenados con Hibernate. El primer parámetro de los procedimientos almacenados debe ser un parámeto de tipo "OUT" que devuelva un resultset.1. modificar o borrar Hibernate3 puede usar comandos SQL a medida para operaciones de creación.2. actualización y borrado. Si no sigue esas reglas. En Oracle hay que definir un tipo REF CURSOR. La invocación recomendada es el estádar de SQL92: { ? = call functionName(<parameters>) } or { ? = call procedureName(<parameters>}. Los "persistores" de clases y colecciones en Hibernate ya contienen un conjunto de cadenas (insertsql. ?)}</sql-update> </class> 157 de 198 17/02/2009 09:25 a.html collection> Note que los procedimientos almacenados actualmente sólo devuelven escalares o entidades. es incompatible con Hibernate. SQL a medida para crear. seguramente éste será más eficiente. ID) VALUES ( UPPER(?).2. ? )</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. <sql-delete>. Si usted puede habilitar SET NOCOUNT ON en su procedimiento.hibernar. Hibernate recorrerá los resultados y tomará el primer resultado que sea resultset. El resto se descarta. .Persistencia Relacional para Java Idiomático http://www. 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. se aplican las siguientes reglas: Las funciones deben devolver un resultado "resultset". 16. updatesql etc. dado que cada proveedor de base de datos tiene una semántica y una sintaxis distinta pars los procedimientos almacenados. el procedimiento o función debe seguir ciertas reglas. Las reglas son diferentes para cada base de datos. Los procedimientos almacenados se soportan. <return-join> y <loadno se soportan.connection(). Esto se logra usando un tipo SYS_REFCURSOR en Oracle 9 o 10. Las tags de mapeo <sql-insert>. deletesql.m. así que usted es libre de utilizar cualquier dialecto que desee.org/documentacion_es/castellano. Para Oracle.3. Para Sybase o MS SQL server se aplican las siguientes reglas: El procedimiento debe devolver un resultset. 16.

hibernar. Hibernate imprimirá el SQL estático que se usa para crear entidades. para las operaciones de ABM (alta-baja-modificación): CREATE OR REPLACE FUNCTION updatePerson (uid IN NUMBER.m. simplemente.persister. borrarlas. recuerde no incluir su SQL a medida en los archivos de mapeo. uname IN VARCHAR2) RETURN NUMBER IS BEGIN update PERSON set NAME = uname.*} FROM EMPLOYMENT emp WHERE EMPLOYER = :id ORDER BY STARTDATE ASC.id} FROM PERSON WHERE ID=? FOR UPDATE </sql-query> Esta es. porque Hibernate realiza algunos chequeos en tiempo de ejecución para verificar el éxito del comando. 16.org/documentacion_es/castellano. como se discutió anteriormente. una declaración de una consulta nombrada (named query). where ID = uid. En la mayoría de los casos. fuertemente recomendado) que los procedimientos almacenados devuelvan el número de filas insertadas/actualizadas/borradas. return SQL%ROWCOUNT.4. etc.name}. END updatePerson. habilitando logueo a nivel "debug" en org.Persistencia Relacional para Java Idiomático http://www. ID AS {pers. Se puede incluso definir un a consulta para cargar la colección: <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. SQL a medida para cargar Se puede también 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.entity. actualizarlas. (Para ver la secuencia esperada. Con esta categoría habilitada. Hibernate siempre registra el primer parámetro del "statement" como de salida y numérico. es obligatorio (o más bien. Se puede ver el orden esperado. dado que deben estar en la misma secuencia en que Hibernate los espera. 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.html El orden de los parámetros posicionales es ahora esencial.. dado que éste suplantará al SQL estático generado por Hibernate).HIBERNATE .employments"/> SELECT {emp. EMPLOYEE ASC </sql-query> 158 de 198 17/02/2009 09:25 a. .hibernate.

17. Un filtro de Hibernate es un filtro global. Los filtros pueden ser usados como vistas (views) de la base de datos. nombrado y parametrizado.setParameter("myFilterParam". esto se vería así: session.hibernar. usando datos con el patrón de programación 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..1.Filter que permiten el encadenamiento de filtros.*}..org/documentacion_es/castellano. Excepto que estas condiciones de filtrado pueden ser parametrizadas. Note que hay métodos en la interfaz org. muy común en Hibernate. Por defecto. <filter name="myFilter" condition=":myFilterParam = MY_FILTERED_COLUMN"/> </class> o a una colección: <set . Para definir un filtro.ID = emp.> . y adjuntar esos filtros tanto a nivel de la clase como a nivel de la colección.html Hasta se puede definir un "cargador de entidades" que cargue una coleccíón mediante captura con "join": <sql-query name="person"> <return alias="pers" class="Person"/> <return-join alias="emp" property="pers. Filtros de Hibernate Hibernate3 incorpora la capacidad de predefinir criterios de filtrado. al mismo tiempo.> <filter name="myFilter" condition=":myFilterParam = MY_FILTERED_COLUMN"/> </set> o incluso a ambas. Para usar filtros. Filtrar datos Hibernate3 provee un enfoque innovador para manejar datos que tengan "reglas de visibilidad".Persistencia Relacional para Java Idiomático http://www. Un cirterio de filtrado es la capacidad de definir una cláusula de restricción. que puede estar habilitado o inhabilitado para una sesión en particular. primero tienen que ser definidos y adjuntados al elemento de mapeo correspondiente. "some-value"). 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...*} FROM PERSON pers LEFT OUTER JOIN EMPLOYMENT emp ON pers. La aplicación puede. deben ser habilitados explícitamente mediante el uso del método Session.enableFilter("myFilter").enableFilter(). o a varias de ambas. pero parametrizados dentro de la aplicación. . muy similar al atributo "where" disponible en la clase y varios elementos de colecciones. {emp... y cuáles deberían ser sus parámetros. getEnabledFilter(String filterName).employments"/> SELECT NAME AS {pers. el cual devuelve una instancia de la interfaz Filter. tomar decisiones en tiempo de ejecución acerca de si un filtro debería estar habilitado. Usando el filtro simple definido antes. este filtro puede ser adosado a una clase: <class name="myClass" . y disableFilter(String filterName).HIBERNATE . los filtros no están habilitados para una sesión dada.m. Un ejemplo completo.PERSON_ID WHERE ID=? </sql-query> Capítulo 17. Los métodos en Session son: enableFilter(String filterName). entoces.hibernate.

org/documentacion_es/castellano.createQuery("from Employee as e where e.. que estén actualmente activos.> . Nota: si se planea usar filtros con "outer joins" (sea a través de HQL o de estrategias de "fetch") tenga cuidado con la dirección de la expresión de condición. 18. en lugar de los POJOs.. new Date()).. Hibernate soporta la API dom4j para manipular los árboles XML. antes de capturar datos de empleados: Session session = . <filter-def/> permite definir una condición por defecto.enableFilter("effectiveDate")..salary > :targetSalary") ..html </filter-def> <class name="Employee" .setLong("targetSalary". Lo más seguro es configurarlo como "left outer join". new Long(1000000)) . un filtro puede ser adosado a entidades y/o colecciones.. Un árbol XML válido puede ser concebido como sencillamente otra forma de representar los datos relacionales a nivel de objetos.. <!-Note que esto asume que los registros no-terminales tinenen una fecha de finalización efect a la cual se le asignó el máximo valor de fecha posible en la BD. simplemente habilite el filtro en la sesión. Trabajar con datos XML Hibernate le permite trabajar con datos persistentes en XML de la misma forma en que lo haría con POJOs. Por esto..m.> .1.. ponga el parámetro primero. <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"/> .. sea como un atributo. seguido por el nombre o nombres de columna luego del operador.list().. . cada una con su propia condición.. a causa del filtro habilitado. para asegurarse de que siempre se obtiene el registro más actual.setParameter("asOfDate"... esta condición por defecto será usada siempre que el filtro se adjunte a algo sin haber especificado una condición. Note que esto significa que se puede dar una condición específica como parte de la adjunción del filtro. Eso puede ser tedioso cuando las condiciones son las mismas en todos los casos. o como CDATA: <filter-def name="myFilter" condition="abc > xyz">. Capítulo 18. incluso si sólo se mencionó una condición relativa al salario en los resultados. Se puede escribir consultas que obtengan árboles dom4j 160 de 198 17/02/2009 09:25 a. En el HQL precedente.0. --> <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. session.hibernar.Persistencia Relacional para Java Idiomático http://www.. para simplificar. Luego de haber sido definido. la consulta devolverá los empleados que con un salario mayor a un millón y. que suplanta a la condición por defecto para ese caso en particular.</filter-def> <filter-def name="myOtherFilter">abc=xyz</filter-def> Entonces.HIBERNATE . List results = session. en general. Mapeo XML Note que ésta es una característica experimental en Hibernate 3. y se encuentra actualmente en muy activo desarrollo.

Persistencia Relacional para Java Idiomático http://www.html desde la base de datos. Si se especifica embedes el valor por defecto. Esta habilidad tiene muchos usos. 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. 18. al elemento especificado del atributo especificado. hay un atributo embed-xml adicional. </class> 18. sólo el documento XML.. analizarlo usando dom4j. saveOrUpdate(). En caso contrario. o.1.. y producción de reportes basada en XSLT. replicate() (merge aún no se soporta). "element-name/@attribute-name": mapea Para asociaciones y asociaciones a valores simples. si no hay ninguna clase para mapear. El formato del atributo node debe ser uno de los siguientes: "element-name": mapea al elemento XML especificado al atributo XML especificado. Especificar sólo 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"/> ..2.1. Incluso se puede tomar un documento XML. entonces sólo el valor del identificador al que se hace referencia aparecerá en el XML (para asociaciones xml="true". externalización de entidades via JMS o SOAP. Un solo mapeo puede ser usado para mapear simultáneamente las propiedades de una clase y los nodos de un documento XML a la base de datos. 18. Los nombres de las propiedades son construcciones puramente lógicas. lo cua 161 de 198 17/02/2009 09:25 a. "@attribute-name": mapea ". merge(). a las que se puede hacer referencia en consultas HQL. delete(). si embedxml="false". incluyendo: importación/exportación de datos.HIBERNATE . y escribirlo en la base de datos con cualquiera de las operaciones básicas de Hibernate: persist(). Especificar el mapeo XML y el mapeo de la clase al mismo tiempo He aquí un ejemplo de mapeo de un POJO y XML simultáneamente: <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"/> .2.org/documentacion_es/castellano. el árbol XML para la entidad asociada (la de tipo colección o "value type") será incrustada directamente en el árbol XML de la entidad que posee la asociación.m. </class> Este mapeo permite acceder a los datos como si fueran un árbol dom4j.hibernar.1.": mapea al elemento padre. .. y lograr que cualquier modificación practicada al XML se sincronice automáticamente a la base de datos. o una representación en forma de pares nombre/valor (Maps de Java).

los datos se verían así: <customer id="123456789"> <account id="987632567" short-desc="Savings"> <customer id="123456789"/> <balance>100. pero no los datos de las cuentas propiamente dichas..html de "value type"s) y para las colecciones no aparecerá nada. La siguiente consulta HQL: from Customer c left join fetch c.hibernar..accounts where c. hemos decidido incrustar una colección de ids de cuentas (accounts)...3.. ¡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=".29</balance> </account> <account id="985612323" short-desc="Credit Card"> <customer id="123456789"/> <balance>-2370.. </customer> Si se asigna embed-xml="true" en el mapeo <one-to-many>.HIBERNATE .lastName like :lastName Devolvería 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> ." 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> .org/documentacion_es/castellano. Manipular datos XML 162 de 198 17/02/2009 09:25 a. </class> en este caso.Persistencia Relacional para Java Idiomático http://www. Debería tenerse cuidado de no asignarles embed-xml="true" a demasiadas asociaciones. . </customer> 18.34</balance> </account> <name> <first-name>Gavin</first-name> <initial>A</initial> <last-name>King</last-name> </name> .m.

list(). Session dom4jSession = session. Lo hacemos obteniendo una sesión dom4j: Document doc = .setText(firstName).element("name"). Element cust = (Element) dom4jSession. este segundo SELECT sólo se ejecutará cuando realmente se acceda a la asociación.element("last-name").getSession(EntityMode.commit(). captura por lotes (batch fetching): es una estrategia de optimización de la captura por Select. A menos que se inhabilite la captura haragana (lazy fetching) especificando lazy="false". este segundo SELECT sólo se ejecutará cuando realmente se acceda a la asociación. A menos que se inhabilite la captura haragana (lazy fetching) especificando lazy="false".beginTransaction(). Session session = factory.size(). captura poe Subselect: se usa un segundo SELECT para obtener todas las entidades o colecciones asociadas. Las estrategias de captura pueden ser declaradase en los metadatos de mapeo. captura por Select: se usa un segundo SELECT para obtener la entidad o colección asociada. o bien ser sustituidas para una consulta HQL o Criteria en particular.HIBERNATE .get("Customer". colección o atributo son capturados inmediatamente.setText(lastName). i++ ) { Element customer = (Element) results. que se habían obtenido en el SELECT anterior. name.DOM4J). Combinar esta funcionalidad con la operación replicate() es extremadamente útil para implementar la importación/exportación de datos basados en XML: Capítulo 19.get(i). Transaction tx = session.getSession(EntityMode. Hibernate también distingue entre: captura inmediata: la asociación. customerId). agregándole un OUTER JOIN al SELECT mismo. sino una lista de claves primarias o foráneas. session.get(i).openSession(). //cambia el nombre del cliente en el XML y en la BD Element name = customer. i<results. especificando no una.element("initial").hibernar.1. Estrategias de captura (fetch) Una estrategia de captura es la estrategia que Hibernate usará para obtener los objetos asociados.accounts where c. i<results.org/documentacion_es/castellano.. i++ ) { //le agrega los datos del cliente (customer) al documento XML Element customer = (Element) results.setText(initial).createQuery("from Customer c left join fetch c. sino un lote (batch) de instancias de entidad o colección en un solo SELECT. 163 de 198 17/02/2009 09:25 a. Transaction tx = session. Mejorar la performance 19.m.close(). name. doc. cuando Hibernate necesite navegar una asociación..add(customer).element("first-name").lastName like :lastName") . } tx. } tx.html Vamos a leer y actualizar documentos XML en la aplicación.close(). Session dom4jSession = session. name.. Hibernate obtiene no una..commit(). session.beginTransaction(). for ( int i=0.size().openSession().Persistencia Relacional para Java Idiomático http://www. Hibernate3 define las siguientes estategias de captura: captura por Join Hibernate obtiene la instancia o colección asociada. Session session = factory.DOM4J). cuando el dueño es cargado. for ( int i=0. List results = dom4jSession . .

Transaction tx = s. captura haragana de atributos: un atributo o asociación de valor simple. Alternativamente.html captura haragana de colecciones: una colección es capturada sólo cuando la aplicacíón invoca alguna operación en esa colección (éste es el comportamiento por defecto para las colecciones). la captura haragana plantea un problema del cual hay que ser consciente: acceder a asociaciones haraganas por fuera del contexto de una sesión abierta de Hibernate. especificando lazy="false" para el mapeo de la asociación. 19.createQuery("from User u where u.hibernar. captura "súper-haragana" de colecciones (extra-lazy collection fetching): se accede a elementos individuales de la colección desde la base de datos. tx. captura por Proxy: una asociación de un solo valor se captura cuando se invoca sobre éste cualquier otro método que no sea su getter/setter. User u = (User) s.default_batch_fetch_size. y cómo se captura (qué SQL se usa). Ahora veremos cómo diseñar una estrategia de captura a medida. la colección será incapaz de cargar su estado.close(). y sólo raramente es necesario. para una transacción en particular. pero más transparente.openSession(). los mecanismos para elegir una estrategia de captura son idénticos para las asociaciones de valor simple y para las colecciones. ¡Hibernate terminará cargando toda la base de datos en memoria para cada transacción! Por otra parte. captura sin proxy: una asociación de un solo valor se captura cuando se accede a la variable de instancia . Estos valores por defecto tienen sentido casi siempre. En Hibernate3.1.setString("userName". Nota: si se inicializa la variable de configuración hibernate.m.commit(). De todos modos. userName).1.beginTransaction().Persistencia Relacional para Java Idiomático http://www. De todos modos.uniqueResult(). se espera que se use inicialización haragana en casi todos los casos.2. En comparación con la captura por proxy. La solución es mover el código que lee de la colección a justo antes de que la transacción invoque "commit". Este abordaje requiere instrumentación bytecode de tiempo de compilación. Ajustar las estrategias de captura La captura por select (el comportamiento por defecto) es extremadamente vulnerable a los problemas de N+1 SELECTS.1. dado que no hay ningún proxy visible para la aplicacíón.get("accounts"). sólo en la medida en que se necesita. Hibernate usará la optimización de captura por lotes para las capturas haraganas. 19. 164 de 198 17/02/2009 09:25 a. Si se definen demasiadas asociaciones no haraganas.HIBERNATE . Por ejemplo. este abordaje es menos haragán (se accede a la asociación incluso si sólo se usa el identificador). podríamos usar una colección o asociación no haragana. Map permissions = u. Integer accessLevel = (Integer) permissions. s = sessions.org/documentacion_es/castellano. Trabajar con asociaciones haraganas Hibernate3 usa por defecto "select haragán" para las colecciones. a menudo querremos elegir captura por join (la cual que es naturalmente no haragana) en lugar de captura por select. Se puede usar la palabra lazy para definir un contrato sobre qué estará disponible y qué estará desprendido para una clase en particular. Esta optimización puede también ser habilitada a un nivel más granular. Este abordaje requiere instrumentación bytecode de tiempo de compilación. Aquí tenemos dos nociones ortogonales: cuándo la asociación se captura. . se capturan cuando se accede a la instancia o asociación. Hibernate no intenta capturar toda la colección en memoria. y "captura haragana por proxy" para las asociaciones de valor simple. // ¡Error! Como la colección "permissions" no estaba inicializada cuando la sesión fue cerrada. resultará en una excepción. a menos que sea absolutamente necesario (esto es lo adecuado para colecciones muy extensas). y sólo raramente es necesario.getPermissions(). Hibernate no soporta la inicialización haragana de objetos desprendidos. s. y para casi todas las asociaciones. ¡A no confundir una con la otra! Se usa la palabra fetch para ajustar la eprformance.name=:userName") .

class) .. y lo sustituiremos para una transacción en particular.. usando un outer join. se garantiza que el árbol "no haragán" definido se cargará en memoria.1..add( Restrictions.JOIN). Proxies de asociaciones de un solo extremo La captura haragana para colecciones se implementa usando la implementación para colecciones persistentes de Hibernate mismo. por Si se deseare cambiar la estrategia de captura usada por get() or load().JOIN) .m. 19. con el atributo proxy. (Éste es el equivalente en Hibernate de lo que algunas soluciones ORM llaman un plan de captura o "fetch plan"). En la API de consultas Criteria. A la entidad blanco de la asociación se le debe crear un "proxy"..setFetchMode("permissions". <subclass name="DomesticCat"> . mentendremos el comportamiento por defecto.createCriteria(User. Hibernate implementa los proxies de inicialización haragana para objetos persistentes usando "mejora de bytecode en tiempo de ejecución" (a través de la excelente biblioteca CGLIB). Hibernate3 genera proxies por defecto (durante el arranque) para todas las clases persistentes. en el primer SELECT. Normalmente no usaremos el documento de mapeo para ajustar el tipo de captura.. Esto le dice a Hibernate que capture la asociacíón en forma ansiosa. . ¡Recomendamos este constructor para todas las clases persistentes! Hay algunas dificultades muy comunes. Tenga en cuenta que la clase a la cual se le crea el proxy debe implementar un constructor por defecto (sin parámetros). Note que esto puede resultar en que se usen varios SELECTs inmediatamente para ejecutar una consulta HQL en particular. </subclass> </class> 165 de 198 17/02/2009 09:25 a. usando left join fetch en HQL. FetchMode.hibernar.HIBERNATE . Criteria. con visibilidad por defecto o "package" por lo menos.org/documentacion_es/castellano. se usaría setFetchMode(FetchMode. Hibernate usa por defecto una subclase de la clase.idEq(userId) ) . <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 obtención de datos via get() o load() la obtención de datos que ocurre implícitamente cuando se navega la asociación las consultas Criteria las consultas HQL (si se usa la captura por subselect ) Sin importar qué estrategia de captura se use..html Así que tal vez querramos habilitar la captura por join en el documento de mapeo.uniqueResult(). 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).Persistencia Relacional para Java Idiomático http://www. de las cuales conviene estar al tanto a la hora de extender este enfoque a clases polimórficas. simplemente habría que usar una consulta ejemplo: User user = (User) session. Una forma completamente distinta de evitar los problemas con N+1 selects es usar el caché de 2do nivel. El archivo de mapeo puede declarar una interfaz para ser usada como la "interfaz de proxy" para una clase determinada...3.. Sin embargo. por ejemplo: <class name="Cat" proxy="Cat"> . En cambio. se necesita un mecanismo diferente para el comportamiento haragán en las asociaciones de extremo simple.

) Cat cat = (Cat) session.class.println(cat==dc). } // instancia un proxy (no llama a la base de datos) // llama a la base de datos para inicializar el proxy // ¡Error! En segundo lugar.class.createQuery("from CatImpl as cat where cat.load(Cat. // instancia un proxy de Cat // adquiere un nuevo proxy par // falso Sin embargo.de proxies. Por ejemplo: <class name="CatImpl" proxy="Cat"> .HIBERNATE .getWeight() ). podemos evitar los problemas asociados con la conversión ("cast") entre tipos.Persistencia Relacional para Java Idiomático http://www.class. La clase proxy es una verdadera subclase de la clase persistente. entonces dichos recursos serán también adquiridos por el proxy. id). no CatImpl.load(CatImpl. if ( cat. Inicializar proxies y colecciones 166 de 198 17/02/2009 09:25 a. incluso cuando la instancia subyacente sí es una instancia de DomesticCat: Cat cat = (Cat) session. si su clase persistente adquiere recursos durante la inicialización (por ejemplo.name='fritz'"). Cat fritz = (Cat) iter.. Las relaciones también son incializadas en forma haragana.out. no se puede usar un proxy CGLIB para clases final ni para clases que tengan métodos final..load(Cat. si la clase persistente no sustituye equals() si la clase persistente no sustituye hashCode() hashCode(). id). el getter del método identificador Hibernate detectará las clases persistentes que sustituyan (override) equals() o hashCode().0). esta situación no es tan mala como parece. Y usted debe especificar estas interfaces en el documento de mapeo. 19. Así. id). Ciertas operaciones no requieren inicialización de proxies: equals(). Sin embargo. System.html Primero que nada.org/documentacion_es/castellano. (Note que list() normalmente no devuelve proxies.1.next(). y todas las operaciones resultarán en una inicialización de proxy inmediata. Incluso si ahora tenemos dos referencias a objetos "proxy" diferentes.. . .0 En tercer lugar. Si usted quiere evitar estos problemas.class.. // llama a la base de datos para inicializar el proxy System. cada una de sus clases persistentes debe implementar una interfaz que declare sus métodos de negocio.. los proxies para instancias de Cat y DomesticCat pueden ser devueltos por load() o por iterate()..hibernar.iterate(). Por último. // 11. en inicializadores o constructores por defecto). necesitaremos instrumentación de bytecode en tiempo de compilación. DomesticCat dc = (DomesticCat) session. Eligiendo lazy="no-proxy" en lugar del lazy="proxy" que viene por defecto.load(DomesticCat. Cat cat = (Cat) session.4. Iterator iter = session.m.out. la instancia subyacente aún es el mismo objeto: cat. es posible romper el operador ==.isDomesticCat() ) { DomesticCat dc = (DomesticCat) cat. las instancias de la clase Cat jamás podrán ser convertidas con "cast" a DomesticCat.. catid). </subclass> </class> en donde CatImpl implementa la interfaz Cat y DomesticCatImpl implementa la interfaz DomesticCat.setWeight(11. Esto significa que toda propiedad debe ser declarada como de tipo Cat. Estos problemas se deben todos a limitaciones fundamentales del modelo de herencia única de Java.println( dc. <subclass name="DomesticCatImpl" proxy="DomesticCat"> .

Pero esto sería confuso para quien leyere el código.hibernar. o en distintos procesos físicos.getKittens(). asegurarse de que una única sesión se mantenga abierta cuando una colección se inicialice puede llegar a ser un problema.size().HIBERNATE . Por supuesto. siempre podemos forzar la inicialización invocando cat. u obtiene la colección en forma ansiosa usando una consulta de Hibernate con cláusula FETCH o con un FetchMode. Imagínese que tiene la siguiente situación en tiempo de ejecución: Hay 25 instancias de Cat cargadas en la sesión.initialize( cat. cuando la entidad que posea la colección o que tienga una referencia al proxy esté en un estado desprendido. Hibernate. . 19. Normalmente.get(0) ). siempre y cuando su sesión esté aún abierta. lazy="true".setMaxResults(10). Usar la captura por lotes Hibernate puede hace un uso eficiente de la captura por lotes. Hibernate por defecto ejecutará 26 comandos SELECT.setFirstResult(0). Hibernate no debería hacer esto automáticamente. su tamaño).intValue() El método createFilter() se usa también para obtener eficientemente subconjuntos de una colección sin necesidad de inicializarla toda. También se puede adjuntar un objeto previamente cargado a una nueva sesión.initialize(cat) forzará la inicialización del proxy. incluso cuando ocurriere una excepción mientras se presentare la interfaz de usuario. Hay básicamente dos maneras de lidiar con esto: En una aplicación de web. ¡puesto que ello introduciría una semántica de transaccion ad hoc! A veces usted no querrá inicializar toda una colección muy extensa. Es decir.5. Por supuesto. La captura por lotes es una optimización del tipo de captura por "SELECT haragán"). Si se itera a través de todos los gatos (cats) y se invoca getOwner() en cada uno de ellos. Esto significa que la capa de negocios debería cargar todos los datos que hagan falta para un caso en particular.createFilter( lazyCollection. Los métodos estáticos Hibernate. se puede usar un filtro de servlet para cerrar la sesión sólo cuando realmente se llegue al final de la request. Hay dos maneras de ajustar la captura por lotes: en la clase. s. para obtener los proxies de los dueños. por ejemplo. esto crea una pesada responsabilidad en cuando a la corrección del manejo de excepciones por parte de la infraestructura de la aplicación.list(). (O colecciones. una instancia de Person.isInitialized() le proveen a la aplicación una forma conveniente de trabajar con colecciones o proxies que hayan sido inicializados en forma haragana. Esto es normalmente más fácil si se adopta el patrón de programación Command en lugar del patrón Session Façade.JOIN en el Criteria. Se puede ajustar este comportamiento especificando un batch-size (tamño de lote) en el mapeo de Person: 167 de 198 17/02/2009 09:25 a. con merge() o lock() antes de acceder a colecciones (u otros proxies) no inicializados. Vea la wiki de Hibernate para ejemplos de este patrón "Open Session in View". cada Cat tiene una referencia a su dueño.org/documentacion_es/castellano. o a nivel de la colección. e inconveniente para cualquier código que intentare ser genérico. cat. y devolvérselos a la capa de interfaz de usuario/web. la lógica de negocio debe "preparar" todas las colecciones que vayan a ser necesitadas por la capa de web. La clase Person está mapeada con un proxy.createFilter( collection.1.Persistencia Relacional para Java Idiomático http://www. particularmente en donde el código que accede a Hibernate y el código que lo usa están en distinas capas.html Si se trata de acceder a una colección o proxy no inicializados fuera del alcance de una sesión. "").list().getSex() o cat. Se puede usar un filtro de colección para obtener el tamaño de una colección sin inicializarla: ( (Integer) s.getKittens() ) tiene un efecto similar para la colección de kittens (gatitos). o un subconjunto de sus datos. una vez que la presentación de la interfaz de usuario (view) ha sido completada (el patrón de programación Open Session in View ).m. la aplicación llama a Hibernate. A veces necesitamos asegurarnos de que un proxy o colección sean inicializados antes de cerrar la sesión. Otra opción es mantener la sesión abierta hasta que todas las colecciones y proxies necesarios hayan sido cargados. Hibernate. pero sí necesitará un poco de información acerca de ella (por ejemplo. es decir que puede cargar varios "proxies" no inicializados cuando se accede a uno. Es de vital importancia que la sesión sea cerrada y la transacción concluida antes de retornar el control al usuario. No. En la arquitectura de algunas aplicaciones. La captura por lotes a nivel de la clase es más fácil de entender.initialize() e Hibernate. "select count(*)" ). En aplicaciones que tengan una capa de negocios separada.initialize() para cada colección que vaya a ser necesaria en la capa de web (este llamado ocurre antes de que la sesión se cierre). Hibernate emitirá una LazyInitializationException. antes de retornar.

Para la instrumentación bytecode. si cada Person tiene un colección haragana de Cats.. Hibernate ignorará silenciosamente la configuración de propiedades a "lazy". use la siguiente tarea de Ant: <target name="instrument" depends="compile"> <taskdef name="instrument" classname="org. Hibernate pre-capturará las colecciones: <class name="Person"> <set name="cats" batch-size="3"> . . </set> </class> Con un a batch-size igual a 3.6. 3. Hibernate cargará 3.</class> Hibernate ahora ejecutará sólo 3 consultas: el patrón es 10. 10. Esta técnica de optimización también se conoce como grupos de captura (en inglés "fetch groups"). También se puede habilitar la captura en lotes de colecciones.class"/> 168 de 198 17/02/2009 09:25 a.1.hibernar.org/documentacion_es/castellano.1. 19. por ejemplo. 5. 3.. Usar la captura por subselect Si una colección o proxy de valor simple haraganes tienen que ser capturados. por sus siglas en inglés). la típica "Lista de Materiales" necesarios para construir una pieza (bill of Materials o BOM.HIBERNATE . De todos modos. 19. Hibernate los carga todos. Si se habilita la captura por lotes para las colecciones de cats en el mapeo de Person. leer sólo algunas propiedades de una clase puede ser útil en algunos casos extremos. pero sin la carga "parte por parte".dir}/org/hibernate/auction/model"> <include name="*. dado que. y en un momento hay 10 personas cargadas en la sesión.InstrumentTask"> <classpath path="${jar. el valor del atributo dependerá del número esperado de colecciones no inicializadas para una sesión en particular. dese cuenta de que esto es un extra más publicitario que funcional. (Aunque para árboles de "mayormente lectura" un set anidado o un "path materialziado" serían mejores opciones) . y se resignará a usar la captura inmediata usual.7.. Esto funciona de la misma manera que la captura por lotes.class.m. 1 colecciones en 4 SELECTs.dir}"/> <classpath refid="lib. Usar la captura de propiedades haragana Hibernate3 soporta la captura haragana de propiedades individuales. volviendo a ejecutar la consulta original en un subselect. optmizar las lecturas de filas es mucho más importante que optimizar las lecturas de columna. iterar a través de todas esas personas generaría 10 SELECTs. configure el atributo lazy en mapeos de propiedad específicos: <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 instrumentación bytecode de tiempo de compilación! Si sus clases persistentes han sido mejoradas. en la práctica.. Para habilitar la carga haragana de propiedades. De nuevo. en donde tablas anticuadas/heredadas tengan cientos de columnas y el modelo de datos no pueda ser mejorado.Persistencia Relacional para Java Idiomático http://www.hibernate.instrument. La captura por lotes es particularmente útil si se tiene un árbol anidado de items.html <class name="Person" batch-size="10">.path"/> </taskdef> <instrument verbose="true"> <fileset dir="${testclasses. Por ejemplo. uno por cada llamado a getCats().path}"/> <classpath path="${classes. Por favor.tool.

Hibernate trae incorporada una buena cantidad de integraciones con proveedores de cachés open-source. Existe la opción de decirle a Hibernate qué implementación de cacheo usar.x sí (requiere sí sincronización (replicación) de relojes) sí sí (requiere (replicación sincronización o de relojes) invalidación) en cluster JBoss Cache (multicast de org. que se aplique a una o más clases en particular. usando fetch all properties en HQL.HashtableCacheProvider que sea usado en producción) EHCache OSCache org.m. Esto evita la necesidad del bytecode de tiempo de compiación.OSCacheProvider memoria sí memoria.provider_class.cache. Se puede forzar la captura ansiosa usual de propiedades. Éste ya no es el caso a partir de 3.hibernate. transaccional 19.EhCacheProvider org.hibernate. se puede implementar un caché propio y enchufarlo como se indicó anteriormente. Table 19.hibernate.cache.2. Se puede incluso "enchufar" un caché en cluster. es usar las capacidades de proyección (Projections) que tienen las consultas HQL y Criteria. usando la propiedad hibernate. 19. porque los cachés nunca están al tanto de los cambios que le hayan sido hechos al repositorio de datos persistente por otra aplicación (aunque sí pueden ser configurados para que sus datos cacheados expiren regularmente luego de un cierto tiempo).Persistencia Relacional para Java Idiomático http://www. .hibernate. especificando el nombre de una clase que implemente org. Prveedores de Caché Soporta el Seguro para caché de usar en consultas clusters (Query) Caché Clase del proveedor Tipo Hashtable (no se espera org.cache.2.hibernate.JBossCacheRegionFactory 2 ip). disco en sí cluster(multicast (invalidación de ip) de cluster) en cluster (multicast de ip).hibernate. El caché de 2do nivel Una sesión (Session) de Hibernate.SwarmCacheProvider JBoss Cache org. o a nivel de la JVM (a nivel de la SessionFactory o fábrica de sesiones).html </fileset> </instrument> </target> Una manera diferente (y tal vez mejor) de evitar lecturas de columa innecesarias. Es posible configurar un caché a nivel de cluster.hibernate. además.2 exclusive usaban EhCache como su proveedor por defecto. al menos en transacciones de sólo-lectura.2.cache.cache.1.HIBERNATE .org/documentacion_es/castellano.1.jbc2. Mapeos de caché El elemento <cache> del mapeo de una clase o colección 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. Nota: las versiones hasta 3. Hay que tener cuidado. disco memoria.TreeCacheProvider 1.cache. (listados a continuación).cache. es un caché de datos persistentes a nivel de la transacción.cache. y/o a una o más colecciones en particular.hibernar. y es ciertamente una solución preferible. transaccional sí sí SwarmCache org.CacheProvider.

4. y no se requiere un aislamiento de transacciones estricto.2. por defecto. <class name="eg. Alternativamente (y tal vez preferiblemente) se puede especificar elementos <class-cache> y <collection-cache> en el archivo hibernate..transaction.. <class name="eg. se debe especificar hibernate. Si el caché se usa en un entorno JTA.2..m. </class> 19. Si se quiere usar esta estrategia en un cluster. Estrategia transaccional 170 de 198 17/02/2009 09:25 a. Estrategia de sólo-lectura Si su aplicación necesita leer pero nunca modificar las instancias de una clase persistente. nonstrict-read-write or (2) caché de 2 (3) include (optativo. pero sólo ocasionalmente (es decir.xml..org/documentacion_es/castellano. Esta estrategia de cacheo nunca debería ser usada si se requiere aislamiento de transacciones serializables. 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. En otros entornos. por defecto. 19.close() o Session.. Si el caché se usa en un entorno JTA. <set name="kittens" . si es improbable que dos transacciones traten de actualizar el mismo ítem simultáneamente). puede ser apropiado un caché "de lecto-escritura no estricta" (nonstrict-read-write). hay que asegurarse de que la transacción esté completa para cuando ocurran Session.manager_lookup_class. Los proveedores de caché que vienen ya incorporados no lo soportan. Estrategia de lecto-escritura Si la aplicación necesita actualizar datos.Persistencia Relacional para Java Idiomático http://www..Immutable" mutable="false"> <cache usage="read-only"/> .close() o Session. También es perfectamente segura de utilizar en un cluster. hay que asegurarse de que la implementación subyacente de caché soporta "locking".. 19. > <cache usage="read-write"/> ..2.HIBERNATE . read-write.disconnect().. Estrategia de lecto-escritura no estricta Si la aplicación necesita actualizar datos.transaction.cfg.Cat" .manager_lookup_class.. Esta es la estrategia más simple y la de mejor performance. En otros entornos. se puede usar un caché read-only. puede ser apropiado usar una caché de lecto-escritura (read-write).disconnect(). > <cache usage="read-write"/> . do el nombre de rol de la clase o colección): especifica el nombre de la región del nivel..2.5. EL atributo usage especifica una estrategia de concurrencia de caché. . especificando una estrategia para obtener la propiedad TransactionManager de JTA.. se debe especificar la propiedad hibernate. </set> </class> 19.3. region (optativo.2.html /> (1) usage (obligatorio) especifica read-only la estrategia de cacheo transactional.hibernar.. hay que asegurarse de que la transacción esté completa para cuando ocurran Session..

dicho objeto se agrega al caché interno de la sesión. Compatibilidad entre el proveedor de caché y la estrategia de concurrencia Importante Ninguno de los proveedores de caché soporta todas las estrategias de concurrencia.m. sess.class). Cuando a continuación se invoca flush().clear() Para el caché de 2do nivel.transaction. } La Session también provee un método contains() para determinar si una instancia ya pertenece al caché de sesión. CacheMode.hibernar.HIBERNATE . de la instancia de una colección.2. sessionFactory. Para desalojar a todos los objetos del caché de sesión. . catId).kittens".html La estrategia transaccional (transactional) provee soporte para proveedores de caché enteramente transaccionales. catId). doSomethingWithACat(cat).2. //desaloja un colección de kittens en particu sessionFactory. Admninistrar los cachés Siempre que un objeto se le pase a save().evict(Cat. get(). //desaloja todos los Cats sessionFactory.evict(Cat. update() o saveOrUpdate(). y se debe especificar hibernate. Tabla 19.3. //desaloja todas lsa colecciones de kittens El argumento CacheMode controla cómo una sesión en particular interactúa con el caché de 2do nivel. o si se está procesando una cantidad inmensa de objetos que haga necesario manejar la memoria eficientemente.evictCollection("Cat. el estado de dicho objeto será sincronizado con la base de datos. llame Session.createQuery("from Cat as cat").NORMAL: lee y escribe items en el caché de 2do nivel 171 de 198 17/02/2009 09:25 a. list().next() ) { Cat cat = (Cat) cats.class.org/documentacion_es/castellano.Persistencia Relacional para Java Idiomático http://www. //desaloja una instancia de Cat en particular sessionFactory.scroll(). 19.get(0). como JBoss TreeCache. //un resultset inmenso while ( cats. La siguiente table muestra qué proveedores son compatibles con qué estrategias de concurrencia. y cada vez que se obtenga un objeto usando load().evictCollection("Cat.manager_lookup_class. o de un rol de colección completo. de toda una clase.kittens"). iterate() o scroll(). Tales cachés sólo pueden ser usados en un entorno JTA. se puede usar el método evict() para quitar objetos y sus colecciones del caché de primer nivel.6. ScrollableResult cats = sess. Si no se quiere que esta sincronización ocurra.evict(cat). Soporte de estrategias de concurrencia de caché Caché Hashtable (no concebida para uso en producción) EHCache OSCache SwarmCache JBoss Cache 1.x JBoss Cache 2 sólo-lectura sí sí sí sí sí sí lecto-escritura no estricta sí sí sí sí sí sí lectoescritura sí sí sí transaccional 19. hay métodos definidos en SessionFactory para desalojar el estado cacheado de una instancia.

se puede especificar una región de caché para una consulta en particular.createQuery("from Blog blog where blog.generate_statistics true hibernate. Si la consulta forzare un refresco de esta región de caché en particular. pero no lee.html CacheMode. no por Hibernate). invoque Query.getSecondLevelCacheStatistics(regionName) .cache. o agregue sus resultados al caché.setCacheable(true). cachea solamente los valores de los identificadores. así que las consultas no se cachean por defecto. optativamente.hibernar. A la mayoría de las consultas no les representa ninguna ventaja el ser cacheadas. y la otra conteniendo la fecha y hora de las actualizaciones más recientes hechas en las tablas "consultables" (org.getStatistics() .getEntries().hibernate.UpdateTimestampsCache). al ser ejecutada. blogger) .Persistencia Relacional para Java Idiomático http://www. Esto sólo esútil para consultas que son ejecutadas frecuentemente. o de una región de cacheo de consultas. CacheMode.setCacheRegion().5.use_query_cache true Esta configuración provoca la creación de dos nuevas regiones de caché: una que contendrá los resultados cacheados de las consultas (org. 172 de 198 17/02/2009 09:25 a. Comprender la performance de las colecciones Ya hemos invertido bastante tiempo en hablar sobre las colecciones.PUT:escribe items en el caché de 2do nivel.evictQueries(). primero hay que habilitarlo: hibernate. Para usar el caché de consutas. pero no escribe en el caché de 2do nivel excepto cuando se items en el caché de 2do nivel. List blogs = sess. habría que invocar Query.cache. Este llamado permite que la consulta.4.org/documentacion_es/castellano. 19. y. Esto es particularmente útil para los casos en donde los datos subyacentes pudieren haber sido actualizados por un proceso separado (por ejemplo. Par habilitar el cacheo. invocando Query.setCacheRegion("frontpages") .cache. y le permite a la aplicación refrescar selectivamente un resultado en particular.use_structured_entries true 19. CacheMode. enfatizaremos un par de asuntos más.setEntity("blogger".setCacheMode(CacheMode. referentes a cómo se comportan las colecciones en tiempo de ejecución.m. actualicen datos.REFRESH). use la API de Statistics: Map cacheEntries = sessionFactory.hibernate. El caché de consultas (query cache) Los resultados de las consultas también pueden ser cacheados. y con los mismos parámetros.StandardQueryCache). .cache. elude los efectos de do hibernate. busque resultados ya existentes.HIBERNATE .use_minimal_puts. forzar a Hibernate a que escriba las entradas de caché en un formato más legible por seres humanos: hibernate.list(). Así que el caché de consultas siempre debería ser usado en conjunción con el caché de 2do nivel. Note que el caché de consultas no cachea el estado de las entidades mismas contenidas en el resultado.REFRESH: escribe Para navegar por ls contenidos del caché de 2do nivel. Necesitará habilitar estadísticas.GET: lee items del caché de 2do nivel.cache. Si se require un control más granular sobre las políticas de expiración de los cachés.blogger = :blogger") . pero lee del caché de 2do nivel. En esta sección.setMaxResults(15) .setCacheable(true) . y los resultados de tipo "value type". Esto es más eficiente que el desalojo de toda una región de cachés via SessionFactory. forzando un refresco del caché de 2 nivel para todos los items leídos de la base de datos.

o actualizar elementos. Las bags son el peor caso. la clasificación recién descripta es aún útil (aún refleja cómo es que Hibernate "localiza" filas individuales de una colección). Note que para una asociación de-uno-a-muchos. debe declararse not-null="true" para todas las columnas). mapas e idbags son los tipos (no inversos) de colección con mejor performance. Los sets son el tipo más común de colección en Hibernate. Taxonomía Hibernate define tres tipos básicos de colección: colección de valores asociaciones de-uno-a-muchos asociaciones de-muchos-a-muchos Esta clasificación distingue entre las varias relaciones de tablas y claves foráneas. la "clave primaria" piede no ser la clave primiaria física de la tabla en la base de datos. Esto puede ser menos eficiente para algunos tipos de elemento de colección. seguidos de cerca por los sets. particularmente cuando se usen identificadores sintéticos. Esto a su vez sugiere la siguiente clasificación: colecciones indexadas sets bags Todas las colecciones indexadas (maps.hibernar. de nuevo. lists. Como una bag permite valores de elemento duplicados y no tiene columnas índice. debemos considerar también la estructura de la clave primaria que es usada por Hibernate para actualizar o borrar colecciones de filas.html 19.Persistencia Relacional para Java Idiomático http://www. así que son muy eficientes de actualizar.5. el UPDATE es manejado por el extremo 'de-muchos-a-uno' de la asociación. Para estas asociaciones. Hibernate nunca efectúa un UPDATE de una fila cuando un elemento se "cambia". Las lists. es muy probable que sea igual de eficiente. concluiríamos que las listas. 19. la base de datos puede no ser capaz de indexar tan eficientemente una clave primaria compleja.org/documentacion_es/castellano. En este caso. Los cambios en un Set siempre requieren INSERT(s) y DELETE(s) de filas individuales.m. Por otra parte. quitar. debería quedar claro que las colecciones indexadas y (normalmente) los sets permiten el desempeño más eficiente en términos de agregar. Esto puede llegar a ser muy ineficiente. para asociaciones de-uno-a-muchos o de-muchos-a-muchos. Sin embargo. (Nota aparte: si se quiere que SchemaExport realmente cree por sí solo la clave primaria de un <set>. Tras observar que los arrays no pueden ser haraganes. Esta consideración. las actualizaciones a la colección 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. no se aplica a las asociaciones de-uno-a-muchos. tienen una clave primaria que consiste en las columnas de <key> e <index>. . arrays). Hibernate resuelve este problema borrando completamente la colección (con un simple DELETE) y recreándola cada vez que algo cambia. los mapeos <idbag> definen una clave sustituta. pero en realidad no nos dice todo lo que necesitamos saber acerca del modelo relacional. maps. no se puede definir ninguna clave primaria.5. son el mejor caso. o grandes campos de texto o binarios. particularmente los elementos compuestos. usualmente vemos que la mayóría de las coleccioes son en realidad asociaciones de-uno-a-muchos con inverse="true". Los sets tienen una clave primaria que consiste en una <key> y columnas elemento. porque la semántica de un set es la más natural para un modelo relacional. 173 de 198 17/02/2009 09:25 a. Podría decirse las colecciones indexadas tienen una ventaja más sobre los sets en las asociaciones de-muchos-a-muchos o colecciones de valores: a causa de la estructura de un Set. así que estas disquisiciones sobre la performance al actualizar colecciones simplemente no son relevantes.1. De hecho. Para comprender cabalmente la estructura relacional y las características de performance. Hibernate no tiene forma de distinguir entre filas duplicadas. idbags y sets son las colecciones más eficientes de actualizar Basándose en la discusión precedente.2.HIBERNATE . Pero incluso en este caso. en un modelo de dominio Hibernate bien diseñado.

y luego insertar 3 filas borrar toda la colección (usando un solo DELETE) e insertar todos los 5 elementos actuales. Esto puede ser muy útil y poderoso a veces. si uno invoca list. uno por uno. 19. etc). Borrado en una pasada Ocasionalmente. Vea el siguiente código para ejemplos mínimos de configuración: // servicio de registro de MBean para una SessionFactory específica Hashtable tb = new Hashtable(). Hibernate no es lo suficientemente astuto como para darse cuenta de que la segunda opción probablemente sea más rápida.HIBERNATE . ObjectName on = new ObjectName("hibernate". Sin embargo. Hibernate no es completamente estúpido. Esto puede volver el código siguiente mucho más rápido: Parent p = (Parent) sess. los borrados en una pasada no son relevantes cuando tratamos con colecciones mapeadas con inverse="true". p. id). o uno para cada una. Supongamos que se agrega un simple elemento a una colección de tamaño 20.add() y Collection. Para una colección con inverse="true" (la relación bidireccional estándar estándar de-uno-a-muchos.addAll() siempre tienen que devolver "true" para una bag o list.setParent(p). borrar elementos de una colección puede volverse extremadamente ineficiente. Afortunadamente. Por supuesto.6.Persistencia Relacional para Java Idiomático http://www. tb.clear(). y listo. Hibernate emite un solo DELETE.hibernar.m. Esto es deseable.flush(). descartando (es decir des-referenciando) la colección original.3. y luego agregamos el nuevo elemento. dejando 2. En este caso.org/documentacion_es/castellano.1. tb). ¡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. Las estadísticas en Hibernate son accesibles por cada SessionFactory. Las bags y lists son las colecciones inversas más eficientes No descarte a las bags para siempre.add(c). Monitorear una SessionFactory Se puede acceder a mediciones de la SessionFactory de dos maneras: La primera opción es llamar a sessionFactory. Hibernate provee un rango muy completo de valores numéricos acerca de sus operaciones internas. por ejemplo.4.6. // nombre del objeto MBean 174 de 198 17/02/2009 09:25 a. "statistics"). así que sabe que no lo tiene que hacer en el caso de una colección nueva y vacía. c. si se habilita el MBean StatisticsService MBean. Hay un caso en particular en el cual las bags (y también las lists) tienen mucha mejor performance que los sets. tb. suponga que quitamos 18 elementos. por ejemplo.5. y devolviendo una colección recientemente instanciada con todos los elementos activos. al contrario de lo que ocurre con un Set.getChildren(). 19. tal comportamiento podría confundir a los triggers de la BD. Se puede habilitar un solo MBean para todas las SessionFactorys.5.put("type".html 19. Hibernate emitirá un comando INSERT y dos DELETEs (a menos que la colección sea una bag).put("sessionFactory". 19. Monitorear la performance Optimizar no es muy útil sin monitoreo y acceso a medidas concretas de performance.(Y probablemente sea mejor así. // ¡no es necesario capturar toda la colección! sess. . podemos forzar este comportamiento (la estrategia número 2) en cualquier momento.getStatistics() y leer o mostrar la Statistics usted mismo. todavía. y luego se quitan 2 elementos.load(Parent. Aquí hay dos maneras de proceder: borrar 18 filas una por una. "myFinancialApp"). Child c = new Child(). Hibernate también puese usar JMX para publicar mediciones.class.

y en algunas plataformas ésta tiene solo un grado de exactitud de 10 segundos.html StatisticsService stats = new StatisticsService(). . CollectionStatistics. en promedio. consultas y cachés como un todo (es decir. double queryCacheHitRatio = queryCacheHitCount / (queryCacheHitCount + queryCacheMissCount).put("sessionFactory". obtenemos y usamos el MBean dorectamente. etc.getStatistics().getEntityStatistics( Cat.HIBERNATE . Tenga en cuenta que el número de milisegundos es sólo una aproximación en Java. asígnesele a hibernate. sf. necesita una consulta.Persistencia Relacional para Java Idiomático http://www.sessionFactory.info(Cat. Por ejemplo.setSessionFactoryJNDIName("my/JNDI/Name") Se puede activar/desactivar el monitoreo para una SessionFactory: en tiempo de configuración. y QueryStatistics para más información. Mediciones detalladas relacionadas con una entidad. EntityStatistics. etc en particular) se usan simples métodos "getter". miss and put ratio). // implementación del MBean stats. Mediciones relacionadas con las entidades.generate_statistics el valor false en tiempo de ejecución.getName() + " changed " + changes + "times" ). long changes = entityStats. usando el método logSummary(). SecondLevelCacheStatistics. colección. El siguiente código muestra un ejemplo simple: Statistics stats = HibernateUtil. Se puede acceder a las mediciones de una entidad. el número de conexiones JDBC obtenidas. Usar hibernateStatsBean. // liga las estadísticas a la SessionFactory server. mediciones globales). se puede chequear la proporción de veces en que se da en el blanco.registerMBean(stats. y el tiempo que. // nombre del objeto MBean StatisticsService stats = new StatisticsService(). consulta o región de caché en particular. double queryCacheHitCount = stats. // Registra el MBean en el servidor A hacer: esto no tiene sentido. 19.org/documentacion_es/castellano. EntityStatistics entityStats = stats. Se puede mandar un sumario al log (a nivel info).class. log. log. las colecciones y las consultas. desde muy básicas. Hibernate está atado a la precisión de la JVM. en tres categorías: Las mediciones relacionadas con el uso de la sesión en general. "all"). Para acceder a las mediciones globales (es decir. En el segundo. "statistics"). no atadas a una entidad.6. on).getQueryCacheHitCount().put("type". tb.setStatisticsEnabled(true) Las estadísticas pueden ser reinicializadas en forma programática. colecciones. tb. debemos dar el nombre JNDI en el cual la fábrica de sesiones está contenida antes de usarla. En el primer caso.getName() ). Por favor refiérase a los JavaDocs de las APIs de Statistics.getInsertCount() + entityStats. on). tb).2. colección o región de caché en particular a través del nombre. usando el método clear().info("Query Hit ratio:" + queryCacheHitRatio).getDeleteCount(). Mediciones Hibernate provee un buen número de mediciones. caché. // implementación del MBean server.hibernar.registerMBean(stats. // registra el Mbean em el servidor // servicio de registro de MBean para todas las SessionFactorys Hashtable tb = new Hashtable(). hasta información especializada que sólo es relevante en ciertos escenarios. 175 de 198 17/02/2009 09:25 a.setSessionFactory(sessionFactory). para las entidades. o se inserta en el caché (en inglés: hit.m.getStatistics().class. no se da en el blanco.getQueryCacheMissCount(). double queryCacheMissCount = stats. Todos los contadores relevantes están descriptos en la API de Statistics. tales como el número de desiones abiertas. y a través de su representación en HQL o en SQL para las consultas. ObjectName on = new ObjectName("hibernate".getUpdateCount() + entityStats.setStatisticsEnabled(true) ohibernateStatsBean.

y un atributo unique (para generar constraints de unicidad en las columnas de la tabla). convirtiéndolo en archivos fuente tipo POJO y archivos de mapeo de Hibernate. consultas y regiones de caché. consultas y regiones con los siguientes métodos: getQueries().HIBERNATE .html Para trabajar en todas las entidades.m. Tareas (tasks) de Ant: Por favor refiérase al paquete Hibernate Tools y a su documentación para más información. Consola: La consola es una bueva vista (view) de Eclipse. así como herramientas de Ant para efectuar ingeniería reversa de base de datos existentes. Se debe especificar el dialecto SQL (Dialect) a través de la propiedad hibernate. y también "de ida" (roundtrip engineering). haciéndolo mucho más versátil que un editor de XML común. retoque sus archivos de mapeo para mejorar el esquema a generar.1. Se puede configurar el largo.1.hibernar. Wizards para desarrollo: Con las herramientas de Hibernate Eclipse se proveen varios "wizards". que soporta auto-compleción y resaltado de sintaxis. Las Herramientas de Hibernate (Hibernate Tools) actualmente incluyen plugins para el entorno ECLIPSE. Generación automática del esquema de base de datos El lenguaje de definición de datos (o DDL por su siglas en inglés) puede ser generado por una utilidad de Hibernate a partir de los archivos de mapeo. 20. y getSecondLevelCacheRegionNames(). También soporta auto-compleción semántica para los nombres de las clases y para los nombres de campos y propiedades. Por otra parte. precisión y escala respectivamente de una columna con estos atributos. y nevegar los resultados directamente en Eclipse. dado que el DDL es altamente dependiente del proveedor de DB. 20. (N. el paquete principal de Hibernate ya trae incluida una herramienta (que puede hasta puede ser usada instantáneamente desde dentro de Hibernate): SchemaExport.del T): se les suele llamar "wizards" o hechiceros a los programas que van nagevando de una pantalla a la otra de manera secuencial. Se puede usar un "wizard" para generar rápidamente archivos de configuración de Hibernate. getEntityNames(). <property name="zip" length="5"/> <property name="balance" precision="12" scale="2"/> Algunas tags también aceptan un atributo not-null (para generar una constraint NOT NULL en las columnas de la tabla). también permite la ejecución de consultas HQL contra la base de datos. Además de una visión jarárquica general de la configuración de la consola. colecciones. También se crean tablas y secuencias para los generadores de identificadores. Guía de las herramientas (Toolset) Hay un conjunto de plugins de Eclipse. . El wizard para ingeniería reversa soporta patrones (templates) configurables a medida. colecciones. para permitirle al usuario realizar una operación compleja guiándolo a través de unas pocas opciones simples por vez. que permiten uar Hibernate para practicar ingeniería reversa.1. El esquema generado incluye las constraints de integridad referencial (claves primarias y foráneas) para las tablas de entidades y colecciones. getCollectionRoleNames(). Editor de mapeo: Un editor de archivos XML de mapeo de Hibernate.dialect cuando se use esta herramienta.org/documentacion_es/castellano. precision y scale.Persistencia Relacional para Java Idiomático http://www. Capítulo 20. también llamada hbm2ddl. tasks de Ant y herramientas de consola. se pued obtener la lista de nombres de entidades. Primero. Retocar el esquema de base de datos Muchos elementos de mapeo de Hibernate definen atributos opcionales llamados length. o se se le puede hacer una ingeniería reversa completa a un esquema de DB existente. <many-to-one name="bar" column="barId" not-null="true"/> 176 de 198 17/02/2009 09:25 a.

customtypes. Se puede agrupar múltiples columnas en en mismo índice.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 (debería asignársele el mismo valor a la propiedad mapeada antes de grabar una nueva instancia de la clase mapeada). <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 foránea.m.. <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. el valor especificado del atributo unique-key no es usado para nombrar la constraint en el DDL generado. <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="bar" type="float"/> </class> Tabla 20.hibernar. <property name="foo" type="integer"> <column name="foo" check="foo > 10"/> </property> <class name="Foo" table="foos" check="bar < 100. Al presente.org/documentacion_es/castellano. .HIBERNATE . simplemente especificando el mismo nombre de índice.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. <property name="balance" type="float"> <column name="balance" sql-type="decimal(13. solamente para agrupar a las columnas en el archivo de mapeo.0"> . <many-to-one name="bar" column="barId" foreign-key="FKFooBar"/> Muvhos elementos de mapeo también aceptan un elemento <column> hijo.Persistencia Relacional para Java Idiomático http://www. Sumario Atributo largo precision scale Valores numéricos numéricos numérico largo de la columna precisión decimal de la columna escala decimal de la columna Interpretación 177 de 198 17/02/2009 09:25 a.1. Esto es particularmente útil al mapear tipos multicolumna: <property name="name" type="my.3)"/> </property> El atributo check permite especificar una constraint de chequeo.

hibernate. <key>.Persistencia Relacional para Java Idiomático http://www. Descripción no imprima el script en la salida estándar sólo elimine (drop) las tablas sólo 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 configuración de Hibernate de una archivo XML lea las propiedades de la BD de un archivo formatee prolijamente el SQL generado en el script agréguele un delimitador de fin de línea al script También se puede incrustar un SchemaExport dentro de la aplicación 178 de 198 17/02/2009 09:25 a.hbm2ddl. .MyNamingStrategy --config=hibernate.SchemaExport options mapping_files Table 20.org/documentacion_es/castellano.xml --properties=hibernate. sea para la tabla o para la columna foreign-key foreign_key_name sql-type default check tipo SQL de la columna expresión SQL expresión SQL El elemento <comment> permite especificar comentarios en el esquema generado. para un elemento de mapeo <one-to-one>.m. 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. Ejecutar la herramienta La herramienta SchemaExport imprime un script DDL en la salida estándar y/o ejecuta los comandos DDL.hibernar.ddl --naming=eg. </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.1.tool..properties --format --delimiter=. cuando esto se soportada.HIBERNATE . o <many-to-many>.2. 20.html Atributo not-null unique index unique-key Valores true|false true|false index_name unique_key_name Interpretación especifica que la columna debería ser no anulable especifica que la columna debería 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 foránea generada para una asociación. <class name="Customer" table="CurCust"> <comment>Current customers only</comment> . Opciones de línea de comandos para SchemaExport Opción --quiet --drop --create --text --output=my_schema. Note que los extremos con inverse="true" serán ignorados por el SchemaExport. <many-to-one>.2. java -cp hibernate_classpaths org.cfg..

5. SchemaUpdate Command Line Options Opción --quiet --text --naming=eg.username hibernate.connection.connection.tool.sql"> <fileset dir="src"> <include name="**/*.3.1.hbm. true).hibernate..html Configuration cfg = .SchemaExportTask" classpathr <schemaexport properties="hibernate.connection.dialect Descripción clase del driver jdbc URL jdbc usuario de la base de datos database user clave del usuario dialecto 20.4.HIBERNATE .properties en un archivo nombrado.hbm2ddl. Note que SchemaUpdate depende grandemente de la API de metadatos de JDBC. . Actualizaciones incrementales del esquema de base de datos La herramienta SchemaUpdate actualizará un esquema de base de datos existente con cambios "incrementales".4.1.hbm2ddl.hibernate. Porpiedades de conexión de SchemaExport Nombre de la propiedad hibernate.url hibernate.m. new SchemaExport(cfg). java -cp hibernate_classpaths org. Usar Ant Se puede llamar al SchemaExport desde un script de Ant <target name="schemaexport"> <taskdef name="schemaexport" classname="org.properties" quiet="no" text="no" drop="no" delimiter=".Persistencia Relacional para Java Idiomático http://www...connection." output="schema-export. 20.tool.driver_class hibernate.SchemaUpdate options mapping_files Table 20.org/documentacion_es/castellano.MyNamingStrategy Descripción no imprima el script en la salida estándar no exporte el script a la base de datos seleccione una NamingStrategy 179 de 198 17/02/2009 09:25 a.hibernar.3.1. así que no funcionará con todos los drivers de JDBC. Propiedades Se puede especificar propiedades de base de datos: como propiedades de sistema con -D<propiedad> en hibernate.create(false.xml"/> </fileset> </schemaexport> </target> 20. con --properties Las propiedades que se necesitan son: Tabla 20.password hibernate..

hbm.xml"/> </fileset> </schemavalidator> </target> Capítulo 21. Ejemplo: Padre/Hijo 180 de 198 17/02/2009 09:25 a.hibernar. new SchemaUpdate(cfg).validate().MyNamingStrategy --properties=hibernate.xml"/> </fileset> </schemaupdate> </target> 20..m.execute(false).SchemaValidator options mapping_files Tabla 20.tool.. 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. new SchemaValidator(cfg)... java -cp hibernate_classpaths org.SchemaUpdateTask" classpathr <schemaupdate properties="hibernate.7.Persistencia Relacional para Java Idiomático http://www. Note que el SchemaValidator depende grandemente de la API de metadatos de JDB.hibernate.hbm2ddl. Opciones de línea de comando para SchemaValidator Opción --naming=eg.xml Se puede incrustar un SchemaUpdate en la aplicación Configuration cfg = .hibernate.tool. Esta herramienta es extremadamente útil para tests.1. 20..properties --config=hibernate.hbm2ddl. Validación del esquema de base de datos La herramienta SchemaValidator validará si el esquema de BD existente "corresponde" con los archivos de mapeo. 20.5.xml Se puede incrustar un archivo SchemaValidator en la aplicación Configuration cfg = . Usar Ant para la validación 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.org/documentacion_es/castellano. así que no funcionará con todos los drivers JDBC.html Opción --properties=hibernate.cfg.8.xml Descripción selecciona una NamingStrategy lee las propiedades de base de datos de una archivo especifica un archivo .cfg.hbm2ddl.properties"> <fileset dir="src"> <include name="**/*.SchemaValidatorTask" clas <schemavalidator properties="hibernate.cfg.6.1...hibernate.xml Descripción lea las propiedades de base de datos de un archivo especifique un archivo .properties" quiet="no"> <fileset dir="src"> <include name="**/*.hbm.cfg.tool.properties --config=hibernate.1..HIBERNATE . .

2. Esto es muy apropiado para todos los casos. Ahora bien.getChildren(). nunca de las entidades contenidas. el abordaje más conveniente. ocurre que la semántica por defecto de una asociación de-uno-a-muchos (en Hibernate). session. "parent" y "child" respectivamente). el número de versión del dueño de la colección se incrementa. En cambio.flush(). Si un objeto quitado de una colección es una instancia de un "value type" (es decir. dicho objeto dejará de ser persistente y su estado será completamente borrado de la base de datos.org/documentacion_es/castellano..Persistencia Relacional para Java Idiomático http://www.add(c).hibernar.. ¡No es nada difícil! 21. Por varias razones. <set name="children"> <key column="parent_id"/> <one-to-many class="Child"/> </set> If we were to execute the following code Parent p = .m. y quitársela borra dicho vínculo.. ¡Esta distinción es crucial! Y tiene las siguientes consecuencias: Cuando quitamos/agregamos un objeto de una colección. (El enfoque alternativo es declarar el Hijo como un elemento compuesto ( <composite-element>). Por otra parte. Este comportamiento es completamente consistente: ¡un cambio en el estado interno de una entidad no debería causar que la entidad asociada se esfume! Del mismo modo.HIBERNATE . es modelar una relación del tipo padre/hijo (en inglés. de-uno-a-muchos bidireccional Supongamos que se empieza con una simple asociación de-uno-a-muchos de padre a hijo.1. el comportamiento por defecto es que. session. agregarle una entidad a una colección no provoca por defecto que la entidad se vuelva persitente. que a la semántica del mapeo de un elemento compuesto. si es una entidad lo que se quita de una colección (en una asociación de-uno-a-muchos o de-muchosa-muchos). es modelar tanto Padre como Hijo como clases de entidad. de un elemento compuesto). Del mismo modo. ésta no será borrada por defecto. . Nota sobre las colecciones Las colecciones de Hibernate se consideran como una parte lógica de la entidad que las posee. simplemente crea un vínculo entre las dos entidades. Child c = new Child().. con una asociación de-uno-a-muchos (<one-to-many>) del Padre al Hijo. Explicaremos cómo usar una asociación 'de-uno-a-muchos bidireccional con propagación en cascada' para modelar una relación padre/hijo eficiente y elegantemente.. agregarle una instancia de "value type" a la colección causará que su estado se vuelva inmediatamente persistente.html Una de las primeras cosas que los nuevos usuarios tratan de hacer con Hibernate. es mucho más parecida a la semántica usual de una relación padre/hijo. Hay dos abordajes diferentes para esto. sino que viola cualquier constraint NOT NULL que pudiere haber en la columna parent_id column.save(c). agregarle una entidad a una colección. 21. Podemos areglar la violación de la constraint de nulabilidad especificando not-null="true" en el mapeo de la colección: <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. Hibernate emitirá los siguientes comandos SQL: un INSERT para crear el registro para c un UPDATE para crear el vínculo de p a c Esto es no solamente ineficiente. especialmente para usuarios nuevos. p. excepto para el caso en que la vida de un hijo dependa del ciclo de vida del padre.

3. session.html De todos modos. Lo siguiente borra a p y a todos sus hijos de la base de datos: Parent p = (Parent) session. <set name="children" inverse="true"> <key column="parent_id"/> <one-to-many class="Child"/> </set> El código siguiente sería usado para agregar un nuevo Child: Parent p = (Parent) session. session. } y ahora.addChild(c). session.add(c).load(Parent. sólo se emite un comando INSERT! Para afinar las cosas un poco más.HIBERNATE . podríamos crear un método addChild() en la clase Parent. Ciclo de vida de la propagación en cascada El llamado explícito a save() aún es molesto. pid). Ahora que la entidad Child está manejando el estado del vínculo. le indicamos a la colección que no actualice el vínculo ella.save(c). <many-to-one name="parent" column="parent_id" not-null="true"/> (También es necesario agragar la propiedad parent a la clase Child). 182 de 198 17/02/2009 09:25 a. Nos ocuparemos de esto usando la propagación en cascada.flush().hibernar.add(c). ésta no es la solución que se recomienda. children.load(Parent. Para esto se usa el atributo inverse.org/documentacion_es/castellano.save(c).addChild(c). session.class. session. <set name="children" inverse="true" cascade="all"> <key column="parent_id"/> <one-to-many class="Child"/> </set> Esto simplifica el código anterior a Parent p = (Parent) session. pid).load(Parent. ¡Y ahora.getChildren(). .flush(). pid). Child c = new Child().load(Parent. Así que la solución es volver al vínculo que es parte del mapeo del objeto Child. pid). p.flush(). c.flush(). public void addChild(Child c) { c. session. el cófigo para agregar un Child se ve así: Parent p = (Parent) session. En forma similar.m.setParent(p). p. session. La causa subyacente de este comportamiento es que el vínculo (la clave foránea 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.setParent(this). Child c = new Child(). 21.Persistencia Relacional para Java Idiomático http://www.delete(p). no necesitamos iterar a través de los hijos al grabar o borrar un Parent. p.class.class.class. Child c = new Child().

iterator(). parent. . en este caso. y cuáles representan filas ya existentes en la base de datos. o. Desafortunadamente.flush(). Las propagaciones en cascada y unsaved-value Supóngase que cargamos un Parent en una sesión. 183 de 198 17/02/2009 09:25 a. realmente queremos que sea borrado. c. <set name="children" inverse="true" cascade="all-delete-orphan"> <key column="parent_id"/> <one-to-many class="Child"/> </set> Nota: aún cuando el mapeo de la colección especifica inverse="true". En el caso de los mapeos con <composite-element> no existe ninguno de estos problemas. lás propagaciones en cascada sí se procesan iterando a través de los elementos de la colección.getChildren().update(parent). si quitamos un Child de una colección. No basta con invocar setParent(). Child c = (Child) p.m. La mayoría de las aplicaciones Hibernate utilizan el patrón padre/hijo en muchos lugares. Ahora.class. y deseamos persistir dichos cambios en una nueva sesión.next(). borrada o actualizada en cascada. Child c = (Child) p. 21. Conclusión Esto es bastante para digerir de una vez.Persistencia Relacional para Java Idiomático http://www. Entonces.getChildren().HIBERNATE .org/documentacion_es/castellano.flush().5. session.hibernar.load(Parent. e insertará un nuevo hijo (newChild). se debe agregar el atributo "cascade" a la colección. p. ya no es necesario especificar un unsaved-value explícitamente. y puede parecer confuso la primera vez. Hay que borrar al (con delete()) explícitamente al Child. El siguiente código actualizará tanto al padre como al hijo. 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 sesión previa. pid). Hibernate Hibernate usará el identificador y los valores de propiedad de version/timestamp para determinar cuáles de los hijos son nuevos (Vea Sección 10. session. hacemos algunos cambios en la interfaz de usuario. invocando update(). existen dos grandes limitaciones al trabajar con clases de elementos compuestos: un elemento compuesto no puede contener colecciones. Todo esto está muy bien en el caso de un identificador autogenerado. p. en el peor de los casos. un Child no puede realmente existir sin su padre. este código Parent p = (Parent) session. Child newChild = new Child().next(). El Parent contendrá una colección de hijos. para verificar si la fila existe. pero ¿qué pasas con los identificadores asignados. no borrará a c de la base de datos.getChildren().addChild(newChild).iterator(). Asumamos que tanto Parent como Child tienen identificadores generados del tipo Long. Para ello debemos usar cascade="all-delete-orphan".4.remove(c). Hibernate usará o bien las propiedades version/timestamp.load(Parent. session.flush(). En este caso. y ellos mismos sólo pueden ser hijos de una única entidad padre. Parent p = (Parent) session. y como la propagación en cascada para "update" está habilitada.7.class. que tienen exactamente la semántica de una relación padre/hijo. o bien consultará el caché de 2do nivel. //tanto el padre como el hijo fueron cargados en una sesión anterior parent. sólo quitará el vínculo con p (y causará en este caso una violación de constraint NOT NULL).getChildren(). “Detección automática de estado”). pid). Hibernate necesita saber cuáles de los hijos han sido recientemente instanciados. En Hibernate3. Así que si se necesita que una colección sea grabada. En el primer párrafo mencionábamos una alternativa. la base de datos. session. session.remove(c).html Sin embargo.delete(c). o con los identificadores compuestos? Esto es más difícil.setParent(null). Pero en la práctica todo se acomoda y funciona en una forma muy linda.addChild(child). 21.

} public void setDatetime(Calendar calendar) { _datetime = calendar.util. } public void setId(Long long1) { _id = long1. private String _name. public class BlogItem { private Long _id.List. private List _items. private String _title. } public void setName(String string) { _name = string. . import java. private Blog _blog. } public Long getId() { return _id.Persistencia Relacional para Java Idiomático http://www. import java. y un item publicado en el weblog. 184 de 198 17/02/2009 09:25 a. } public void setText(String string) { _text = string.1. import java.HIBERNATE . pero utulizaremos una bag ordenada.DateFormat. private String _text. private Calendar _datetime. public class Blog { private Long _id. } public void setBlog(Blog blog) { _blog = blog. public Blog getBlog() { return _blog. public Long getId() { return _id.Calendar. } public String getTitle() { return _title. en lugar de un set.text. } public void setId(Long long1) { _id = long1.org/documentacion_es/castellano.util.html Capítulo 22. } } package eg. Ejemplo: la aplicación Weblog 22. } public Calendar getDatetime() { return _datetime. package eg.m. } public String getName() { return _name. } public void setItems(List list) { _items = list. } public String getText() { return _text.hibernar. Tienen que ser modeladas según una relación padre/hijo estándar. Clases persistentes Las clases pesistentes representan: un weblog (bitácora de web). } public List getItems() { return _items.

List.0//EN" "http://hibernate.Calendar.org/documentacion_es/castellano. import import import import java.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. java.util.html } public void setTitle(String string) { _title = string.Query.net/hibernate-mapping-3. . package eg.hibernate.sourceforge. <?xml version="1.0.util. import org.net/hibernate-mapping-3. usando Hibernate.util.Iterator. java.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.hibernar. java. import org. 185 de 198 17/02/2009 09:25 a. Código Hibernate La clase siguiente demuestra algunas de las cosas que se puede hacer con estas clases. } } 22.Persistencia Relacional para Java Idiomático http://www.2.ArrayList.0//EN" "http://hibernate.HibernateException.sourceforge.hibernate.m.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.3. Mapeos de Hibernate Los mapeos de XML deberían resultar bastante sencillos.util.0.HIBERNATE .

addClass(Blog.addClass(BlogItem.hibernate. tx.beginTransaction(). 186 de 198 17/02/2009 09:25 a.hibernate. item.getInstance() ).add(item). String text) throws HibernateException BlogItem item = new BlogItem().html import import import import import org. item.cfg.persist(blog).update(blog).m.hbm2ddl. true).rollback(). org.commit().Session. session.setItems( new ArrayList() ).commit().beginTransaction().addClass(Blog.setTitle(title). public void configure() throws HibernateException { _sessions = new Configuration() .setBlog(blog). session.close(). String text) throws HibernateExceptio BlogItem item = new BlogItem().hibernate.addClass(BlogItem.hibernate.setDatetime( Calendar.SessionFactory.hibernate.Transaction.class) . blog. throw he. Session session = _sessions. } return blog.setName(name). String title. } public void exportTables() throws HibernateException { Configuration cfg = new Configuration() . } public BlogItem createBlogItem(Long blogid.openSession(). org. blog. } return item. throw he.SchemaExport. item.class) . try { tx = session.hibernar. Session session = _sessions. Transaction tx = null. } public Blog createBlog(String name) throws HibernateException { Blog blog = new Blog().setDatetime( Calendar. } catch (HibernateException he) { if (tx!=null) tx.Persistencia Relacional para Java Idiomático http://www. item.setTitle(title). . } finally { session. new SchemaExport(cfg). item.class) . blog.getItems(). item.buildSessionFactory(). public class BlogMain { private SessionFactory _sessions.setText(text). String title.HIBERNATE .org/documentacion_es/castellano.create(true.openSession(). } finally { session.setText(text).class). org. } public BlogItem createBlogItem(Blog blog. org. try { tx = session.tool.rollback().Configuration. Transaction tx = null. item.getInstance() ).close(). tx. } catch (HibernateException he) { if (tx!=null) tx.

setBlog(blog). session.commit(). Transaction tx = null.class. try { tx = session. throw he. blog. } finally { session. item. } catch (HibernateException he) { if (tx!=null) tx.class. } 187 de 198 17/02/2009 09:25 a. item.hibernar. } public void updateBlogItem(BlogItem item. BlogItem item = (BlogItem) session. throw he.load(Blog.list().name.name.commit().rollback().beginTransaction(). } return item.close().beginTransaction().load(BlogItem.HIBERNATE .id " + "order by max(blogItem. . throw he.createQuery( "select blog. blog.beginTransaction().setText(text).setText(text). } catch (HibernateException he) { if (tx!=null) tx.Persistencia Relacional para Java Idiomático http://www. } } public List listAllBlogNamesAndItemCounts(int max) throws HibernateException { Session session = _sessions. Query q = session. result = q.openSession().openSession().m. blogid). Transaction tx = null. count(blogItem) " + "from Blog as blog " + "left outer join blog. try { tx = session. Transaction tx = null. Session session = _sessions. } finally { session.commit(). tx. throw he.getItems(). tx. tx. } finally { session.close().rollback(). } catch (HibernateException he) { if (tx!=null) tx.rollback(). } catch (HibernateException he) { if (tx!=null) tx. itemid).setMaxResults(max).id. tx.items as blogItem " + "group by blog.org/documentacion_es/castellano. q. List result = null.close(). blog. Blog blog = (Blog) session.rollback(). String text) throws HibernateException { Session session = _sessions.commit().beginTransaction(). } } public void updateBlogItem(Long itemid.openSession().add(item).update(item). try { tx = session.openSession(). String text) throws HibernateException { item.datetime)" ). Transaction tx = null.html Session session = _sessions. try { tx = session.

list().HIBERNATE .html finally { session. try { tx = session. Empleador/Empleado El modelo siguiente de la relación entre empleador y empleado (Employer y Employee) usa una verdadera clase de entidad. } return result. Transaction tx = null. cal).datetime > :minDate" ).getInstance().close().1.uniqueResult(). Employment (empleo) para representar la asociacón. } catch (HibernateException he) { if (tx!=null) tx. Ejemplo: Mapeos varios Estos capítulos exponen algunos mapeos de asociación más complejos.commit(). q. Query q = session.commit().hibernar. } public Blog getBlogAndAllItems(Long blogid) throws HibernateException { Session session = _sessions.beginTransaction().MONTH.close().beginTransaction(). } finally { session.id = :blogid" ).setCalendar("minDate". tx.rollback(). } finally { session. Calendar cal = Calendar. List result = null.m. throw he. false).createQuery( "from Blog as blog " + "inner join blog. } } Capítulo 23. } public List listBlogsAndRecentItems() throws HibernateException { Session session = _sessions. try { tx = session.items " + "where blog.Persistencia Relacional para Java Idiomático http://www. cal. result = q. } return blog.items as blogItem " + "where blogItem.roll(Calendar. 23.openSession(). Esto se hace porque puede haber másde un período de empleo para las mismas dos partes involucradas.setParameter("blogid". Para modelar valores monetarios y nombres de empleados se usan componentes. Blog blog = null. . q. blogid). blog = (Blog) q.close(). 188 de 198 17/02/2009 09:25 a. Query q = session. } return result.openSession().org/documentacion_es/castellano.rollback(). tx. } catch (HibernateException he) { if (tx!=null) tx.createQuery( "from Blog as blog " + "left outer join fetch blog. throw he. Transaction tx = null.

. 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.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.org/documentacion_es/castellano.Persistencia Relacional para Java Idiomático http://www.HIBERNATE .m. create table employers ( 189 de 198 17/02/2009 09:25 a.hibernar.

name VARCHAR(255). end_date TIMESTAMP. Author y Person respectivamente).org/documentacion_es/castellano. primary key (id) ) create table employees ( id BIGINT not null.HIBERNATE . Otra posibilidad sería hacer que Author extendiere Person. 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. start_date TIMESTAMP. . autor y persona (Work. employee_id BIGINT not null. hourly_rate NUMERIC(12. Representamos la relación entre Work y Author como un asociación de-muchos-a-muchos.2. primary key (id) ) create table employment_periods ( id BIGINT not null. 2).hibernar.Persistencia Relacional para Java Idiomático http://www. taxfileNumber VARCHAR(255). 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. lastName VARCHAR(255). employer_id BIGINT not null. initial CHAR(1). Autor/Obra Considérese el modelo siguiente de la relación entre obra. Elegimos representar la asociación entre Author y Person como de-uno-a-uno. currency VARCHAR(12).html id BIGINT not null. firstName VARCHAR(255).m.

autores y personas respectivamente. text INTEGER.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.HIBERNATE . create table works ( id BIGINT not null generated by default as identity.m. tal cual es generado por SchemaExport. author_work es una tabla de asociación que vincula a los autores con sus obras. primary key (id) ) alter table authors add constraint authorsFK0 foreign key (id) references persons 191 de 198 17/02/2009 09:25 a. author_id) ) create table authors ( id BIGINT not null generated by default as identity.hibernar. Aquí está el esquema de tablas. works.org/documentacion_es/castellano. primary key (work_id. primary key (id) ) create table author_work ( author_id BIGINT not null. type CHAR(1) not null. genre VARCHAR(255). tempo FLOAT. authors y persons contienen las obras. alias VARCHAR(255). title VARCHAR(255). primary key (id) ) create table persons ( id BIGINT not null generated by default as identity.Persistencia Relacional para Java Idiomático http://www. . name VARCHAR(255).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"> <!-. work_id BIGINT not null.

LineItem y Product respectivamente). 192 de 198 17/02/2009 09:25 a. Hay una asociación de-uno-a-muchos entre Customer y Order. pero ¿cómo deberíamos representar Order / LineItem / Product? Elijo mapear LineItem como una clase de asociación que representa la asociación de-muchos-a-muchos entre Order y Product. line_items también actúa como una tabla de asociación que vincula órdenes con productos.Persistencia Relacional para Java Idiomático http://www. 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.m.3.hibernar. items de las órdenes y productos. orden. orders. órdenes. line_items y products contienen los datos de clientes.org/documentacion_es/castellano. esto se denomina un "elemento compuesto" (composite element). create table customers ( id BIGINT not null generated by default as identity. name VARCHAR(255).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. Cliente/Orden/Producto Ahora consideremos un modelo de las relaciones entre cliente. En Hibernate. ítem (es decir. línea de la orden) y producto (Customer. Order. . respectivamente.HIBERNATE .

html primary key (id) ) create table orders ( id BIGINT not null generated by default as identity. serialNumber VARCHAR(255). Ejemplos misceláneos de asociación Estos ejemplos han sido extraídos todos ellos de la suite de tests de Hibernate. product_id BIGINT.4.1. order_id BIGINT not null.org/documentacion_es/castellano.4. primary key (order_id. line_number) ) create table products ( id BIGINT not null generated by default as identity. 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. Allí pueden encontrarse muchos otros ejemplos útiles. 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.2. quantity INTEGER.m. date TIMESTAMP.HIBERNATE .Persistencia Relacional para Java Idiomático http://www.4. primary key (id) ) create table line_items ( line_number INTEGER not null. . Asociación 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'. '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. 'HOME'. A HACER: revestir esto con palabras 23.hibernar. customer_id BIGINT. Busque en el directorio test de la distribución de Hibernate.

quantity*p.price) from LineItem li.productId = p.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.org/documentacion_es/castellano.hibernar.m.HIBERNATE .quantity) 194 de 198 17/02/2009 09:25 a. Product p where li.Persistencia Relacional para Java Idiomático http://www. .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.customerId = customerId and li.productId and li.

4.Persistencia Relacional para Java Idiomático http://www.4.hibernar. Discriminación 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.org/documentacion_es/castellano. .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.HIBERNATE .html from LineItem li where li.4.m.productId = productId ) </formula> </property> </class> 23.

Esto alienta la reutilización de código y simplifica la reingeniería. Use una clase Direccion para encapsular calle. provincia.Persistencia Relacional para Java Idiomático http://www. barrio.hibernar.4. Recomendamos que estos identificadores sean "sintéticos" (generados. Hibernate hace que las propiedades identificadoras sean opcionales. 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> Capítulo 24. pero existe todo tipo de razones por las cuales habría que usarlos siempre. CodigoPostal.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. y mapéelas usando <component>. Declare propiedades identificadoras en las clases persistentes.m.org/documentacion_es/castellano.HIBERNATE . Prácticas recomendadas Escriba clases con gran nivel de detalle.5. . sin ningún 196 de 198 17/02/2009 09:25 a.

digamos de una biblioteca. Identifique claves naturales para todas las entidades.org/documentacion_es/castellano. . pero no provee los métodos de acceso necesarios para mapearlo como un componente.hibernate. Comprenda el "flush" de sesión De tanto en tanto. particularmente en un entorno de programación en equipo. Ésta es una buena práctica si sus consultas utilizan funciones SQL que no sean estándar de ANSI. Cargue los archivos de mapeo como recursos. Si no puede usar los proveedores de conexiones que ya vienen incluidos.Persistencia Relacional para Java Idiomático http://www. Use una nueva sesión para servir a cada solicitud (request). Esto tiene sentido.HIBERNATE .ConnectionProvider. considere usar objetos desprendidos. Externalizarlas volverá la aplicación más portátil. la sesión sincroniza su estado persistente con la base de datos. De este modo.saveOrUpdate() para sincronizar objetos con la base de datos. Esta estrategia libera al código de la aplicación de implementar transformaciones desde o hacia un tipo Hibernate. Las transacciones de DB tienen que ser lo más cortas posible.connection. use JDBC manual. Pero por favor. Es común usar objetos desprendidos para implementar transacciones de aplicación. Una alternativa. Hibernate le permite a la aplicación manejar sus conexiones JDBC. ¡Nunca use manipulación de cadenas para unir un valor no-constante a una consulta! Mejor aún. considere usar contextos largos de persistencia. En áreas de performance críticas de un sistema. Considere externalizar las cadenas SQL de las consultas. Despliegue los mapeos junto con las clases que mapean. una unidad de trabajo única desde el punto de vista del usuario. En cuellos de botella. usted aún puede aprovechar la estrategia de transacciones y el proveedor de conexiones subyacente.merge() o Session.hibernar. y mapéelas usando <natural-id>. Use Session. Sin embargo. Considere usar un tipo a medida. Identifique claves naturales. considere usar parámetros nombrados en las consultas.eg. No maneje sus propias conexiones JDBC.xml. Use variables de vínculo. Suponga que tiene un tipo Java. puede valer la pena abrir una sesión y usar esa conexión JDBC. espere hasta estar seguro de que algo constituye un cuello de botella.hbm. 197 de 198 17/02/2009 09:25 a.Foo en el archivo com/eg/Foo. Mapee com. Como en JDBC. siempre reemplace valores no constantes con "?". A veces se puede disminuir la cantidad de "flush" innecesarios inhabilitando el "flushing" automático. En una arquitectura de tres capas. considere proveer su propia implementación de org. La performance se resentirá si este proceso ocurre demasiado seguido. Una "transacción de aplicación" puede extenderse por varios ciclos solicitud/respuesta del cliente. para que la aplicación sea escalable. Cuando se usa una arquitectura de servlet/session bean. Implemente equals() y hashCode() para comparar las propiedades que componen la clave natural.html significado de negcocios).hibernate. No use un único documento de mapeo monolítico.UserType. a veces es necesario implementar transacciones "de aplicación" de largo aliento. que necesita ser persistido. se pueden pasar objetos persistentes cargados en el session bean desde y hacia la capa de servlets/JSP. En una arquitectura de dos capas. pero esto debe considerarse como un últmo recurso.m. Ubique cada mapeo de clase en su propio archivo. o incluso cambiando el orden de las consultas u otras operaciones dentro de una transacción en particular. Y no asuma que JDBC es necesariamente más rápida. algunos tipos de operación podrían beneficiarse al usar JDBC directamente. Si necesita utilizar JDBC directamente. Usted debería considerar implementar org.

Como corolario de esto. Hay que tener cuidado al usar cualquier otro estilo de asociación. para un caso de uso en particular. Se puede hacer incluso que algunas clases sean persistidas por JDBC escrita a mano. Use proxies y colecciones haraganas para la mayoría de las asociaciones a clases que no es probable que sean retenidas en el caché de 2do nivel.hibernar. Esto no es una limitación de Hibernate. Cuando ocurra una excepción. sortear el problema de que los entity beans no son serializables. Combine los partrones DAO y Sesión Thread Local.Persistencia Relacional para Java Idiomático http://www. Considere abstraer su lógica de negocios. Hibernate no puede garantizar que el estado en memoria represente correctamente el estado persistente. Los casos de uso bien definidos. a menos que se esté dispuesto a mantener la sesión abierta a través de la capa de presentación. Esto una práctica necesaria más que una "práctica recomendada". use una consulta con left join fetch.html extremadamente apropiada en arquitecturas de dos capas. sino un requerimiento fundamental para un acceso seguro a datos transaccionales. invoque un rollback de la transacción. Nunca comparta una misma sesión a través de más de una "transacción de aplicación" o estará trabajando con datos rancios. casi todas las asociaciones deben ser navegables por consultas en ambas direcciones. reconectándose al comenzar la solicitud siguiente. en donde exista una probabilidad extremadamante alta de ubicarla en el caché. es mantener un único contacto de persistencia abierto (una sesión) para todo el ciclo de vida de la "transacción de aplicación". y asociadas a Hibernate por medio de un UserType. En ese caso. Use la captura ansiosa (eager fetching) con mesura. sea apropiado usar una captura por join. y cierre la sesión. no use Session. Para asociaciones a clases cacheadas. Prefiera las asociaciones bidireccionales.org/documentacion_es/castellano. use el patrón open session in view. los DTOs tienen un doble propósito: uno. y preguntarse si es verdaderamente necesario. o una fase de ensamble (assembly phase) disciplinada para evitar problemas con datos no capturados. Las asociaciones unidireccionales son más difíciles de consultar. es mucho mejor usar dos asociaciones de-uno-a-muchos a una clase de vínculo intermedia. inhabilite explícitamente la captura haragana usando lazy="false". que involucren verdaderas asociaciones de-muchos-a-muchos. y simplemente desconectarse de la conexión JDBC al final de cada slicitud. En aplicaciones grandes. 198 de 198 17/02/2009 09:25 a.HIBERNATE .load() para determinar si una instancia con un identificador dado existe en la base de datos. No trate las excepciones como si fueran recuperables. Oculte el código (Hibernate) de acceso a datos detrás de una interfaz. ¡no es adecuado para una aplicación con 5 tablas!) No use mapeos de asociación exóticos.m. Hibernate libera al programador de la tediosa tarea de escribir objetos de transferencia de datos (DTO por sus siglas en inglés). creemos que la mayoría de las asociaciones son de-uno-a-muchos y de-uno-a-uno. use Session. Si no lo hace. son raros. (Este consejo se aplica sólo a aplicaciones "lo suficientemente largas". que implícitamente 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. separándola de Hibernate. Hibernate elimina el primer propósito. el otro. En general se necesita que la "tabla de vínculo" almacene información adicional. . pero aún se necesita una fase de ensamble (imagínese a los métodos de negocio como si tuvieran un estricto contrato con la capa de presentación acerca de qué datos hay disponibles en los objetos desprendidos). En lugar de eso. antes de que el control le sea devuelto a la capa de presentación. En una arquitectura EJB tradicional. De hecho. Prefiera la captura haragana (lazy fetching) para las asociaciones. Cuando.get() o una consulta.

Sign up to vote on this title
UsefulNot useful