Sie sind auf Seite 1von 248

10/11/13

Tutoriales de Programacion Java: HIbernate - Parte 1: Persistiendo Objetos Simples usando Mapeos en XML
Compartir

14

Ms

Siguiente blog

Tutoriales de Programacion Java


Blog dedicado a temas de programacin actuales usando el lenguaje de programacin Java y las ltimas versiones de sus APIs y Herramientas.
Pgina principal

Pgina de Concursos

Tutoriales UPAO 2010

Presentaciones Capacitacin

VIERNES, 1 DE MAYO DE 2009

HIbernate - Parte 1: Persistiendo Objetos Simples usando Mapeos en XML

DONACIONES

En la mayora de las aplicaciones empresariales, si no es que en todas, una parte muy importante es el almacenamiento de datos de
forma que estos datos puedan sobrevivir ms all del tiempo que nuestra aplicacin est encendida (ya sea en una aplicacin standalone
o en una aplicacin web).
El almacn de datos ms comn son las bases de datos relacionales. La naturaleza de estas bases hace que no sea tan fcil usarlas en
el almacenamiento de datos en aplicaciones orientadas a objetos (por las diferencias entre el modelo de datos de objetos y el modelo de
datos relacionales), ya que para guardar un objeto debemos extraer cada una de sus propiedades que queremos persistir y armar con
ellos una sentencia INSERT de SQL. De la misma forma, cuando queremos recuperar los datos de un objeto, debemos usar una
sentencia SELECTde SQLy despus extraer el valor de cada una de las columnas recuperadas y llenar as nuestro objeto.
Esto puede no parecer un problema en aplicaciones pequeas, pero cuando comenzamos a tener muchos objetos que debemos guardar
se vuelve algo muy pesado y engorroso, adems de que consume mucho de nuestro tiempo que podramos dedicar a mejorar la lgica de
la aplicacin, o a realizar pruebas de la misma.
Esto se hizo de esta manera durante muchos aos, hasta que comenzaron a surgir las soluciones de Mapeo Objeto/Relacional (ORM
por sus siglas en ingls). El mapeo objeto/relacional se refiere a una tcnica de mapear representaciones de datos de un modelo de
objetos a un modelo de datos relacionales con un esquema basado en SQL.
Hibernate, como la definen sus autores, es una herramienta de mapeo objeto/relacional para ambientes Java. Adems no solo se
encarga del mapeo de clases Java a tablas de la base de datos (y de regreso), sino que tambin maneja los queries y recuperacin de
datos, lo que puede reducir de forma significativa el tiempo de desarrollo que de otra forma gastaramos manejando los datos de forma
manual con SQLy JDBC, encargndose de esta forma de alrededor del 95% de las tareas comunes relacionadas con la persistencia de
datos, manejando todos los problemas relativos con la base de datos particular con la que estemos trabajando, de forma transparente
para nosotros como desarrolladores. Entonces, si cambiamos el manejador de base de datos no ser necesario que modifiquemos todo el
SQLque ya tenamos para adaptarse al SQLque maneja la nueva base de datos. Solo ser necesario modificar una lnea en un archivo de
configuracin de Hibernate, y este se encargar del resto.

JAVA TUTORIALES EN FACEBOOK

Java Tutoriales
Me gusta

Java Tutoriales

Amigo programador,
ests todo el da pica
cdigo, escucha esta
recomendaciones sl
hechas para ti..... q
esto?... Gracias Jorg
Rubira....

No olviden poner la
sentencia where al ha
un borraro en la base
datos..

http://www.youtube.c
watch?v=i_cVJgIz_Cs
A 7895 personas les gusta

En esta serie de tutoriales veremos cmo usar Hibernate para realizar las tareas ms comunes cuando trabajamos con bases de datos.
Existen dos formas de hacer los mapeos en Hibernate, la primera es a travs de archivos de mapeo en XML, que es la forma que
veremos en este primer tutorial. La otra forma es usando anotaciones, que dejaremos para la segunda. As que comencemos.
Para los tutoriales usaremos MySQL 5.1como base de datos. Tambin deben bajar el conector para Java versin 5.1.7.
Creamos una base de datos llamada "pruebahibernate". No se preocupen por crear alguna tabla, ya que haremos que sea el propio
Hibernate el que las genere. Ahora comencemos con nuestra aplicacin.
Lo primero que haremos es crear una biblioteca de NetBeans con los jars bsicos de Hibernate, de esta forma cada vez que queramos
usar Hibernate en un proyecto solo tendremos que agregar esta biblioteca. En realidad no crearemos esta biblioteca desde cero, ya que
NetBeans ya tiene una biblioteca de Hibernate 3.2.5, solo actualizaremos la biblioteca con la ltima versin de Hibernate, la 3.3.1 GA.
As que descargamos la ltima versin del core de Hibernate desde la pgina de descarga de Hibernate.

Plug-in social de Facebook

Una vez que descarguemos y descomprimamos el archivo correspondiente veremos que en la raz hay dos jars de Hibernate:
"hibernate3.jar" y "hibernate-testing.jar". "hibernate3.jar" contiene las clases principales para el uso de Hibernate.
Existen varias clases de soporte que son usadas por Hibernate para su funcionamiento normal. Algunas son opcionales y otras son
requeridas. Afortunadamente estas se encuentran separadas en el mismo archivo que hemos descargado. Las clases obligatorias, que
son las que nos interesan en este caso, se encuentran en el directorio "lib\required".
Bien, entonces para actualizar la biblioteca abrimos el NetBeans y nos dirigimos al men "Tools -> Libraries":

En la ventana que se abre buscamos la biblioteca "Hibernate" y la seleccionamos. Con esto se mostrarn los archivos que la
conforman. Seleccionamos todos los archivos y presionamos el botn "Remove" para eliminarlos de la biblioteca.

www.javatutoriales.com/2009/05/hibernate-parte-1-persistiendo-objetos.html

1/29

10/11/13

Tutoriales de Programacion Java: HIbernate - Parte 1: Persistiendo Objetos Simples usando Mapeos en XML

Una vez eliminados los archivos presionamos el botn "Add JAR/Folder..." para agregar los nuevos archivos:

SEGUIDORES

Agregamos a la biblioteca los siguientes archivos:

Participar en este sitio


Google Friend Connect

hibernate3.jar

Miembros (173) Ms

y del directorio de jars requeridos:


antlr-2.7.6.jar
commons-collections-3.1.jar
dom4j-1.6.1.jar
javassist-3.4.GA.jar
jta-1.1.jar
O sea, casi todos los archivos requeridos. Estamos excluyendo el archivo "slf4j-api-1.5.2.jar" porque si lo incluimos solo, se
lanza una excepcin. Lo que ocurre es que slf4j es una fachada para el logging, o bitcora de la aplicacin (similar a "commonslogging" que estuvimos usando el los tutoriales de JasperReports). Esto significa que podemos usar el framework de logging que
queramos (en teora). Sin embargo en la distribucin de Hibernate no se incluye ningn jar con una clase que implemente dicha fachada,
por lo que debemos bajar uno nosotros mismos.
Podemos hacer dos cosas, la primer es agregar el archivo "slf4j-api-1.5.2.jar" que viene con Hibernate a nuestra biblioteca y el
zip con la versin correspontiente de slf4j. De l extraemos "slf4j-simple-1.5.2.jar" (o el archivo que se ajuste al framework de
logging que estemos usando) y lo incluimos en la biblioteca.
Lo otro que podemos hacer es, aprovechando que ya estamos bajando jars, descargar la ltima versin de slf4j de aqu (actualmente es la
1.5.6) y aprovechar para agregar los archivos "slf4j-api-1.5.6.jar" y "slf4j-simple-1.5.6.jar" a nuestra biblioteca. Yo har
esto ltimo.
Una vez seleccionados estos archivos la biblioteca de Hibernate debe verse as:

Ya eres miembro? Iniciar sesin

ARCHIVO DEL BLOG

2012 (2)
2011 (11)
2010 (10)
2009 (22)
septiembre (2)
agosto (2)
julio (1)
junio (3)
mayo (2)

HIbernate - Parte 2: Persistien


Simples ...

HIbernate - Parte 1: Persistien


Simples ...
abril (5)
marzo (2)
febrero (2)
enero (3)

Presionamos el botn "OK" y nuestra biblioteca ya estar actualizada.


Ahora creamos un nuevo proyecto de NetBeans (men "File -> New Project... -> Java -> Java Application"). Le damos
un nombre y una ubicacin al proyecto y nos aseguramos de que las opciones "Create Main Class" y "Set as Main Project"

www.javatutoriales.com/2009/05/hibernate-parte-1-persistiendo-objetos.html

2/29

10/11/13

Tutoriales de Programacion Java: HIbernate - Parte 1: Persistiendo Objetos Simples usando Mapeos en XML
estn habilitadas. Presionamos el botn "Finish" y veremos aparecer en el editor nuestra clase "Main".
Agregamos la biblioteca de "Hibernate", que creamos hace unos momentos, a nuestro proyecto. Hacemos clic derecho en el nodo
"Libraries" del proyecto. En el men contextual que se abre seleccionamos la opcin "Add Library...":

En la ventana que se abre seleccionamos la biblioteca "Hibernate":

DATOS PERSONALES

Alex

Presionamos el botn "Add Library" para que la biblioteca se agregue a nuestro proyecto. Aprovechamos tambin para agregar el
conector de MySQL. Debemos tener los siguientes archivos en nuestro proyecto:

Programador Java con algunos


experiencia en mltiples poyec
mltiples APIs y herramientas d
compartir experiencias con el
programadores.
Ver todo mi perfil

El siguiente paso es crear una clase cuyas instancias sern almacenadas como fila de una tabla en base de datos. Este tipo de objetos
son llamados "Entidades". Para este ejemplo crearemos una pequea y bsica agenda, as que las entidades sern objetos de la clase
"Contacto".
Los atributos que tendr esta sern un nombre, un correo, y un nmero telefnico. Adems, por regla, necesitamos un atributo que
funcione como identificador para cada una de las entidades.
En este caso he hecho que la clase implementa la interface "java.io.Serializable", esto no es obligatorio pero es una buena
prctica.
La clase "Contacto" queda de la siguiente forma:

www.javatutoriales.com/2009/05/hibernate-parte-1-persistiendo-objetos.html

3/29

10/11/13

Tutoriales de Programacion Java: HIbernate - Parte 1: Persistiendo Objetos Simples usando Mapeos en XML

public class Contacto implements Serializable


{
private long id;
private String nombre;
private String email;
private String telefono;
public Contacto()
{
}
public Contacto(String nombre, String email, String telefono)
{
this.nombre = nombre;
this.email = email;
this.telefono = telefono;
}
public String getEmail()
{
return email;
}
public void setEmail(String email)
{
this.email = email;
}
public long getId()
{
return id;
}
private void setId(long id)
{
this.id = id;
}
public String getNombre()
{
return nombre;
}
public void setNombre(String nombre)
{
this.nombre = nombre;
}
public String getTelefono()
{
return telefono;
}
public void setTelefono(String telefono)
{
this.telefono = telefono;
}
}

La clase "Contacto" usa la c onvencin de nombres JavaBeans para los gettersy settersy visibilidad privada para los atributos.
Este tambin es un diseo recomendado pero no obligatorio. Hibernate puede acceder a los campos o atributos de las entidades
directamente.
El constructor sin argumentos si es obligatorio ya que Hibernate crear instancias de esta clase usando reflexin cuando recupere las
entidades de la base de datos. Este constructor puede ser privado (si es que no quieren permitir que alguien ms lo utilice), pero
usualmente el nivel de acceso ms restrictivo que usaremos es el de paquete (el default), ya que esto hace ms eficiente la creacin de
los objetos.
La propiedad "id" mantendr, como dije antes, un valor nico que identificar a cada una de las instancias de "Contacto". Todas las
clases de entidades persistentes deben tener una propiedad que sirva como identificador si queremos usar el conjunto completo de
funcionalidades que nos ofrece Hibernate (y que veremos a lo largo de esta serie de tutoriales). De todas formas, la mayora de las
aplicaciones necesitan poder distinguir objetos de la misma clase mediante algn tipo de identificador. Usualmente no manipulamos
directamente este identificador (dejamos que sea la base de datos quien lo genere, cuando la entidad sea guardada, y Hibernate quien lo
asigne al objeto), por lo tanto el setterdel "id" es privado (fjense cmo lo he puesto en la clase "Contacto").
Hibernate puede acceder a los campos privatedirectamente, as que no debemos preocuparnos por el hecho de que el identificador no
pudiera ser establecido.
El siguiente paso es crear el archivo de mapeo. Si recuerdan, anteriormente dije que Hibernate es una herramienta de mapeos
Objeto/Relacional, o sea que mapea los atributos de los objetos con las columnas de una tabla de una base de datos relacional.
Tambin dije que hay dos formas de hacerlo: mediante un archivo de mapeo en XML y mediante anotaciones y que en esta ocasin
veramos solo como usar los archivos de mapeo.

www.javatutoriales.com/2009/05/hibernate-parte-1-persistiendo-objetos.html

4/29

10/11/13

Tutoriales de Programacion Java: HIbernate - Parte 1: Persistiendo Objetos Simples usando Mapeos en XML
Crearemos un nuevo paquete que contendr los archivos de mapeo, no es obligatorio tener los archivos de mapeo en un paquete separado
ya que ms adelante indicaremos donde se encuentra cada uno de los archivos, pero nos ayudar a mantener un poco de orden en
nuestro proyecto. Hacemos clic derecho sobre el nodo "Source Packages" del proyecto para mostrar un men contextual. De ese
men seleccionamos la opcin "New -> Java Package..":

Nombramos a este paquete como "mapeos" y presionamos el botn "Finish" para agregar el nuevo paquete.
Ahora creamos un nuevo archivo XML que contendr el mapeo de la clase "Contacto" con la tabla "CONTACTOS" de la base de datos.
Por convencin la extensin de estos archivos es ".hbm.xml" y tiene el mismo nombre de la entidad que est mapeando (aunque eso
tampoco es necesario ya que podemos mapear ms de una clase o entidad dentro del mismo archivo).
Hacemos clic derecho sobre el paquete que acabamos de crear. En el men contextual que se abre seleccionamos la opcin "New ->
XML Document". Si no se muestra est opcin seleccionamos "Other..." y en la ventana que se abre seleccionamos "XML -> XML
Document":

Le damos al archivo el nombre "Contacto.hbm" (el asistente se encargar de agregar de forma automtica el ".xml" al final):

Presionamos el botn "Next >" y se nos preguntar qu tipo de documento queremos crear: solo un documento XML bien formado, un
documento regido por un DTD, o un documento regido por un Schema XML. Aunque el documento de mapeo est regido por un DTD
nosotros elegiremos crear un documento XML bien formado ("Well-formed Document") ya que es ms fcil simplemente pegarlo en el
archivo que se crear que indicar mediante el asistente dnde se encuentra este archivo. Presionamos el botn "Finish" para que se
nos muestre en el editor el nuevo archivo XML, el cual debe verse ms o menos as:

Modificaremos este archivo. Eliminamos todo el contenido del archivo y lo reemplazamos por este:

www.javatutoriales.com/2009/05/hibernate-parte-1-persistiendo-objetos.html

5/29

10/11/13

Tutoriales de Programacion Java: HIbernate - Parte 1: Persistiendo Objetos Simples usando Mapeos en XML

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
</hibernate-mapping>

Teniendo esta declaracin, la cual indica el DTD que se usa para validar el archivo, el IDE nos ayudar a autocompletar las etiquetas y a
asegurarnos que el archivo sea vlido.
El elemento "<hibernate-mapping>" es el nodo raz del documento y, por lo tanto, el resto de los elementos irn entre estas dos
etiquetas.
El elemento con el que indicamos qu clase es la que estamos mapeando es el elemento "<class>" este elemento tiene los atributos
"name" y "table" que nos permiten indicar el nombre completo de la clase y la tabla con la que ser mapeada, respectivamente:

<hibernate-mapping>
<class name="hibernatenormal.Contacto" table="CONTACTOS">
</class>
</hibernate-mapping>

Con esto indicamos que las entidades de la clase "Contacto" sern almacenadas en la tabla "CONTACTOS". Ahora debemos indicar
cul de los elementos de la clase entidad es el identificador. Este identificador ser mapeado con la llave primaria de la tabla, adems
como nosotros no manejaremos el valor del identificador, le indicamos a Hibernate cmo queremos que este valor sea generado (la
estrategia de generacin). Para esto usamos el elemento "<id>", indicando el nombre del atributo de la clase entidad que representa
el identificador (que en este caso tambin se llama "id" ^-^). Opcionalmente en este elemento (como en el resto de los elementos de
mapeo de propiedades) podemos indicar con qu columna queremos que se mapee usando el atributo "column":

<hibernate-mapping>
<class name="hibernatenormal.Contacto" table="CONTACTOS">
<id name="id" column="ID">
<generator class="identity" />
</id>
</class>
</hibernate-mapping>

El elemento "<generator>" es el que nos permite indicar la estrategia de generacin del identificador usando su atributo "class".
Existen varias estrategias que estn explicadas en esta pgina, pero las que usaremos ms frecuentemente son "identity" (con la que
Hibernate se encarga de generar el query necesario para que el nuevo identificador sea igual a el ltimo identificador + 1) y "native" (con
el que se usa la estrategia por default del manejador que estemos utilizando (dialecto)).
Para terminar con el mapeo incluimos las declaraciones para el resto de las propiedades persistentes (las que queremos que sean
almacenadas) de la clase entidad ("nombre", "email", y "telefono") usando el elemento "<property>" en el cual indicamos el
nombre de la propiedad como aparece en la clase entidad y, opcionalmente, el tipo de la propiedad y la columna con la que ser mapeada
usando los atributos "type" y "column" respectivamente:

<hibernate-mapping>
<class name="hibernatenormal.Contacto" table="CONTACTOS">
<id name="id" column="ID">
<generator class="identity" />
</id>
<property name="nombre" type="string" column="NOMBRE" />
<property name="email" />
<property name="telefono" />
</class>
</hibernate-mapping>

El archivo "Contacto.hbm.xml" final debe verse as:

www.javatutoriales.com/2009/05/hibernate-parte-1-persistiendo-objetos.html

6/29

10/11/13

Tutoriales de Programacion Java: HIbernate - Parte 1: Persistiendo Objetos Simples usando Mapeos en XML

Qu ocurre si no indicamos el tipo de la propiedad? En ese caso Hibernate utiliza nuevamente reflexin en nuestra clase para determinar
el tipo del atributo y as elegir el tipo ms adecuado para la columna de la tabla (en caso de que dejemos que Hibernate genere las
tablas).
Qu ocurre si no indicamos el nombre de la columna con la que mapea una propiedad? Esto depende de si Hibernate est generando
las tablas de la base de datos o las hemos generado nosotros mismos. Si es Hibernate quien est generando las tablas no hay problema,
simplemente dar a la columna correspondiente el mismos nombre de la propiedad. Por ejemplo, para la propiedad "email" crear una
columna "email". Sin embargo, si nosotros hemos creado las tablas hay un riesgo potencial de un error. Hibernate buscar en las
consultas una columna con el mismo nombre de la propiedad, pero si hemos usado un nombre distinto, por ejemplo en vez de "email"
hemos llamado a la columna "E_MAIL" ocurrir una excepcin indicando que no se ha encontrado la columna "email", as que en ese
caso debemos tener cuidado de indicar el nombre de las columnas como estn en la base de datos.
Bien, despus de esta breve explicacin podemos proseguir.
Ya que hemos configurado el mapeo de nuestra clase entidad debemos configurar Hibernate. Hibernate est en la capa de nuestra
aplicacin que se conecta a la base de datos (la capa de persistencia), as que necesita informacin de la conexin. La conexin se
hace a travs de un pool de conexiones JDBC que tambin debemos configurar. La distribucin de Hibernate contiene muchos pools de
conexiones JDBC Open Source, como por ejemplo C3P0, pero en esta ocasin usaremos el pool de conexiones que Hibernate trae
integrado.
La configuracin de Hibernate puede hacerse en tres lugares:
Un archivo de propiedades llamado "hibernate.properties".
Un archivo XML llamado "hibernate.cfg.xml".
En cdigo dentro de la misma aplicacin.
En realidad los archivos pueden tener cualquier nombre, pero Hibernate buscar por default los archivos con los nombres que he
mencionado, en una ubicacin predeterminada (la raz del classpath de la aplicacin). Si queremos usar archivos con otros nombres
deberemos especificarlo en el cdigo.
La mayora, por lo que he podido ver en Internet, preferimos usar el archivo XML ya que, entre otras cosas, los IDEs nos ayudan a su
creacin y configuracin gracias a que est regido por un DTD. As que crearemos este archivo en nuestro proyecto. Hacemos clic
derecho en el nodo "Source Packages" del proyecto. En el men contextual que se abre seleccionamos "New -> XML
Document...":

Nombramos al archivo "hibernate.cfg", el IDE se encargar de colocarle la extensin ".xml". Ubicamos el archivo en el directorio
"src":

Con esto lograremos que el archivo quede en la raz del classpath de la aplicacin, tambin conocido como el paquete default.
Presionamos el botn "Next >" y en la pantalla siguiente indicamos que queremos crear un documento XML bien formado (como en el
caso anterior). Presionamos el botn "Finish" para generar el archivo. Si nos fijamos en el archivo generado, este debe encontrarse en
un paquete llamado "<default package>":

www.javatutoriales.com/2009/05/hibernate-parte-1-persistiendo-objetos.html

7/29

10/11/13

Tutoriales de Programacion Java: HIbernate - Parte 1: Persistiendo Objetos Simples usando Mapeos en XML

Borramos todo el contenido del archivo generado y colocamos las siguientes lneas:

<?xml version='1.0' encoding='utf-8'?>


<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
</hibernate-configuration>

El DTD nos ayudar para que el IDE autocomplete las etiquetas.


Como podemos ver, el elemento raz del archivo de configuracin es "<hibernate-configuration>" y, por lo tanto, todos los
elementos los colocaremos entre estas dos etiquetas.
Lo primero que debemos hacer es configurar un "session-factory", que bsicamente es lo que le dice a Hibernate cmo conectarse y
manejar la conexin a la base de datos. Podemos tener ms de un "session-factory" en el archivo de configuracin (por si
quisiramos conectarnos a ms de una base de datos), pero por lo regular solo ponemos uno:

<hibernate-configuration>
<session-factory>
</session-factory>
</hibernate-configuration>

Lo siguiente es configurar la conexin a nuestra base de datos. En este archivo se configuran los parmetros bsicos y tpicos para una
conexin (la URL, nombre de usuario, contrasea, driver, etc.). Cada uno de estos parmetros se configura dentro de una etiqueta "
<property>" (al igual que casi todos los elementos del archivo de configuracin). Como dije antes, usar una base de datos MySQL
para este ejemplo, as que mi configuracin queda de la siguiente forma:

<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="connection.url">jdbc:mysql://localhost/pruebahibernate</property>
<property name="connection.username">usuario</property>
<property name="connection.password">password</property>

Despus, configuramos el pool de conexiones de Hibernate. En este caso como es un ejemplo muy simple, solo nos interesa tener una
conexin en el pool, por lo que colocamos la propiedad "connection.pool_size" con un valor de "1":

<property name="connection.pool_size">1</property>

El siguiente paso es muy importante. Debemos indicar el "dialecto" que usar Hibernate para comunicarse con la base de datos. Este
dialecto es la variante de SQLque usa la base de datos para ejecutar queries. Indicamos el dialecto con el fully qualified class name, o
el
nombre
completo
de
la
clase
incluyendo
el
paquete.
En
el
caso
de
MySQL
5
usamos
"org.hibernate.dialect.MySQL5Dialect". En esta pgina pueden encontrar una lista ms o menos completa de los dialectos
soportados por Hibernate, pero siempre es mejor revisar la documentacin de la versin que estn usando para estar seguros:

<property name="dialect">org.hibernate.dialect.MySQL5Dialect</property>

www.javatutoriales.com/2009/05/hibernate-parte-1-persistiendo-objetos.html

8/29

10/11/13

Tutoriales de Programacion Java: HIbernate - Parte 1: Persistiendo Objetos Simples usando Mapeos en XML
Otras dos propiedades importantes que podemos configurar son: "show_sql" que indica si queremos que las consultas SQL generadas
sean mostradas en el stdout(normalmente la consola), y "hbm2ddl.auto", que indica si queremos que se genere automticamente el
esquema de la base de datos (las tablas). "show_sql" puede tomar valores de "true" o "false", yo lo colocar en "true" (lo que
puede ser bueno mientras estamos en etapas de desarrollo o pruebas, pero querrn cambiar su valor cuando su aplicacin pase a
produccin). Por otro lado "hbm2ddl.auto" puede tomar los valores, segun la documentacin oficial(falta "none"), de "validate",
"update", "create", y "create-drop" (aunque no todos los valores funcionan para todas las bases de datos). Yo los colocar de la
siguiente forma:

<property name="show_sql">true</property>
<property name="hbm2ddl.auto">create-drop</property>

Con el valor "create-drop" hacemos que cada vez que se ejecute la aplicacin Hibernate elimine las tablas de la base de datos y las
vuelva a crear. Para terminar con este archivo de configuracin, debemos indicar dnde se encuentra cada uno de los archivos de mapeo
que hemos creado, usando el elemento "<mapping>". En nuestro caso solo hemos creado un archivo de mapeo, pero debemos colocar
un elemento "<mapping>" por cada uno de los archivos que hayamos creado:

<mapping resource="mapeos/Contacto.hbm.xml"/>

En el elemento "resource" debemos colocar la ubicacin de los archivos de mapeo dentro de la estructura de paquetes de la aplicacin.
El archivo de configuracin "hibernate.cfg.xml" final debe verse as:

<?xml version="1.0" encoding="UTF-8"?>


<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<!-- parametros para la conexion a la base de datos -->
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="connection.url">jdbc:mysql://localhost/pruebahibernate</property>
<property name="connection.username">usuario</property>
<property name="connection.password">password</property>
<!-- Configuracion del pool interno -->
<property name="connection.pool_size">1</property>
<!-- Dialecto de la base de datos -->
<property name="dialect">org.hibernate.dialect.MySQL5Dialect</property>
<!-- Otras propiedades importantes -->
<property name="show_sql">true</property>
<property name="hbm2ddl.auto">create-drop</property>
<!-- Archivos de mapeo -->
<mapping resource="mapeos/Contacto.hbm.xml"/>
</session-factory>
</hibernate-configuration>

Esta es toda la configuracin que debemos hacer. Ahora veremos el cdigo necesario para guardar y recuperar objetos "Contacto" de la
base de datos.
Lo primero que haremos es crear una clase ayudante o de utilidad llamada "HibernateUtil", que se har cargo de inicializar y hacer el
acceso al "org.hibernate.SessionFactory" (el objeto encargado de gestionar las sesiones de conexin a la base de datos que
configuramos en el archivo "hibernate.cfg.xml") ms conveniente.
Dentro de esta clase declaramos un atributo static de tipo "SessionFactory", as nos aseguraremos de que solo existe una

www.javatutoriales.com/2009/05/hibernate-parte-1-persistiendo-objetos.html

9/29

10/11/13

Tutoriales de Programacion Java: HIbernate - Parte 1: Persistiendo Objetos Simples usando Mapeos en XML
instancia en la aplicacin. Adems lo declararemos como final para que la referencia no pueda ser cambiada despus de que la
hayamos asignado.

private static final SessionFactory sessionFactory;

Despus usamos un bloque de inicializacin esttico para inicializar esta variable en el momento en el que la clase sea cargada en la
JVM.
Para realizar esta inicializacin lo primero que se necesita es una instancia de la clase "org.hibernate.cfg.Configuration" que
permite a la aplicacin especificar las propiedades y documentos de mapeo que se usarn (es aqu donde indicamos todo si no queremos
usar un archivo XML o de propiedades). Si usamos el mtodo "configure()" que no recibe parmetros entonces Hibernate busca el
archivo "hibernate.cfg.xml" que creamos anteriormente. Una vez que tenemos este objeto, entonces podemos inicializar la instancia
de "SessionFactory" con su mtodo "buildSessionFactory()". Adems como este proceso puede lanzar
"org.hibernate.HibernateException" (que extiende de "RuntimeException") la cachamos y lanzamos como un
"ExceptionInInitializarError" (que es lo nico que puede lanzarse desde un bloque de inicializacin). El bloque de inicializacin
queda de la siguiente forma:

static
{
try
{
sessionFactory = new Configuration().configure().buildSessionFactory();
} catch (HibernateException he)
{
System.err.println("Ocurri un error en la inicializacin de la SessionFactory: " + he);
throw new ExceptionInInitializerError(he);
}
}

Finalmente creamos un mtodo staticllamado "getSessionFactory()" para recuperar la instancia de la "SessionFactory":

public static SessionFactory getSessionFactory()


{
return sessionFactory;
}

La clase "HibernateUtil" queda de la siguiente forma:

import org.hibernate.HibernateException;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;
public class HibernateUtil
{
private static final SessionFactory sessionFactory;
static
{
try
{
sessionFactory = new Configuration().configure().buildSessionFactory();
} catch (HibernateException he)
{
System.err.println("Ocurri un error en la inicializacin de la SessionFactory: " + he)
;
throw new ExceptionInInitializerError(he);
}
}
public static SessionFactory getSessionFactory()
{
return sessionFactory;
}
}

www.javatutoriales.com/2009/05/hibernate-parte-1-persistiendo-objetos.html

10/29

10/11/13

Tutoriales de Programacion Java: HIbernate - Parte 1: Persistiendo Objetos Simples usando Mapeos en XML

Bien ha llegado el momento, ahora escribiremos una clase DAO (no seguiremos el patrn al pie de la letra, es solo para mostrar cmo
trabajar con Hibernate) que nos permitir realizar operaciones de base de datos.
Creamos una clase llamada "ContactosDAO" y agregamos dos atributos, uno llamado "sesion" de tipo "org.hibernate.Session",
y otro llamado "tx" de tipo "org.hibernate.Transaction".

private Session sesion;


private Transaction tx;

Estos atributos nos servirn para mantener la referencia a la sesin a base de datos, y a la transaccin actual, respectivamente. Ahora
agregaremos dos mtodos de utilidad. El primero nos ayudar a iniciar una sesin y una transaccin en la base de datos. Llamaremos a
este mtodo "iniciaOperacion", y la implementacin es la siguiente:

private void iniciaOperacion() throws HibernateException


{
sesion = HibernateUtil.getSessionFactory().openSession();
tx = sesion.beginTransaction();
}

En el mtodo anterior obtenemos una referencia a "SessionFactory" usando nuestra clase de utilidad "HibernateUtil". Una vez
que tenemos la "SessionFactory" creamos una conexin a la base de datos e iniciamos una nueva sesin con el mtodo
"openSession()". Una vez teniendo la sesin iniciamos una nueva transaccin y obtenemos una referencia a ella con
"beginTransaction()".
Ahora el segundo mtodo de utilidad (llamado "manejaExcepcion") nos ayudar a manejar las cosas en caso de que ocurra una
excepcin. Si esto pasa queremos que la transaccin que estamos ejecutando se deshaga y se relance la excepcin (o podramos lanzar
una propia). Por lo que el mtodo queda as:

private void manejaExcepcion(HibernateException he) throws HibernateException


{
tx.rollback();
throw new HibernateException("Ocurri un error en la capa de acceso a datos", he);
}

Ahora crearemos los mtodos que nos permitirn realizar las tareas de persistencia de una entidad "Contacto", conocidas en lenguaje
de base de datos como CRUD: guardarla, actualizarla, eliminarla, buscar un entidad "Contacto" y obtener todas los contactos que
existen en la base de datos, as que comencemos.
Afortunadamente Hibernate hace que esto sea fcil ya que proporciona mtodos para cada una de estas tareas. Primero veamos como
guardar un objeto "Contacto". Para esto Hibernate proporciona el mtodo "save" en el objeto de tipo "org.hibernate.Session",
que se encarga de generar el "INSERT" apropiado para la entidad que estamos tratando de guardar. El mtodo "guardaContacto"
queda de la siguiente forma:

www.javatutoriales.com/2009/05/hibernate-parte-1-persistiendo-objetos.html

11/29

10/11/13

Tutoriales de Programacion Java: HIbernate - Parte 1: Persistiendo Objetos Simples usando Mapeos en XML

public long guardaContacto(Contacto contacto)


{
long id = 0;
try
{
iniciaOperacion();
id = (Long)sesion.save(contacto);
tx.commit();
}catch(HibernateException he)
{
manejaExcepcion(he);
throw he;
}finally
{
sesion.close();
}
return id;
}

Regresamos el "id" generado al guardar el "Contacto" solo por si queremos usarlo ms adelante en el proceso (como lo haremos
nosotros), o si queremos mostrarle al usuario, por alguna razn, el identificador del "Contacto".
Ahora veremos cmo actualizar un "Contacto". Para eso usamos el mtodo "update" del objeto "sesion" en nuestro mtodo
"actualizaContacto":

public void actualizaContacto(Contacto contacto) throws HibernateException


{
try
{
iniciaOperacion();
sesion.update(contacto);
tx.commit();
}catch (HibernateException he)
{
manejaExcepcion(he);
throw he;
}finally
{
sesion.close();
}
}

Como podemos ver, el mtodo para actualizar es muy similar al mtodo para guardar la entidad. Lo mismo ocurre con el mtodo para
eliminarla, "eliminaContacto":

public void eliminaContacto(Contacto contacto) throws HibernateException


{
try
{
iniciaOperacion();
sesion.delete(contacto);
tx.commit();
} catch (HibernateException he)
{
manejaExcepcion(he);
throw he;
}finally
{
sesion.close();
}
}

Ahora veremos unos mtodos un poco ms interesantes.


Cuando queremos buscar una entidad podemos usar varios criterios. La forma ms fcil es buscar una entidad particular usando su "id".
La clase "org.hibernate.Session" proporciona dos mtodos para esto: "load" y "get". Los dos hacen prcticamente lo mismo: en
base al identificador y tipo de la entidad recuperan la entidad indicada, con la diferencia de que "load" lanza una excepcin en caso de
que la entidad indicada no sea encontrada en la base de datos, mientras que "get" simplemente regresa "null". Pueden usar el que
prefieran, en lo personal me gusta ms "get", as que lo usar para el mtodo "obtenContacto":

www.javatutoriales.com/2009/05/hibernate-parte-1-persistiendo-objetos.html

12/29

10/11/13

Tutoriales de Programacion Java: HIbernate - Parte 1: Persistiendo Objetos Simples usando Mapeos en XML

public Contacto obtenContacto(long idContacto) throws HibernateException


{
Contacto contacto = null;
try
{
iniciaOperacion();
contacto = (Contacto) sesion.get(Contacto.class, idContacto);
} finally
{
sesion.close();
}
return contacto;
}

Finalmente veremos el mtodo "obtenListaContactos" que recupera todos los Contactos que estn guardados en la base de
datos. Como en este caso regresaremos una lista de elementos deberemos crear una consulta. Cuando tenemos que crear una consulta
con JDBC lo hacemos en SQL, sin embargo con Hibernate tenemos varias opciones:
Usar una query en SQLnativo.
Crear una query en HQL(Hibernate Query Language).
Crear una query usando Criteriaque es un API para crear queries de una forma ms "orientada a objetos".
Critera es, a mi parecer, la forma ms fcil de crear las queries. Sin embargo, tambin en mi opinin, HQLes ms poderosa y tenemos
ms control sobre lo que est ocurriendo, as que ser esta forma la que usaremos.
Creando la consulta en HQL Hibernate la transformar al SQL apropiado para la base de datos que estemos usando. La consulta en
realidad es muy simple: indicamos que queremos obtener datos (generar un "SELECT"), en este caso la clausula "SELECT" no es
necesaria (aunque si existe) porque vamos a regresar todos los datos del objeto (podemos indicar solo unos cuantos atributos, eso es
llamado proyeccin, pero se maneja de una forma distinta). Lo que si debemos indicar es de cul clase queremos recuperar las
instancias, por lo que necesitamos la clausula "FROM" y el nombre de la clase (recuerden que en base al nombre de la clase Hibernate
sabr en cul tabla estn almacenadas las entidades). Espero que esta explicacin se haya entendido, se que es un poco enredado, pero
quedar ms claro con el ejemplo:

public List<Contacto> obtenListaContactos() throws HibernateException


{
List<Contacto> listaContactos = null;
try
{
iniciaOperacion();
listaContactos = sesion.createQuery("from Contacto").list();
}finally
{
sesion.close();
}
return listaContactos;
}

Eso es todo, nuestra consulta para recuperar todos los Contactos que tenemos en la base de datos solo debemos usar la clausula "FROM
Contacto". Si quieren una referencia ms amplia de HQL pueden encontrarla en el tutorial sobre HQL.
Bien, eso es todo. La clase "ContactosDAO" queda de la siguiente forma (omitiendo los imports):

public class ContactosDAO


{
private Session sesion;
private Transaction tx;
public long guardaContacto(Contacto contacto) throws HibernateException
{
long id = 0;
try
{
iniciaOperacion();
id = (Long) sesion.save(contacto);
tx.commit();
} catch (HibernateException he)
{
manejaExcepcion(he);
throw he;
} finally

www.javatutoriales.com/2009/05/hibernate-parte-1-persistiendo-objetos.html

13/29

10/11/13

Tutoriales de Programacion Java: HIbernate - Parte 1: Persistiendo Objetos Simples usando Mapeos en XML

} finally
{
sesion.close();
}
return id;
}

public void actualizaContacto(Contacto contacto) throws HibernateException


{
try
{
iniciaOperacion();
sesion.update(contacto);
tx.commit();
} catch (HibernateException he)
{
manejaExcepcion(he);
throw he;
} finally
{
sesion.close();
}
}
public void eliminaContacto(Contacto contacto) throws HibernateException
{
try
{
iniciaOperacion();
sesion.delete(contacto);
tx.commit();
} catch (HibernateException he)
{
manejaExcepcion(he);
throw he;
} finally
{
sesion.close();
}
}
public Contacto obtenContacto(long idContacto) throws HibernateException
{
Contacto contacto = null;
try
{
iniciaOperacion();
contacto = (Contacto) sesion.get(Contacto.class, idContacto);
} finally
{
sesion.close();
}
return contacto;
}
public List<Contacto> obtenListaContactos() throws HibernateException
{
List<Contacto> listaContactos = null;
try
{
iniciaOperacion();
listaContactos = sesion.createQuery("from Contacto").list();
} finally
{
sesion.close();
}
return listaContactos;
}
private void iniciaOperacion() throws HibernateException
{
sesion = HibernateUtil.getSessionFactory().openSession();
tx = sesion.beginTransaction();
}
private void manejaExcepcion(HibernateException he) throws HibernateException
{
tx.rollback();
throw new HibernateException("Ocurri un error en la capa de acceso a datos", he);
}
}

www.javatutoriales.com/2009/05/hibernate-parte-1-persistiendo-objetos.html

14/29

10/11/13

Tutoriales de Programacion Java: HIbernate - Parte 1: Persistiendo Objetos Simples usando Mapeos en XML
Ahora, y para terminar el ejemplo, haremos uso de "ContactosDAO" para crear y recuperar algunas instancias de "Contacto". Creo
que el cdigo es muy claro as que no lo explicar ^-^!. La clase "Main" queda de la siguiente forma:

public class Main


{
public static void main(String[] args)
{
ContactosDAO contactosDAO = new ContactosDAO();
Contacto contactoRecuperado = null;
long idAEliminar = 0;
//Creamos tes instancias de Contacto
Contacto contacto1 = new Contacto("Contacto 1", "contacto1@contacto.com", "12345678");
Contacto contacto2 = new Contacto("Contacto 2", "contacto2@contacto.com", "87654321");
Contacto contacto3 = new Contacto("Contacto 3", "contacto3@contacto.com", "45612378");
//Guardamos las tres instancias, guardamos el id del contacto1 para usarlo posteriormente
idAEliminar = contactosDAO.guardaContacto(contacto1);
contactosDAO.guardaContacto(contacto2);
contactosDAO.guardaContacto(contacto3);
//Modificamos el contacto 2 y lo actualizamos
contacto2.setNombre("Nuevo Contacto 2");
contactosDAO.actualizaContacto(contacto2);
//Recuperamos el contacto1 de la base de datos
contactoRecuperado = contactosDAO.obtenContacto(idAEliminar);
System.out.println("Recuperamos a " + contactoRecuperado.getNombre());
//Eliminamos al contactoRecuperado (que es el contacto3)
contactosDAO.eliminaContacto(contactoRecuperado);
//Obtenemos la lista de contactos que quedan en la base de datos y la mostramos
List<Contacto> listaContactos = contactosDAO.obtenListaContactos();
System.out.println("Hay " + listaContactos.size() + "contactos en la base de datos");
for(Contacto c : listaContactos)
{
System.out.println("-> " + c.getNombre());
}
}
}

En el momento que ejecutemos la aplicacin Hibernate crear la tabla correspondiente en la base de datos (llamada "contactos") y que
tiene los siguientes campos:

Como podemos ver la tabla y los nombres de las columnas se generan en base al archivo de mapeo. En donde hemos colocado los
nombres de las columnas se han usado estos nombres, en donde no lo hemos hecho se han tomado los mismos nombres que el de los
atributos que estamos mapeando.
Si observamos la salida de la consola podemos ver, que en la parte final, se indica esta creacin y adems las consultas que Hibernate

www.javatutoriales.com/2009/05/hibernate-parte-1-persistiendo-objetos.html

15/29

10/11/13

Tutoriales de Programacion Java: HIbernate - Parte 1: Persistiendo Objetos Simples usando Mapeos en XML
ha generado (revueltas con los mensajes que sacamos a consola). He marcado con rojo los mensajes que mandamos a consola para que
sea fcil distinguirlos.

Segun indica la salida en la base de datos solo debemos tener dos entidades, con los nombres "Nuevo Contacto 2" y "Contacto
3". Revisemos la tabla para ver que esto sea correcto:

Como podemos ver, esto es correcto, en la base de datos existen solo los registros indicados, con lo que podemos estar seguros de que
nuestra aplicacin funciona!!! ^-^.
Entonces, vimos que con Hibernate fue muy simple hacer la manipulacin de los datos de una base de datos relacional sin escribir una
sola lnea de SQL. En aplicaciones de tamao mediano a grande esto nos ahorrar mucho tiempo (que normalmente usaramos en escribir
el SQL para query, armar algunas de estas de forma dinmica, pasar los parmetros adecuados, recuperar los mismos de un
ResultSet, entre otras cosas) para mejorar algunos otros aspectos de la aplicacin, como la interfaz grfica, la lgica del negocio, o
realizar ms pruebas. Adems nuestro cdigo es ms simple y por lo tanto fcil de mantener.
Lo nico malo es que ahora tenemos que crear mapeos de las entidades con las tablas de la base de datos en un archivo XLM. Es por
esto que en el siguiente tutorial veremos cmo realizar este mismo ejemplo pero usando anotaciones en vez del archivo de mapeo ^-^.
Espero que esto les haya sido de utilidad. No olviden dejar sus comentarios, dudas, y sugerencias.
Saludos.
Descarga los archivos de este tutorial desde aqu:
Hibernate Archivos de Mapeo

Entradas Relacionadas:
Parte 2: Persistiendo Objetos Simples usando Anotaciones (Metadatos)
Parte 3: Relaciones / Uno a uno
Parte 4: Relaciones / Uno a muchos
Parte 5: Relaciones / Muchos a uno
Parte 6: Relaciones / Muchos a Muchos
Parte 7: HQL Primera Parte
Parte 8: HQL Segunda Parte
Parte 9: Parmetros en HQL
Parte 10: Herencia
Parte 11: Interceptores y Eventos
Publicado por Alex en 10:48

divertido (1)

Reacciones:

interesante (5)

increible (1)

no me gusta (0)

+14 Recomendar esto en Google


Etiquetas: base de datos, hibernate, java

79 comentarios:
Annimo 13 de mayo de 2009 05:17
ok programador java , como siempre excelente tutorial ya lo estoy implementando . . .
Responder

janeth 2 de junio de 2009 07:30


Gracias:
quisiera saber que version de Netbeans utiliza, y como queda el ContactosDAO, el main que no me funcionan.
gracias nuevamente
Responder

Alex

2 de junio de 2009 08:49

Hola Janeth;

www.javatutoriales.com/2009/05/hibernate-parte-1-persistiendo-objetos.html

16/29

10/11/13

Tutoriales de Programacion Java: HIbernate - Parte 2: Persistiendo Objetos Simples usando Anotaciones (metadatos)
Compartir

Ms

Siguiente blog

Tutoriales de Programacion Java


Blog dedicado a temas de programacin actuales usando el lenguaje de programacin Java y las ltimas versiones de sus APIs y Herramientas.
Pgina principal

Pgina de Concursos

Tutoriales UPAO 2010

Presentaciones Capacitacin

MIRCOLES, 13 DE MAYO DE 2009

HIbernate - Parte 2: Persistiendo Objetos Simples usando Anotaciones


(metadatos)

DONACIONES

En el tutorial anterior vimos como crear una pequea aplicacin con Hibernate usando mapeos en archivos XML. Aunque esto es bastante
til (en algunas situaciones) puede ser bastante engorroso, especialmente en aplicaciones muy grandes.
JAVA TUTORIALES EN FACEBOOK

Afortunadamente existe otra forma de realizar estos mapeos, y es usando anotaciones o metadatos, los cuales se agregan directamente
al cdigo fuente y, por lo tanto, es ms fcil estar conscientes de estos datos de mapeos al estar editando el cdigo fuente. Adems
usan muchos valores por default, ya no ser necesario que escribamos toda la informacin para los mapeos.
En esta ocasin mostrar como realizar el mismo ejemplo que en el tutorial anterior, pero haciendo uso de anotaciones en lugar de
archivos de mapeo XML.
Para este ejemplo usaremos MySQL 5.1 como base de datos. Si no la tienen pueden descargarla desde aqu. Tambin deben bajar el
conector para Java versin 5.1.7 desde aqu. Adems usaremos la biblioteca de Hibernate que creamos tambin en el tutorial anterior.
Hibernate proporciona un API especial para trabajar usando anotaciones llamada "Hibernate Annotations" que puede ser
descargada desde aqu. Actualmente la ltima versin es la 3.4.0 GA y es la que usaremos para este tutorial.
Una vez descargado el archivo y descomprimido, veremos que dentro del directorio de "hibernate-annotations" hay un archivo
llamado "hibernate-annotations.jar". Este jar contiene las clases principales de Hibernate annotations. Dentro del directorio
"lib" encontrarn algunos jarsde soporte.
Crearemos una biblioteca que contendr estos archivos para que sea fcil agregarlos cada vez que queramos trabajar con anotaciones de
Hibernate.

Java Tutoriales
Me gusta

Java Tutoriales

Amigo programador,
ests todo el da pica
cdigo, escucha esta
recomendaciones sl
hechas para ti..... q
esto?... Gracias Jorg
Rubira....

No olviden poner la
sentencia where al ha
un borraro en la base
datos..

http://www.youtube.c
watch?v=i_cVJgIz_Cs

Abrimos el NetBeans y vamos al men "Tools -> Libraries":


A 7895 personas les gusta

Plug-in social de Facebook

En la ventana que se abre seleccionamos la opcin "New Library..." con lo que se abre otra ventana. En esta ventana le damos a la
biblioteca el nombre "HibernateAnotaciones" (sin espacios), de tipo "Class Libraries":

www.javatutoriales.com/2009/05/hibernate-parte-2-persistiendo-objetos.html

1/20

10/11/13

Tutoriales de Programacion Java: HIbernate - Parte 2: Persistiendo Objetos Simples usando Anotaciones (metadatos)

Presionamos el botn "OK" y ya tendremos creada nuestra biblioteca, ahora hay que agregar los jars que la conformarn. Presionamos el
botn "Add JAR/Folder" y seleccionamos, del directorio de "hibernate-annotations" los siguientes archivos:

Extend JMS to
.NET
www.CodeMesh.c

hibernate-annotations.jar
y del directorio lib:

Let .NET applications


participate in any JMS
messaging system.

ejb3-persistence.jar
hibernate-commons-annotations.jar
Nuestra biblioteca debe verse as:

Cursos Gratis
INEM
Curso Online
de jquery
Programador
Java

Ahora cada vez que queramos usar hibernate con anotaciones deberemos agregar la biblioteca "Hibernate" (que creamos en el tutorial
anterior) y la nueva biblioteca "HibernateAnotaciones".
Ahora creamos un nuevo proyecto desde el men "File -> New Project... -> Java -> Java Application". Llamamos a la
aplicacin "HibernateAnotaciones" y nos aseguramos que las opciones "Create Main Class" y "Set as Main Project"
estn seleccionadas. Presionamos el botn "Finish" y veremos la clase "Main" en nuestro editor.

Cursos de
Java

SEGUIDORES

Participar en este sitio


Google Friend Connect

Agregamos las bibliotecas de Hibernate a nuestro proyecto. Hacemos clic derecho sobre el nodo "Libraries" del proyecto y
agregamos las dos bibliotecas de Hibernate que creamos ("Hibernate" y "HibernateAnotaciones"), seleccionando la opcin "Add
Library..." del men contextual que se abre. Aprovechamos para agregar el driver de la base de datos, el archivo "mysqlconnector-java-5.1.7-bin.jar" usando la opcin "Add JAR/Folder..." de ese mismo men contextual. Al final el nodo
"Libraries" debe verse as:

Miembros (173) Ms

Ya eres miembro? Iniciar sesin

ARCHIVO DEL BLOG

2012 (2)
2011 (11)
2010 (10)
2009 (22)
septiembre (2)
agosto (2)
julio (1)
junio (3)
mayo (2)

Tambin es buen momento para crear la base de datos "pruebahibernate" si no lo han hecho. Igual que en el tutorial anterior no se
preocupen por crear tablas, ya que ser el propio Hibernate quien lo haga.
Creamos una clase simple que servir como Entidad. De hecho reutilizaremos la clase "Contacto" del tutorial anterior, cuyo cdigo
qued de esta forma:

HIbernate - Parte 2: Persistien


Simples ...

HIbernate - Parte 1: Persistien


Simples ...
abril (5)
marzo (2)
febrero (2)
enero (3)

www.javatutoriales.com/2009/05/hibernate-parte-2-persistiendo-objetos.html

2/20

10/11/13

Tutoriales de Programacion Java: HIbernate - Parte 2: Persistiendo Objetos Simples usando Anotaciones (metadatos)

public class Contacto implements Serializable


{
private long id;
private String nombre;
private String email;
private String telefono;
public Contacto()
{
}
public Contacto(String nombre, String email, String telefono)
{
this.nombre = nombre;
this.email = email;
this.telefono = telefono;
}
public String getEmail()
{
return email;
}
public void setEmail(String email)
{
this.email = email;
}
public long getId()
{
return id;
}
private void setId(long id)
{
this.id = id;
}
public String getNombre()
{
return nombre;
}

DATOS PERSONALES

Alex

Programador Java con algunos


experiencia en mltiples poyec
mltiples APIs y herramientas d
compartir experiencias con el
programadores.
Ver todo mi perfil

public void setNombre(String nombre)


{
this.nombre = nombre;
}
public String getTelefono()
{
return telefono;
}
public void setTelefono(String telefono)
{
this.telefono = telefono;
}
}

En el caso anterior habamos dejado la clase as, y el archivo de mapeo se encargaba del resto. En este caso agregaremos en la clase
las anotaciones para realizar el mapeo.
Antes de comenzar debo decir que en realidad Hibernate no trabaja solo cuando usamos anotaciones. Si recuerdan, cuando creamos la
biblioteca de "HibernateAnotaciones" entre los archivos que agregamos para conformarla se encontraba "ejb3persistence.jar". Este archivo contiene las clases de un Framework llamado "JPA" o "Java Persistence API", la cual es el API
"oficial" de persistencia para aplicaciones Java. Trabaja utilizando lo que se conoce como un "proveedor de persistencia" que es quien
se encarga de hacer el verdadero trabajo con la base de datos. En este caso Hibernate ser el proveedor de persistencia. Las anotaciones
que usaremos si son de JPA. Hibernate tambin proporciona algunas anotaciones, pero son por si queremos agregar funcionalidad extra,
lo cual escapa al objetivo de este tutorial.
No usaremos al 100% JPA ya que no realizaremos la configuracin como debe ser (en un archivo llamado "persistence.xml") sino
que seguiremos usando Hibernate para configurar todo.
Ahora si, pasemos a anotar nuestra clase. La anotacin ms importante es "javax.persistence.Entity", la cual indica que la clase
es una "Entidad", por lo que la anotacin se coloca a nivel de clase.

www.javatutoriales.com/2009/05/hibernate-parte-2-persistiendo-objetos.html

3/20

10/11/13

Tutoriales de Programacion Java: HIbernate - Parte 2: Persistiendo Objetos Simples usando Anotaciones (metadatos)

@Entity
public class Contacto implements Serializable
{
}

Cuando Hibernate genere la tabla para esta entidad lo har en base al nombre de la misma. En este caso crear una tabla llamada
"contacto". Pero, en lo personal, prefiero que los nombres de las tablas estn el plural. As que usar la anotacin
"javax.persistence.Table" para indicar cul ser el nombre de la tabla generada (o si ya tenemos una base de datos creada, cul
es el nombre de la tabla en la que se almacenarn estas entidades):

@Entity
@Table(name="contactos")
public class Contacto implements Serializable
{
}

Despus debemos indicar cul atributo de la clase ser el identificador. Esto lo hacemos con la anotacin "javax.persistence.Id".
Este atributo podemos colocarlo en dos lugares: en el getterdel atributo identificador, o directamente en el atributo.
Cuando colocamos la anotacin en el atributo decimos que se realiza un acceso por "atributo" (field access), o sea que Hibernate
lee y establece los valores directamente de los atributos. Cuando la colocamos en el getterdecimos que se realiza un acceso por
"propiedad" (property access), o sea que Hibernate accesa a los valores mediante los settersy getters. No pueden mezclarse
los tipos de acceso, as que elijan con cuidado. Pueden encontrar un poco ms de informacin acerca de esto aqu (es un tutorial de JPA)
En este caso colocar la anotacin en el atributo:

@Id
private long id;

Podemos
personalizar la
forma en
la
que se
generar el
valor
del identificador
usando la
anotacin
"javax.persistence.GeneratedValue" e indicando la "estrategia" que se usar para generarlo. Existen solo 4 estrategias en JPA
(si usamos las anotaciones de Hibernate podemos usar todos los generadores de Hibernate):
AUTO
IDENTITY
SEQUENCE
TABLE
Las ms usadas son "AUTO" e "IDENTITY". La primera usa la estrategia por default de la base de datos, mientras que la segunda genera
los identificadores en orden (1, 2, 3, etc.). Pueden encontrar ms informacin aqu.

@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private long id;

Esto es todo lo que es necesario hacerle a la clase, el resto de las propiedades que se persistirn sern obtenidas mediante reflexin, la
explicacin es la misma que en el tutorial anterior. Todos los atributos que no estn marcados como "transient" o con la anotacin
"javax.persistence.Transient" sern persistidas.
Si queremos personalizar la columna de la tabla que se generar de un atributo, podemos hacerlo con la anotacin
"javax.persistence.Column". Por ejemplo, yo no quiero que la columna generada del atributo "email" sea "email", sino que sea
"e_mail", por lo que agrego la anotacin de la siguiente forma:

@Column(name="e_mail")
private String email;

Al final la clase "Contacto" queda de la siguiente forma (omitiendo los imports):

www.javatutoriales.com/2009/05/hibernate-parte-2-persistiendo-objetos.html

4/20

10/11/13

Tutoriales de Programacion Java: HIbernate - Parte 2: Persistiendo Objetos Simples usando Anotaciones (metadatos)

@Entity
@Table(name="contactos")
public class Contacto implements Serializable
{
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private long id;
private String nombre;
@Column(name="e_mail")
private String email;
private String telefono;
public Contacto()
{
}
public Contacto(String nombre, String email, String telefono)
{
this.nombre = nombre;
this.email = email;
this.telefono = telefono;
}
public String getEmail()
{
return email;
}
public void setEmail(String email)
{
this.email = email;
}
public long getId()
{
return id;
}
private void setId(long id)
{
this.id = id;
}
public String getNombre()
{
return nombre;
}
public void setNombre(String nombre)
{
this.nombre = nombre;
}
public String getTelefono()
{
return telefono;
}
public void setTelefono(String telefono)
{
this.telefono = telefono;
}
}

Y esto nos ahorrar el tener que crear el archivo de mapeo para esta clase ^-^. Ahora configuraremos Hibernate. Como expliqu
anteriormente: La configuracin de Hibernate puede hacerse en tres lugares:
Un archivo de propiedades llamado "hibernate.properties".
Un archivo XML llamado "hibernate.cfg.xml".
En cdigo dentro de la misma aplicacin.
Yo usar el archivo "hibernate.cfg.xml". As que crearemos este archivo en nuestro proyecto. Hacemos clic derecho en el nodo
"Source Packages" del proyecto. En el men contextual que se abre seleccionamos "New -> XML Document...":

www.javatutoriales.com/2009/05/hibernate-parte-2-persistiendo-objetos.html

5/20

10/11/13

Tutoriales de Programacion Java: HIbernate - Parte 2: Persistiendo Objetos Simples usando Anotaciones (metadatos)

Nombramos al archivo "hibernate.cfg", el IDE se encargar de colocarle la extensin ".xml". Ubicamos el archivo en el directorio
"src":

Con esto lograremos que el archivo quede en la raz del classpath de la aplicacin, tambin conocido como el paquete default.
Presionamos el botn "Next >" y en la pantalla siguiente indicamos que queremos crear un documento XML bien formado (como en el
caso anterior). Presionamos el botn "Finish" para generar el archivo. Si nos fijamos en el archivo generado, este debe encontrarse en
un paquete llamado "<default package>":

Borramos todo el contenido del archivo generado y colocamos las siguientes lneas:

<?xml version='1.0' encoding='utf-8'?>


<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
</hibernate-configuration>

El DTD nos ayudar para que el IDE autocomplete las etiquetas.


Como podemos ver, el elemento raz del archivo de configuracin es "<hibernate-configuration>" y, por lo tanto, todos los
elementos los colocaremos entre estas dos etiquetas.
Lo primero que debemos hacer es configurar un "session-factory", que bsicamente es lo que le dice a Hibernate cmo conectarse y
manejar la conexin a la base de datos. Podemos tener ms de un "session-factory" en el archivo de configuracin (por si
quisiramos conectarnos a ms de una base de datos), pero por lo regular solo ponemos uno:

<hibernate-configuration>
<session-factory>
</session-factory>
</hibernate-configuration>

Lo siguiente es configurar la conexin a nuestra base de datos. En este archivo se configuran los parmetros bsicos y tpicos para una
conexin (la URL, nombre de usuario, contrasea, driver, etc.). Cada uno de estos parmetros se configura dentro de una etiqueta "
<property>" (al igual que casi todos los elementos del archivo de configuracin). Como dije antes, usar una base de datos MySQL
para este ejemplo, as que mi configuracin queda de la siguiente forma:

www.javatutoriales.com/2009/05/hibernate-parte-2-persistiendo-objetos.html

6/20

10/11/13

Tutoriales de Programacion Java: HIbernate - Parte 2: Persistiendo Objetos Simples usando Anotaciones (metadatos)

<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="connection.url">jdbc:mysql://localhost/pruebahibernate</property>
<property name="connection.username">usuario</property>
<property name="connection.password">password</property>

Despus, configuramos el pool de conexiones de Hibernate. En este caso como es un ejemplo muy simple, solo nos interesa tener una
conexin en el pool, por lo que colocamos la propiedad "connection.pool_size" con un valor de "1":

<property name="connection.pool_size">1</property>

*Nota: Este pool de conexiones es solo para efectos de pruebas en desarrollo. Cuando nuestra aplicacin para a produccin se recom ienda usar
un pool de conexiones distinto, com o C3P0.

El siguiente paso es muy importante. Debemos indicar el "dialecto" que usar Hibernate para comunicarse con la base de datos. Este
dialecto es la variante de SQLque usa la base de datos para ejecutar queries. Indicamos el dialecto con el "fully qualified class name",
o
el
nombre
completo
de
la
clase
incluyendo
el
paquete.
En
el
caso
de
MySQL
5
usamos
"org.hibernate.dialect.MySQL5Dialect". En esta pgina pueden encontrar una lista ms o menos completa de los dialectos
soportados por Hibernate, pero siempre es mejor revisar la documentacin de la versin que estn usando para estar seguros:

<property name="dialect">org.hibernate.dialect.MySQL5Dialect</property>

Otras dos propiedades importantes que podemos configurar son: "show_sql", que indica si queremos que las consultas SQL generadas
sean mostradas en el stdout(normalmente la consola), y "hbm2ddl.auto", que indica si queremos que se genere automticamente el
esquema de la base de datos (las tablas). "show_sql" puede tomar valores de "true" o "false", yo lo colocar en "true" (lo que
puede ser bueno mientras estamos en etapas de desarrollo o pruebas, pero querrn cambiar su valor cuando su aplicacin pase a
produccin). Por otro lado "hbm2ddl.auto" puede tomar los valores, segn la documentacin oficial, de "validate", "update",
"create", y "create-drop" (falta "none") (aunque no todos los valores funcionan para todas las bases de datos). Yo los colocar de la
siguiente forma:

<property name="show_sql">true</property>
<property name="hbm2ddl.auto">create-drop</property>

Con el valor "create-drop" hacemos que cada vez que se ejecute la aplicacin Hibernate elimine las tablas de la base de datos y las
vuelva a crear, cuando su sistema pase a produccin sera bueno que quitaran esta propiedad.
Para terminar la configuracin, debemos indicar dnde estn las clases entidades. Cuando usamos Hibernate con archivos de mapeo
usamos el atributo "resource" del elemento "<mapping>", en el que indicbamos en dnde se encontraba dicho archivo de mapeo.
Cuando usamos anotaciones (y por lo tanto no hay archivos de mapeo) debemos indicar las clases anotadas usando su atributo "class",
de la siguiente forma:

<mapping class="hibernateanotaciones.Contacto" />

Tal vez encuentren que "<mapping>" tiene otro atributo que es "package". No se confundan, este atributo NO sirve para indicar un
paquete en el que se encuentren las clases entidades anotadas y lograr que Hibernate encuentre automticamente estas clases para
ahorrarnos el trabajo de indicar cada clase. De hecho este atributo se usa cuando tenemos paquetes anotados. No estoy seguro de para
qu pueden usarse, pero solo no se confundan ^-^!.
El archivo de configuracin queda de la siguiente forma:

www.javatutoriales.com/2009/05/hibernate-parte-2-persistiendo-objetos.html

7/20

10/11/13

Tutoriales de Programacion Java: HIbernate - Parte 2: Persistiendo Objetos Simples usando Anotaciones (metadatos)

<?xml version="1.0" encoding="UTF-8"?>


<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="connection.url">jdbc:mysql://localhost/pruebahibernate</property>
<property name="connection.username">usuario</property>
<property name="connection.password">password</property>
<property name="connection.pool_size">1</property>
<property name="dialect">org.hibernate.dialect.MySQL5Dialect</property>
<property name="show_sql">true</property>
<property name="hbm2ddl.auto">create-drop</property>
<mapping class="hibernateanotaciones.Contacto" />
</session-factory>
</hibernate-configuration>

Esto es todo lo que debemos poner en el archivo de configuracin. Ahora veremos cmo crear el cdigo de acceso a la base de datos. Al
igual que en el tutorial anterior crearemos una clase de utilidad llamada "HibernateUtil", que se har cargo de inicializar y hacer el
acceso al "SessionFactory". La clase ser casi idntica, con una excepcin.
Creamos una nueva clase llamada "HibernateUtil" y dentro de esta clase declaramos un atributo static de tipo
"SessionFactory", as nos aseguraremos de que solo existe una instancia en la aplicacin. Adems lo declararemos como final
para que la referencia no pueda ser cambiada despus de que la hayamos asignado.

private static final SessionFactory sessionFactory;

Despus usamos un bloque de inicializacin esttico para inicializar esta variable en el momento en el que la clase sea cargada en la
JVM.
La ltima vez usamos una instancia de la clase "org.hibernate.cfg.Configuration" para cargar la configuracin. Cuando
usamos anotaciones usamos una instancia de "org.hibernate.cfg.AnnotationConfiguration". Si usamos el mtodo
"configure()" que no recibe parmetros entonces Hibernate busca el archivo "hibernate.cfg.xml" que creamos anteriormente.
Una vez que tenemos este objeto, entonces podemos inicializar la instancia de "SessionFactory" con su mtodo
"buildSessionFactory". Adems como este proceso puede lanzar "HibernateException" (que extiende de
"RuntimeException") la cachamos y lanzamos como un "ExceptionInInitializarError" (que es lo nico que puede lanzarse
desde un bloque de inicializacin). El bloque de inicializacin queda de la siguiente forma:

static
{
try
{
sessionFactory = new AnnotationConfiguration().configure().buildSessionFactory();
} catch (HibernateException he)
{
System.err.println("Ocurri un error en la inicializacin de la SessionFactory: " + he);
throw new ExceptionInInitializerError(he);
}
}

Finalmente creamos un mtodo staticpara recuperar la instancia de la "SessionFactory":

public static SessionFactory getSessionFactory()


{
return sessionFactory;
}

www.javatutoriales.com/2009/05/hibernate-parte-2-persistiendo-objetos.html

8/20

10/11/13

Tutoriales de Programacion Java: HIbernate - Parte 2: Persistiendo Objetos Simples usando Anotaciones (metadatos)

La clase "HibernateUtil" queda de la siguiente forma:

import org.hibernate.HibernateException;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.AnnotationConfiguration;
public class HibernateUtil
{
private static final SessionFactory sessionFactory;
static
{
try
{
sessionFactory = new AnnotationConfiguration().configure().buildSessionFactory();
} catch (HibernateException he)
{
System.err.println("Ocurri un error en la inicializacin de la SessionFactory: " + he)
;
throw new ExceptionInInitializerError(he);
}
}
public static SessionFactory getSessionFactory()
{
return sessionFactory;
}
}

Ahora escribiremos una clase DAO (nuevamente no seguiremos el patrn al pie de la letra, es solo para mostrar cmo trabajar con
Hibernate) que nos permitir realizar operaciones de base de datos. De hecho es la misma clase "ContactosDAO" del tutorial anterior.
Copiar los pasos y la explicacin para que no tengan que regresar a revisarla
Creamos una clase llamada "ContactosDAO" y agregamos dos atributos, uno llamado "sesion" de tipo "org.hibernate.Session",
y otro llamado "tx" de tipo "org.hibernate.Transaction".

private Session sesion;


private Transaction tx;

Estos atributos nos servirn para mantener la referencia a la sesin a base de datos, y a la transaccin actual, respectivamente. Ahora
agregaremos dos mtodos de utilidad. El primero nos ayudar a iniciar una sesin y una transaccin en la base de datos. Llamaremos a
este mtodo "iniciaOperacion", y la implementacin es la siguiente:

private void iniciaOperacion() throws HibernateException


{
sesion = HibernateUtil.getSessionFactory().openSession();
tx = sesion.beginTransaction();
}

En el mtodo anterior obtenemos una referencia a "SessionFactory" usando nuestra clase de utilidad "HibernateUtil". Una vez
que tenemos la "SessionFactory" creamos una conexin a la base de datos e iniciamos una nueva sesin con el mtodo
"openSession()". Una vez teniendo la sesin iniciamos una nueva transaccin y obtenemos una referencia a ella con
"beginTransaction()".
Ahora el segundo mtodo de utilidad (llamado "manejaExcepcion") nos ayudar a manejar las cosas en caso de que ocurra una
excepcin. Si esto pasa queremos que la transaccin que estamos ejecutando se deshaga y se relance la excepcin (o podramos lanzar

www.javatutoriales.com/2009/05/hibernate-parte-2-persistiendo-objetos.html

9/20

10/11/13

Tutoriales de Programacion Java: HIbernate - Parte 2: Persistiendo Objetos Simples usando Anotaciones (metadatos)
una propia). Por lo que el mtodo queda as:

private void manejaExcepcion(HibernateException he) throws HibernateException


{
tx.rollback();
throw new HibernateException("Ocurri un error en la capa de acceso a datos", he);
}

Ahora crearemos los mtodos que nos permitirn realizar las tareas de persistencia de una entidad "Contacto", conocidas en lenguaje
de base de datos como CRUD: guardarla, actualizarla, eliminarla, buscar un entidad "Contacto" y obtener todas los contactos que
existen en la base de datos, as que comencemos.
Afortunadamente Hibernate hace que esto sea fcil ya que proporciona mtodos para cada una de estas tareas. Primero veamos como
guardar un objeto "Contacto". Para esto Hibernate proporciona el mtodo "save" en nuestro objeto de tipo
"org.hibernate.Session", que se encarga de generar el "INSERT" apropiado para la entidad que estamos tratando de guardar. El
mtodo "guardaContacto" queda de la siguiente forma:

public long guardaContacto(Contacto contacto)


{
long id = 0;
try
{
iniciaOperacion();
id = (Long)sesion.save(contacto);
tx.commit();
}catch(HibernateException he)
{
manejaExcepcion(he);
throw he;
}finally
{
sesion.close();
}
return id;
}

Regresamos el "id" generado al guardar el "Contacto" solo por si queremos usarlo ms adelante en el proceso (como lo haremos
nosotros), o si queremos mostrarle al usuario, por alguna razn, el identificador del contacto.
Ahora veremos cmo actualizar un "Contacto". Para eso usamos el mtodo "update", de nuestro objeto "session", en nuestro
mtodo "actualizaContacto":

public void actualizaContacto(Contacto contacto) throws HibernateException


{
try
{
iniciaOperacion();
sesion.update(contacto);
tx.commit();
}catch (HibernateException he)
{
manejaExcepcion(he);
throw he;
}finally
{
sesion.close();
}
}

Como podemos ver, el mtodo para actualizar es muy similar al mtodo para guardar la entidad. Lo mismo ocurre con el mtodo para
eliminarla, "eliminaContacto":

www.javatutoriales.com/2009/05/hibernate-parte-2-persistiendo-objetos.html

10/20

10/11/13

Tutoriales de Programacion Java: HIbernate - Parte 2: Persistiendo Objetos Simples usando Anotaciones (metadatos)

public void eliminaContacto(Contacto contacto) throws HibernateException


{
try
{
iniciaOperacion();
sesion.delete(contacto);
tx.commit();
} catch (HibernateException he)
{
manejaExcepcion(he);
throw he;
}finally
{
sesion.close();
}
}

Ahora veremos unos mtodos un poco ms interesantes.


Cuando queremos buscar una entidad podemos usar varios criterios. La forma ms fcil es buscar una entidad particular usando su "id".
El objeto "org.hibernate.Session" proporciona dos mtodos para esto: "load" y "get". Los dos hacen prcticamente lo mismo. En
base al identificador y tipo de la entidad recuperan la entidad indicada, con la diferencia de que "load" lanza una excepcin en caso de
que la entidad indicada no sea encontrada en la base de datos, mientras que "get" simplemente regresa "null". Pueden usar el que
prefieran, en lo personal me gusta ms "get", as que lo usar para el mtodo "obtenContacto":

public Contacto obtenContacto(long idContacto) throws HibernateException


{
Contacto contacto = null;
try
{
iniciaOperacion();
contacto = (Contacto) sesion.get(Contacto.class, idContacto);
} finally
{
sesion.close();
}
return contacto;
}

Finalmente veremos el mtodo "obtenListaContactos" que recupera todos los Contactos que estn guardados en la base de
datos. Como en este caso regresaremos una lista de elementos deberemos crear una consulta. Nuevamente usaremos HQLpara generar
dicha consulta:

public List<Contacto> obtenListaContactos() throws HibernateException


{
List<Contacto> listaContactos = null;
try
{
iniciaOperacion();
listaContactos = sesion.createQuery("from Contacto").list();
}finally
{
sesion.close();
}
return listaContactos;
}

Eso es todo, nuestra consulta para recuperar todos los Contactos que tenemos en la base de datos solo debemos usar la clausula
"from Contacto". Si queren una referencia ms amplia de HQLpueden encontrarla en esta pgina.
Bien, eso es todo. La clase "ContactosDAO" queda de la siguiente forma (omitiendo los imports):

public class ContactosDAO


{
private Session sesion;
private Transaction tx;
public long guardaContacto(Contacto contacto) throws HibernateException

www.javatutoriales.com/2009/05/hibernate-parte-2-persistiendo-objetos.html

11/20

10/11/13

Tutoriales de Programacion Java: HIbernate - Parte 2: Persistiendo Objetos Simples usando Anotaciones (metadatos)
public long guardaContacto(Contacto contacto) throws HibernateException
{
long id = 0;
try
{
iniciaOperacion();
id = (Long) sesion.save(contacto);
tx.commit();
} catch (HibernateException he)
{
manejaExcepcion(he);
throw he;
} finally
{
sesion.close();
}
return id;
}
public void actualizaContacto(Contacto contacto) throws HibernateException
{
try
{
iniciaOperacion();
sesion.update(contacto);
tx.commit();
} catch (HibernateException he)
{
manejaExcepcion(he);
throw he;
} finally
{
sesion.close();
}
}
public void eliminaContacto(Contacto contacto) throws HibernateException
{
try
{
iniciaOperacion();
sesion.delete(contacto);
tx.commit();
} catch (HibernateException he)
{
manejaExcepcion(he);
throw he;
} finally
{
sesion.close();
}
}
public Contacto obtenContacto(long idContacto) throws HibernateException
{
Contacto contacto = null;
try
{
iniciaOperacion();
contacto = (Contacto) sesion.get(Contacto.class, idContacto);
} finally
{
sesion.close();
}
return contacto;
}
public List<Contacto> obtenListaContactos() throws HibernateException
{
List<Contacto> listaContactos = null;
try
{
iniciaOperacion();
listaContactos = sesion.createQuery("from Contacto").list();
} finally
{
sesion.close();
}
return listaContactos;
}
private void iniciaOperacion() throws HibernateException
{

www.javatutoriales.com/2009/05/hibernate-parte-2-persistiendo-objetos.html

12/20

10/11/13

Tutoriales de Programacion Java: HIbernate - Parte 2: Persistiendo Objetos Simples usando Anotaciones (metadatos)
{
sesion = HibernateUtil.getSessionFactory().openSession();
tx = sesion.beginTransaction();
}
private void manejaExcepcion(HibernateException he) throws HibernateException
{
tx.rollback();
throw new HibernateException("Ocurri un error en la capa de acceso a datos", he);
}
}

Ahora, y para terminar el ejemplo, haremos uso de "ContactosDAO" en la clase "Main" para crear y recuperar algunas instancias de
"Contactos". Como la clase es la misma que en el tutorial anterior no dar una explicacin. La clase "Main" queda de la siguiente
forma:

public class Main


{
public static void main(String[] args)
{
ContactosDAO contactosDAO = new ContactosDAO();
Contacto contactoRecuperado = null;
long idAEliminar = 0;
//Creamos tes instancias de Contacto
Contacto contacto1 = new Contacto("Contacto 1", "contacto1@contacto.com", "12345678");
Contacto contacto2 = new Contacto("Contacto 2", "contacto2@contacto.com", "87654321");
Contacto contacto3 = new Contacto("Contacto 3", "contacto3@contacto.com", "45612378");
//Guardamos las tres instancias, guardamos el id del contacto1 para usarlo posteriormente
idAEliminar = contactosDAO.guardaContacto(contacto1);
contactosDAO.guardaContacto(contacto2);
contactosDAO.guardaContacto(contacto3);
//Modificamos el contacto 2 y lo actualizamos
contacto2.setNombre("Nuevo Contacto 2");
contactosDAO.actualizaContacto(contacto2);
//Recuperamos el contacto1 de la base de datos
contactoRecuperado = contactosDAO.obtenContacto(idAEliminar);
System.out.println("Recuperamos a " + contactoRecuperado.getNombre());
//Eliminamos al contactoRecuperado (que es el contacto3)
contactosDAO.eliminaContacto(contactoRecuperado);
//Obtenemos la lista de contactos que quedan en la base de datos y la mostramos
List<Contacto> listaContactos = contactosDAO.obtenListaContactos();
System.out.println("Hay " + listaContactos.size() + "contactos en la base de datos");
for(Contacto c : listaContactos)
{
System.out.println("-> " + c.getNombre());
}
}
}

En el momento que ejecutemos la aplicacin Hibernate crear la tabla correspondiente en la base de datos (llamada "contactos", como
lo indicamos) y con los siguientes campos:

www.javatutoriales.com/2009/05/hibernate-parte-2-persistiendo-objetos.html

13/20

10/11/13

Tutoriales de Programacion Java: HIbernate - Parte 2: Persistiendo Objetos Simples usando Anotaciones (metadatos)

Como podemos ver la tabla se ha generado en base a las indicaciones que hemos hecho con las anotaciones.
Para terminar veamos los datos de la tabla. Segn la salida en la consola del NetBeans, debe haber dos contactos en la base de datos
"Nuevo Contacto 2" y "Contacto 3":

Si vemos los datos en la base comprabos que, efectivamente, esto es correcto:

Con lo que comprobamos que el ejemplo funciona!!! ^- ^.


Bien, pues en esta ocasin vimos cmo usar Hibernate sin hacer uso de archivos de mapeo en XML, indicando esos datos en el cdigo
fuente de la clase.
Esto tiene sus ventajas y desventajas, as que debe usarse con cuidado. Por ejemplo, como la informacin est en el cdigo fuente,
cualquier cambio necesitar que recompilemos la aplicacin. Adems que nuestra entidad ahora ha quedado atada al API de JPA.
Esto puede no ser problema en muchos casos, pero habr unos en los que si lo sea, como cuando no tenemos el cdigo fuente de las
entidades, o no queremos atarlas a JPA, porque las usaremos posteriormente en otra aplicacin que no usar JPA. Pero, nuevamente,
esto depende de la aplicacin que estn desarrollando.
Adems podemos mezclar ambos mtodos en donde, si existe un mapeo en los dos lugares para una misma clase, el mapero del archivo
XML toma precedencia.
Espero que este tutorial les haya sido de utilidad. En los prximos tutoriales mostrar como trabajar con Hibernate para hacer cosas ms
interesantes y mostrar como realizar la configuracin de las dos formas, con anotaciones y archivos de mapeo.
No olviden dejar sus dudas, comentarios y sugerencias.
Saludos.
Descarga los archivos de este tutorial desde aqu:
Hibernate Anotaciones

Entradas Relacionadas:
Parte 1: Persistiendo Objetos Simples usando Mapeos en XML
Parte 3: Relaciones / Uno a uno
Parte 4: Relaciones / Uno a muchos
Parte 5: Relaciones / Muchos a uno
Parte 6: Relaciones / Muchos a Muchos
Parte 7: HQL Primera Parte
Parte 8: HQL Segunda Parte
Parte 9: Parmetros en HQL
Parte 10: Herencia
Parte 11: Interceptores y Eventos
Publicado por Alex en 17:09
Reacciones:

divertido (1)

interesante (3)

increible (0)

no me gusta (0)

Recomendar esto en Google


Etiquetas: anotaciones, hibernate, java, mapeos

38 comentarios:
nbalike 14 de mayo de 2009 20:59

www.javatutoriales.com/2009/05/hibernate-parte-2-persistiendo-objetos.html

14/20

10/11/13

Tutoriales de Programacion Java: HIbernate - Parte 3: Relaciones / Uno a uno


Compartir

Ms

Siguiente blog

Tutoriales de Programacion Java


Blog dedicado a temas de programacin actuales usando el lenguaje de programacin Java y las ltimas versiones de sus APIs y Herramientas.
Pgina principal

Pgina de Concursos

Tutoriales UPAO 2010

Presentaciones Capacitacin

JUEVES, 4 DE JUNIO DE 2009

HIbernate - Parte 3: Relaciones / Uno a uno

DONACIONES

En los tutoriales anteriores vimos cmo persistir objetos simples en la base de datos usando Hibernate, tanto con archivos de mapeo XML
como con anotaciones. Gracias a eso no tuvimos que escribir ni una sola lnea de cdigo SQL.
Sin embargo solo en raras ocasiones deberemos guardar un objeto simple como lo vimos. Por lo regular guardamos grafos de objetos u
objetos relacionados con otros objetos. En estos casos querremos que los objetos se guarden, actualicen, o eliminen en el momento que
lo haga nuestro objeto principal (o tal vez no ^-^!).
En este tutorial veremos cmo manejar los objetos relacionados (con mapeos y con XML).
En Hibernate (y en general en las bases de datos) existen 4 tipos de relaciones:
Uno a Uno
Uno a Muchos
Muchos a Uno
Muchos a Muchos

JAVA TUTORIALES EN FACEBOOK

Java Tutoriales
Me gusta

Java Tutoriales

Amigo programador,
ests todo el da pica
cdigo, escucha esta
recomendaciones sl
hechas para ti..... q
esto?... Gracias Jorg
Rubira....

Si le ponemos direcciones a estas relaciones (unidireccional, o bidireccional) tendremos 7 tipos de relaciones:


Uno a uno unidireccional
Uno a uno bidireccional

No olviden poner la
sentencia where al ha
un borraro en la base
datos..

Uno a muchos unidireccional


Uno a muchos bidireccional
Muchos a uno unidireccional
muchos a muchos unidireccional

http://www.youtube.c
watch?v=i_cVJgIz_Cs
A 7895 personas les gusta

Muchos a muchos bidireccional


La relacin muchos a uno bidireccional es igual que la relacin uno a muchos bidireccional, as que la dejamos fuera.
Bien, pues en este y los siguientes tutoriales veremos cmo manejar estos 7 tipo de relaciones usando Hibernate.
En este tutorial solo veremos las relaciones uno a uno y cubrir los siguientes tipos de relaciones en las siguientes entregas, ya que hay
mucho que se puede decir sobre cada uno de los tipos de relaciones.
Crearemos un proyecto en NetBeans para mostrar los ejemplos (men "File -> New Project... -> Java -> Java
Application"). Le damos un nombre y una ubicacin al proyecto y nos aseguramos de que las opciones "Create Main Class" y
"Set as Main Project" estn habilitadas. Presionamos el botn "Finish" y veremos aparecer en el editor nuestra clase "Main".

Plug-in social de Facebook

Agregamos la biblioteca de "Hibernate", que creamos en el primer tutorial de la serie. Hacemos clic derecho en el nodo "Libraries"
del proyecto. En el men contextual que se abre seleccionamos la opcin "Add Library...":

En la ventana que se abre seleccionamos la biblioteca "Hibernate":

www.javatutoriales.com/2009/06/hibernate-parte-3-relaciones-uno-uno.html

1/24

10/11/13

Tutoriales de Programacion Java: HIbernate - Parte 3: Relaciones / Uno a uno

Java file
libraries
www.aspose.com
DOC, XLS, PPT, PDF,
MSG and more APIs
to Manage, Print and
Convert

Presionamos el botn "Add Library" para que la biblioteca se agregue a nuestro proyecto. Aprovechamos tambin para agregar el
conector de MySQL. Debemos tener los siguientes archivos en nuestro proyecto:

SEGUIDORES

Participar en este sitio


Google Friend Connect

Ahora creamos dos paquetes, uno con el nombre "modelo", que contendr las clases entidades, y otro con el nombre "mapeos" que
contendr los archivos de mapeo XML. Hacemos clic derecho en el nodo del paquete que se cre al generar el proyecto. En el men
contextual que se abre seleccionamos la opcin "New -> Java Package..." y creamos los dos paquetes.

Miembros (173) Ms

Ya eres miembro? Iniciar sesin

ARCHIVO DEL BLOG

2012 (2)
2011 (11)

Que deben quedar as:

2010 (10)
2009 (22)
septiembre (2)
agosto (2)
julio (1)
junio (3)
Acepto Donaciones

Hibernate - Parte 4: Relacione


muchos

HIbernate - Parte 3: Relacione


uno
mayo (2)
abril (5)
marzo (2)

Aprovecharemos para crear nuestro archivo de configuracin de Hibernate, "hibernate.cfg.xml", el cual ser muy parecido al del
primer tutorial:

www.javatutoriales.com/2009/06/hibernate-parte-3-relaciones-uno-uno.html

febrero (2)
enero (3)

2/24

10/11/13

Tutoriales de Programacion Java: HIbernate - Parte 3: Relaciones / Uno a uno

<!DOCTYPE hibernate-configuration PUBLIC


"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<!-- parametros para la conexion a la base de datos -->
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="connection.url">jdbc:mysql://localhost/hibernaterelaciones</property>
<property name="connection.username">usuario</property>
<property name="connection.password">password</property>
<!-- Configuracion del pool interno -->
<property name="connection.pool_size">1</property>
<!-- Dialecto de la base de datos -->
<property name="dialect">org.hibernate.dialect.MySQL5Dialect</property>
<!-- Otras propiedades importantes -->
<property name="show_sql">true</property>
<property name="hbm2ddl.auto">create-drop</property>
<!-- Aqui iran los archivos de mapeo -->
</session-factory>
</hibernate-configuration>

Para los ejercicios usaremos una base de datos llamada "hibernaterelaciones", en MySQL.
Nota: Yo usar dos proyectos, uno para usar archivos de m apeo y otro para usar anotaciones y que el cdigo de am bos no se m ezcle.

Ahora s, comencemos con el tema del tutorial.


En las relaciones uno a uno un objeto entidad de una clase Aest relacionado con uno y solo un objeto entidad de una clase B. Si la
relacin es unidireccional solo el objeto Aest consciente de la relacin (El objeto Atiene una referencia al objeto B) y el objeto BNO
sabe nada de esta. Por ejemplo, cuando tenemos una relacin Persona-> Direccion(es uno a uno porque una Persona, en teora,
solo puede tener una Direccion). Donde la Personaes la entidad "A" y la Direcciones la entidad "B". O sea, la Personaconoce
su Direccionpero la Direccionno conoce a la Personaa la que pertenece.

DATOS PERSONALES

Alex

Programador Java con algunos


experiencia en mltiples poyec
mltiples APIs y herramientas d
compartir experiencias con el
programadores.
Ver todo mi perfil

En las relaciones bidireccionales las dos entidades estn conscientes de la relacin. Por ejemplo, si tenemos una relacin Pais<->
Presidente(es uno a uno porque un Paissolo debera tener un Presidentey un Presidentesolo puede serlo de un Pais). En
este caso ambos lados de la relacin conocen el otro lado, o su "inverso".
Veamos estos dos ejemplos. Las clases que usaremos sern muy simples y solo pondr un atributo adicional al "id" y al de la relacin
para que esta ltima sea ms clara.

1 - Relaciones Uno a Uno Unidireccionales


Primero crearemos las clases Persona y Direccin (para la relacin unidireccional), dentro del paquete "modelo" que creamos
hace unos momentos. La clase Direccionqueda as:

www.javatutoriales.com/2009/06/hibernate-parte-3-relaciones-uno-uno.html

3/24

10/11/13

Tutoriales de Programacion Java: HIbernate - Parte 3: Relaciones / Uno a uno

public class Direccion implements Serializable


{
private long id;
private String calle;
private String codigoPostal;
public Direccion()
{
}
public long getId()
{
return id;
}
protected void setId(long id)
{
this.id = id;
}
public String getCalle()
{
return calle;
}
public void setCalle(String calle)
{
this.calle = calle;
}
public String getCodigoPostal()
{
return codigoPostal;
}
public void setCodigoPostal(String codigoPostal)
{
this.codigoPostal = codigoPostal;
}
}

Como podemos ver, la clase Direcciones muy simple, solo tiene el "idy dos atributos ms. De hecho esta entidad no tiene idea que
ser relacionada con una entidad Persona, la cual por cierto queda de esta forma:

www.javatutoriales.com/2009/06/hibernate-parte-3-relaciones-uno-uno.html

4/24

10/11/13

Tutoriales de Programacion Java: HIbernate - Parte 3: Relaciones / Uno a uno

public class Persona implements Serializable


{
private long id;
private String nombre;
private Direccion direccion;
public Persona()
{
}
public Direccion getDireccion()
{
return direccion;
}
public void setDireccion(Direccion direccion)
{
this.direccion = direccion;
}
public long getId()
{
return id;
}
protected void setId(long id)
{
this.id = id;
}
public String getNombre()
{
return nombre;
}
public void setNombre(String nombre)
{
this.nombre = nombre;
}
}

La clase Persona es un poco ms interesante. Esta clase tiene, adems del "id" y el atributo "nombre", un atributo de tipo
"Direccion" (con sus correspondientes settersy getters). Por lo tanto la Personatendr acceso a los datos de la Direccion.
En este caso se dice que Personaes la "duea" (owner) de la relacin. O sea que ella controla qu es lo que pasa cuando se realiza
una modificacin en un objeto entidad (si queremos que al eliminarse el dueo se elimine la entidad relacionada, o se actualice, o no pase
nada, etc.). Esto se configura en el archivo de mapeo XML o en las anotaciones, dependiendo del mtodo que estemos utilizando.
Veamos cmo indicar que existe este relacin. Primero veremos cmo indicarlo con archivos de mapeo y despus veremos cmo se hace
con anotaciones.

1.1 RELACIONES UNO A UNO UNIDIRECCIONALES CON ARCHIVOS DE MAPEO


Creamos, en el paquete "mapeos" un nuevo documento XML. Le damos de nombre "Direccion.hbm" (el asistente se encargar de
colocar el ".xml")

Presionamos el botn "Next >" e indicamos que queremos crear un documento XML bin formado (la primer opcin) y presionamos el
botn "Finish".
Eliminamos el contenido del archivo creado y lo reemplazamos con el siguiente:

www.javatutoriales.com/2009/06/hibernate-parte-3-relaciones-uno-uno.html

5/24

10/11/13

Tutoriales de Programacion Java: HIbernate - Parte 3: Relaciones / Uno a uno

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="hibernate.relaciones.modelo.Direccion" table="DIRECCIONES">
</class>
</hibernate-mapping>

El mapeo de la clase "Direccin" es muy simple, como el que expliqu en el primer tutorial de la serie. El mapeo queda de la siguiente
forma:

<hibernate-mapping>
<class name="hibernate.relaciones.modelo.Direccion" table="DIRECCIONES">
<id name="id" column="ID">
<generator class="identity" />
</id>
<property name="calle" />
<property name="codigoPostal" />
</class>
</hibernate-mapping>

Ahora crearemos el mapeo de la clase "Persona", en un archivo llamado llamado "Persona.hbm.xml" en el paquete "mapeos", la cul
de hecho ser muy parecido al de "Direccion", excepto en el identificador. Queremos que el identificador de la "Persona" y de la
"Direccion" sean el mismo, ya que en las relaciones uno a uno Hibernate supone que ambas entidades tendrn el mismo identificador
(lo cual podra no siempre ser verdad) y de esta forma la recuperacin de la Direccion se har automticamente al momento de
recuperar la Persona, lo mismo ocurre con la eliminacin. Pero como solamente Personaest consciente de la relacin, es ella quien
recibir el mismo identificador que la Direccion.
Para lograr esto usamos un generador especial de idllamado "foreign", indicando que el identificador ser tomado de otra entidad.
Decimos que la entidad est referenciada como la propiedad "direccion" de nuestra clase "Persona". Por lo que el identificador queda
as:

<id name="id" column="ID">


<generator class="foreign">
<param name="property">direccion</param>
</generator>
</id>

El archivo, solamente con los mapeos para los atributos "id" y "nombre", se ve as:

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="hibernate.relaciones.modelo.Persona" table="PERSONAS">
<id name="id" column="ID">
<generator class="foreign">
<param name="property">direccion</param>
</generator>
</id>
<property name="nombre" />
</class>
</hibernate-mapping>

www.javatutoriales.com/2009/06/hibernate-parte-3-relaciones-uno-uno.html

6/24

10/11/13

Tutoriales de Programacion Java: HIbernate - Parte 3: Relaciones / Uno a uno

Ahora agregaremos el elemento para indicar la relacin uno a uno con la clase "Direccion". Para esto usamos el elemento "<one-toone>". Usamos el atributo "name" para indicar cmo se llama el atributo en la clase "Persona" que indica la relacin con "Direccion",
que en este caso es "direccion":

<one-to-one name="direccion" />

Queremos que la entidad "Direccion" se guarde en la base de datos en el momento en el que se guarda la "Persona". De la misma
forma, queremos que cuando la "Persona" sea eliminada de la base de datos tambin se elimine su correspondiente "Direccion".
Para lograr esto usamos el atributo "cascade" del elemento "<one-to-one>".
Las operaciones en cascada son operaciones que se realizan en los hijos al mismo momento que en los padres (o en las entidades
relacionadas con la entidad en la que estamos realizando la operacin)
Este atributo puede tener los siguientes valores:
persist
merge
save-update
delete
lock
refresh
evict
replicate
all
none
La mayora de los valores corresponde con un mtodo, con el mismo nombre, del objeto Session de Hibernate, con excepcin de "all" y
"none", que no corresponden con ninguno.
Por default ninguna operacin se realiza en cascada, pero nosotros dijimos que queremos que la Direccionse actualice en el momento
en el que guardamos y eliminamos la Personaentonces indicamos como el valor de cascade"persist, delete":

<one-to-one name="direccion" cascade="persist, delete"/>

Al final el mapeo de Personaqueda de la siguiente forma:

<hibernate-mapping>
<class name="hibernate.relaciones.modelo.Persona" table="PERSONAS">
<id name="id" column="ID">
<generator class="foreign">
<param name="property">direccion</param>
</generator>
</id>
<property name="nombre" />
<one-to-one name="direccion" cascade="persist, delete"/>
</class>
</hibernate-mapping>

Esto es todo lo que necesitamos para esta relacin. No olviden agregar estos dos archivos de mapeo al archivo "hibernate.cfg.xml":

www.javatutoriales.com/2009/06/hibernate-parte-3-relaciones-uno-uno.html

7/24

10/11/13

Tutoriales de Programacion Java: HIbernate - Parte 3: Relaciones / Uno a uno

<mapping resource="hibernate/relaciones/mapeos/Persona.hbm.xml"/>
<mapping resource="hibernate/relaciones/mapeos/Direccion.hbm.xml"/>

Ahora usaremos la clase "HibernateUtil" que creamos en el primer tutorial para trabajar con nuestras entidades.
En la clase "Main" agregamos el siguiente cdigo autoexplicativo:

public static void main(String[] args)


{
Persona persona1 = new Persona();
persona1.setNombre("Persona que sera borrada");
Persona persona2 = new Persona();
persona2.setNombre("Persona que permanecera");
Direccion direccion1 = new Direccion();
direccion1.setCalle("Calle 1");
direccion1.setCodigoPostal("12345");
Direccion direccion2 = new Direccion();
direccion2.setCalle("Calle 2");
direccion2.setCodigoPostal("54321");
persona1.setDireccion(direccion1);
persona2.setDireccion(direccion2);
Session sesion = HibernateUtil.getSessionFactory().openSession();
/*Esta direccion se agrega para comprobar que las personas tomen el mismo
identificador que las direcciones (ninguna persona debe tener el mismo id de
esta direccion)*/
Direccion d = new Direccion();
d.setCalle("Calle de Prueba de identificadores");
d.setCodigoPostal("21345");
/*En la primer sesion a la base de datos almacenamos los dos objetos Persona
los objetos Direccion se almacenaran en cascada*/
sesion.beginTransaction();
sesion.persist(d);
sesion.persist(persona1);
sesion.persist(persona2);
sesion.getTransaction().commit();
sesion.close();

/*En la segunda sesion eliminamos el objeto persona1,


la direccion1 sera borrada en cascada*/
sesion = HibernateUtil.getSessionFactory().openSession();
sesion.beginTransaction();
sesion.delete(persona1);
sesion.getTransaction().commit();
sesion.close();
}

Como podemos ver, se crean tres Direcciones y dos Personas; dos de las Direcciones se relacionan con las Personas y
finalmente se elimina el objeto "persona1". Esto debera dejarnos solamente con una Persona almacenada y dos Direcciones.
Comprobemos que es as:

Como podemos ver, se eliminaron tanto la Personacomo la Direccioncon id= 2, comprobando que nuestra configuracin funciona ^-

www.javatutoriales.com/2009/06/hibernate-parte-3-relaciones-uno-uno.html

8/24

10/11/13

Tutoriales de Programacion Java: HIbernate - Parte 3: Relaciones / Uno a uno


^. Como dije anteriormente, en una relacin uno a uno Hibernate supondr que ambas entidades en la relacin tienen el mismo id.
Nosotros nos aseguramos de que esto ocurra indicando que el idde Persona, que es la nica entidad que sabe de la relacin, sea
tomado en base al idde su Direccionasociada. Claro que esto nos obliga a que siempre debe haber una Direccionasociada con
una Persona, de lo contrario esta ltima no podr obtener su idde ningn lado, por lo que debemos tener cuidado al usar este tipo de
relacin.
Ahora veremos cmo hacer lo mismo pero usando anotaciones:

1.2 RELACIONES UNO A UNO UNIDIRECCIONALES CON ANOTACIONES


Recuerden que pasa usar anotaciones debemos agregar al proyecto la biblioteca "HibernateAnotaciones" que creamos en el
segundo tutorial.
Las anotaciones que colocaremos en la clase "Direccion" sern las mismas que expliqu en el segundo tutorial de esta serie, como
son muy sencillas no volver a explicarlos. La clase "Direccionanotada queda de la siguiente forma:

@Entity
public class Direccion implements Serializable
{
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private long id;
private String calle;
private String codigoPostal;
public Direccion()
{
}
public long getId()
{
return id;
}
protected void setId(long id)
{
this.id = id;
}
public String getCalle()
{
return calle;
}
public void setCalle(String calle)
{
this.calle = calle;
}
public String getCodigoPostal()
{
return codigoPostal;
}
public void setCodigoPostal(String codigoPostal)
{
this.codigoPostal = codigoPostal;
}
}

Listo, con tan solo tres anotaciones nos ahorramos el crear un archivo de mapeo para esta clase.
La clase "Persona" se anota casi de la misma forma, con excepcin de la indicacin de la relacin uno a uno con la clase
"Direccion". Explicar primero esto.
Para cada una de los 4 tipos de relaciones que expliqu antes existe una anotacin especial. En el caso de las relaciones uno a uno se
usa la anotacin "@OneToOne" indicando cul atributo representa la relacin. En este caso la relacin est representado por el atributo
"direccion", as que la colocamos as:

@OneToOne
private Direccion direccion;

Es as de simple ^-^. Habiamos dicho que nos interesa que cuando guardamos y eliminamos la "Persona" tambin se elimine la

www.javatutoriales.com/2009/06/hibernate-parte-3-relaciones-uno-uno.html

9/24

10/11/13

Tutoriales de Programacion Java: HIbernate - Parte 3: Relaciones / Uno a uno


"Direccion" asociada, y que esto se logra indicando que esas operaciones se hagan en cascada. Usando anotaciones tambin
podemos indicar eso usando el atributo "cascade" de la anotacin que representa la relacin (en este caso "@OneToOne"). Este atributo
recibe un arreglo de objetos tipo "javax.persistence.CascadeType" la cual es una enumeracin. Cada elemento de la enumeracin
representa una operacin que ser realizada en cascada. Usando las anotaciones de JPA tenemos un nmero menor de operaciones que
con los archivos de mapeo. De hecho solo tenemos:
merge
persist
refresh
remove
all
Por default ninguna operacin se realiza en cascada, pero nosotros queremos que se realicen en cascada las operaciones de guardar y
eliminar, por lo que colocamos estos valores de la siguiente forma:

@OneToOne(cascade={CascadeType.PERSIST, CascadeType.REMOVE})
private Direccion direccion;

Adems, y para terminar con esta parte, haba comentado que Hibernate realizar las operaciones en cascada suponiendo que tanto la
Personacomo la Direcciontienen el mismo identificador, pero que esto podra no siempre ser verdad (como en el ejemplo que vimos
anteriormente). Por lo que debemos indicar que el identificador de Personadebe ser el mismo que el de Direccion.
Para indicar esto con anotaciones se supone que usamos la anotacin "@PrimaryKeyJoinColumn" en el elemento del que se tomar
el id, que en ese caso tambin es "direccion", pero en la prctica esto no funciona ^-^!, de hecho hay muchos reportes en el sitio de
Hibernate indicando esto. As que dejamos la anotacin de la relacin como est. Con esto lograremos que en la tabla en la que se
almacene las entidades "Persona" se agregue una columna ms para indicar con cul "Direccion" est relacionada.
Finalmente la relacin queda indicada de esta forma:

@OneToOne(cascade={CascadeType.PERSIST, CascadeType.REMOVE})
private Direccion direccion;

La clase "Persona" anotada queda de la siguiente forma:

www.javatutoriales.com/2009/06/hibernate-parte-3-relaciones-uno-uno.html

10/24

10/11/13

Tutoriales de Programacion Java: HIbernate - Parte 3: Relaciones / Uno a uno

@Entity public class Persona implements Serializable


{
@Id
private long id;
private String nombre;
@OneToOne(cascade={CascadeType.PERSIST, CascadeType.REMOVE})
private Direccion direccion;
public Persona()
{
}
public Direccion getDireccion()
{
return direccion;
}
public void setDireccion(Direccion direccion)
{
this.direccion = direccion;
}
public long getId()
{
return id;
}
protected void setId(long id)
{
this.id = id;
}
public String getNombre()
{
return nombre;
}
public void setNombre(String nombre)
{
this.nombre = nombre;
}
}

No olviden que debemos colocar en el archivo de configuracin de Hibernate estas clases:

<mapping class="hibernate.relacionesanotaciones.modelo.Persona" />


<mapping class="hibernate.relacionesanotaciones.modelo.Direccion" />

En esta ocasin usaremos la clase "HibernateUtil" que creamos en el segundo tutorial para trabajar con nuestras entidades.
La clase "Main" tiene el mismo cdigo auto-explicativo de antes:

www.javatutoriales.com/2009/06/hibernate-parte-3-relaciones-uno-uno.html

11/24

10/11/13

Tutoriales de Programacion Java: HIbernate - Parte 3: Relaciones / Uno a uno

public static void main(String[] args)


{
Persona persona1 = new Persona();
persona1.setNombre("Persona que sera borrada");
Persona persona2 = new Persona();
persona2.setNombre("Persona que permanecera");
Direccion direccion1 = new Direccion();
direccion1.setCalle("Calle 1");
direccion1.setCodigoPostal("12345");
Direccion direccion2 = new Direccion();
direccion2.setCalle("Calle 2");
direccion2.setCodigoPostal("54321");
persona1.setDireccion(direccion1);
persona2.setDireccion(direccion2);
Session sesion = HibernateUtil.getSessionFactory().openSession();
/*Esta direccion se agrega para comprobar que las personas tomen el mismo
identificador que las direcciones*/
Direccion d = new Direccion();
d.setCalle("Calle de Prueba de identificadores");
d.setCodigoPostal("21345");
/*En la primer sesion a la base de datos almacenamos los dos objetos Persona
los objetos Direccion se almacenaran en cascada*/
sesion.beginTransaction();
sesion.persist(d);
sesion.persist(persona1);
sesion.persist(persona2);
sesion.getTransaction().commit();
sesion.close();
/*En la segunda sesion eliminamos el objeto persona1,
la direccion1 sera borrada en cascada*/
sesion = HibernateUtil.getSessionFactory().openSession();
sesion.beginTransaction();
sesion.delete(persona1);
sesion.getTransaction().commit();
sesion.close();
}

Nuevamente revisamos que se hayan eliminado la persona1y direccion1:

Como podemos ver tambin este ejemplo funciona ^-^. Ahora veremos cmo crear relaciones uno a uno pero en esta ocasin
bidireccionales.

2 - Relaciones Uno a Uno Bidireccionales


El crear relaciones uno a uno bidireccionales no es muy distinto a crearlas unidireccionales. La nica diferencia es que en este caso
ambos lados de la relacin estn conscientes de la misma. Veamos el ejemplo. Para esto usaremos dos clases: "Paisy "Presidente.
Estas clases las pondremos en el paquete "modelo" que creamos anteriormente.
La clase Paisqueda as:

www.javatutoriales.com/2009/06/hibernate-parte-3-relaciones-uno-uno.html

12/24

10/11/13

Tutoriales de Programacion Java: HIbernate - Parte 3: Relaciones / Uno a uno

public class Pais implements Serializable


{
private int id;
private String nombre;
private Presidente presidente;
public Pais()
{
}
public int getId()
{
return id;
}
protected void setId(int id)
{
this.id = id;
}
public String getNombre()
{
return nombre;
}
public void setNombre(String nombre)
{
this.nombre = nombre;
}
public Presidente getPresidente()
{
return presidente;
}
public void setPresidente(Presidente presidente)
{
this.presidente = presidente;
}
}

Vemos que la clase "Pais" tiene una referencia a un objeto de tipo "Presidente" y por lo tanto sabe que existe la relacin y puede
acceder a la misma.
Ahora veamos cmo queda la clase "Presidente":

www.javatutoriales.com/2009/06/hibernate-parte-3-relaciones-uno-uno.html

13/24

10/11/13

Tutoriales de Programacion Java: HIbernate - Parte 3: Relaciones / Uno a uno

public class Presidente implements Serializable


{
private int id;
private String nombre;
private Pais pais;
public Presidente()
{
}
public int getId()
{
return id;
}
protected void setId(int id)
{
this.id = id;
}
public String getNombre()
{
return nombre;
}
public void setNombre(String nombre)
{
this.nombre = nombre;
}
public Pais getPais()
{
return pais;
}
public void setPais(Pais pais)
{
this.pais = pais;
}
}

Como podemos ver, "Presidente" tambin sabe de la relacin por lo que tiene una referencia a un objeto "Pais". Ahora veremos cmo
realizar el mapeo de las relaciones uno a uno bidireccionales de estas dos clases que, como podremos ver, es igual que para las
relaciones unidireccionales. Comencemos usando los archivos de mapeo:

2.1 RELACIONES UNO A UNO BIDIRECCIONALES CON ARCHIVOS DE MAPEO


Creamos, en el paquete "mapeos" un nuevo documento XML. Le damos de nombre "Pais.hbm" (el asistente se encargar de colocar el
".xml"):

Presionamos el botn "Next >" e indicamos que queremos crear un documento XML bien formado (la primer opcin) y presionamos el
botn "Finish".
Eliminamos el contenido del archivo creado y lo reemplazamos con el siguiente:

www.javatutoriales.com/2009/06/hibernate-parte-3-relaciones-uno-uno.html

14/24

10/11/13

Tutoriales de Programacion Java: HIbernate - Parte 3: Relaciones / Uno a uno

<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC


"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="hibernate.relaciones.modelo.Pais" table="Paises">
<id name="id" column="ID">
<generator class="identity" />
</id>
<property name="nombre" />
<one-to-one name="presidente" cascade="persist,delete"/>
</class>
</hibernate-mapping>

Como podemos ver, el mapeo de "Pais" es prcticamente el mismo que para la relacin uno a uno.
Ahora crearemos el mapeo para la clase "Presidente". Creamos, en el paquete "mapeos" un nuevo documento XML. Le damos de
nombre "Presidente.hbm" (el asistente se encargar de colocar el ".xml)

Presionamos el botn "Next >" e indicamos que queremos crear un documento XML bien formado (la primer opcin) y presionamos el
botn "Finish".
Eliminamos el contenido del archivo creado y lo reemplazamos con el siguiente:

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="hibernate.relaciones.modelo.Presidente" table="Presidentes">
<id name="id" column="ID">
<generator class="foreign">
<param name="property">pais</param>
</generator>
</id>
<property name="nombre" />
<one-to-one name="pais" constrained="true" />
</class>
</hibernate-mapping>

www.javatutoriales.com/2009/06/hibernate-parte-3-relaciones-uno-uno.html

15/24

10/11/13

Tutoriales de Programacion Java: HIbernate - Parte 3: Relaciones / Uno a uno

Podemos ver que nuevamente usamos la estrategia de colocar "foreign" como generador para el "id" del Presidente, para que sea
tomado el mismo que el Paiscon el que est asociado. Aqu estoy haciendo una suposicin para que eso funcione: No puede existir
un Presidentesi antes no existe el Pais que gobernar. O sea que la entidad "Pais" debe ser guardado en la base de datos
antes, o al menos al mismo tiempo, que el "Presidente".
En esta ocasin en el elemento "<one-to-one>" agregu el elemento "constrained". Esto colocar una restriccin, evitando que se
almacene el Presidentesi antes no existe el Pais(para evitar que tratemos de almacenar un Presidentesin Pais, o de un Pais
que no exista).
Eso es todo para mapear las relaciones. No olviden agregar los dos mapeos nuevos al archivo "hibernate.cfg.xml":

<mapping resource="hibernate/relaciones/mapeos/Pais.hbm.xml"/>
<mapping resource="hibernate/relaciones/mapeos/Presidente.hbm.xml"/>

Ahora en nuestra clase "Main" colocamos el siguiente cdigo que, nuevamente, es auto-explicativo:

public static void main(String[] args)


{
Pais pais1 = new Pais();
pais1.setNombre("China");
Pais pais2 = new Pais();
pais2.setNombre("Corea");

Presidente presidente1 = new Presidente();


presidente1.setNombre("Jiang Zemin");
Presidente presidente2 = new Presidente();
presidente2.setNombre("Kim Dae-Jung");
pais1.setPresidente(presidente1);
pais2.setPresidente(presidente2);
presidente1.setPais(pais1);
presidente2.setPais(pais2);
Session sesion = HibernateUtil.getSessionFactory().openSession();

/*Este pais se agrega para comprobar que los presidentes tomen el mismo
identificador que los paises*/
Pais p = new Pais();
p.setNombre("Chipre");

/*En la primer sesion a la base de datos almacenamos los dos objetos Pais
los objetos Presidente se almacenaran en cascada*/
sesion.beginTransaction();
sesion.persist(p);
sesion.persist(pais1);
sesion.persist(pais2);
sesion.getTransaction().commit();
sesion.close();

/*En la segunda sesion eliminamos el objeto pais1,


el presidente1 sera borrado en cascada*/
sesion = HibernateUtil.getSessionFactory().openSession();
sesion.beginTransaction();
sesion.delete(pais1);
sesion.getTransaction().commit();
sesion.close();
}

www.javatutoriales.com/2009/06/hibernate-parte-3-relaciones-uno-uno.html

16/24

10/11/13

Tutoriales de Programacion Java: HIbernate - Parte 3: Relaciones / Uno a uno

En esta ocasin debemos agregar los dos objetos de los dos lados de la relacin, es decir, debemos agregar el Paisal Presidentey
el Presidenteal Paishaciendo:

pais.setPresidente(presidente);
presidente.setPais(pais);

Una forma ms elegante sera llamar al mtodo "setPais" del objeto Presidenteal momento de establecer su Pais, o sea, el mtodo
"setPresidente" de la clase Paisquedara as:

public void setPresidente(Presidente presidente)


{
this.presidente = presidente;
presidente.setPais(this);
}

As solo tendremos que hacer:

pais.setPresidente(presidente);

Pero es cuestin de gustos.


Ahora pasemos a ver los resultados de las operaciones realizadas por Hibernate. Segun el cdigo de la clase Main, debemos haber
guardado 3 Paises y 2 Presidentes y, posteriormente, haber eliminado un Pais(y por lo tanto un Presidente), y quedarnos con 2
Paises y 1 Presidente. Vemos qu es lo que tenemos en la base de datos:

Como podemos ver, una vez ms ^-^, todo ha salido bien, por lo que podemos pasar a la ltima parte de este tutorial:

2.2 RELACIONES UNO A UNO BIDIRECCIONALES CON ANOTACIONES


Nuevamente las anotaciones que hay que usar son muy simples y similares a las que ya hemos usado, por lo que las colocar sin mucha
explicacin. La clase Paisqueda as:

www.javatutoriales.com/2009/06/hibernate-parte-3-relaciones-uno-uno.html

17/24

10/11/13

Tutoriales de Programacion Java: HIbernate - Parte 3: Relaciones / Uno a uno

@Entity
public class Pais implements Serializable
{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String nombre;
@OneToOne(cascade={CascadeType.PERSIST,CascadeType.REMOVE})
private Presidente presidente;
public Pais()
{
}
public int getId()
{
return id;
}
protected void setId(int id)
{
this.id = id;
}
public String getNombre()
{
return nombre;
}
public void setNombre(String nombre)
{
this.nombre = nombre;
}
public Presidente getPresidente()
{
return presidente;
}
public void setPresidente(Presidente presidente)
{
this.presidente = presidente;
}
}

La anotacin que debemos usar es, nuevamente "@OneToOne" y se usa de la misma forma que en el caso de las relaciones
unidireccionales.
La clase Presidentequeda as:

www.javatutoriales.com/2009/06/hibernate-parte-3-relaciones-uno-uno.html

18/24

10/11/13

Tutoriales de Programacion Java: HIbernate - Parte 3: Relaciones / Uno a uno

@Entity
public class Presidente implements Serializable
{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String nombre;
@OneToOne
private Pais pais;
public Presidente()
{
}
public int getId()
{
return id;
}
protected void setId(int id)
{
this.id = id;
}
public String getNombre()
{
return nombre;
}
public void setNombre(String nombre)
{
this.nombre = nombre;
}
public Pais getPais()
{
return pais;
}
public void setPais(Pais pais)
{
this.pais = pais;
}
}

Y listo, esto es todo lo que debemos hacer para tener nuestra aplicacin con una relacin uno a uno bidireccional ^-^. Ahora probemos
que todo funciona correctamente.
No olviden agregar estas dos clases al archivo "hibernate.cfg.xml":

<mapping class="hibernate.relacionesanotaciones.modelo.Pais" />


<mapping class="hibernate.relacionesanotaciones.modelo.Presidente" />

Para probar que todo funciona bien, coloquen el siguiente cdigo en la clase "Main":

www.javatutoriales.com/2009/06/hibernate-parte-3-relaciones-uno-uno.html

19/24

10/11/13

Tutoriales de Programacion Java: HIbernate - Parte 3: Relaciones / Uno a uno

public static void main(String[] args)


{
Pais pais1 = new Pais();
pais1.setNombre("China");
Pais pais2 = new Pais();
pais2.setNombre("Corea");
Presidente presidente1 = new Presidente();
presidente1.setNombre("Jiang Zemin");
Presidente presidente2 = new Presidente();
presidente2.setNombre("Kim Dae-Jung");
pais1.setPresidente(presidente1);
pais2.setPresidente(presidente2);
presidente1.setPais(pais1);
presidente2.setPais(pais2);
Session sesion = HibernateUtil.getSessionFactory().openSession();
/*Este pais se agrega para comprobar que los presidentes tomen el mismo
identificador que los paises*/
Pais p = new Pais();
p.setNombre("Chipre");
/*En la primer sesion a la base de datos almacenamos los dos objetos Pais
los objetos Presidente se almacenaran en cascada*/
sesion.beginTransaction();
sesion.persist(p);
sesion.persist(pais1);
sesion.persist(pais2);
sesion.getTransaction().commit();
sesion.close();
/*En la segunda sesion eliminamos el objeto pais1,
el presidente1 sera borrado en cascada*/
sesion = HibernateUtil.getSessionFactory().openSession();
sesion.beginTransaction();
sesion.delete(pais1);
sesion.getTransaction().commit();
sesion.close();
}

Comprobemos que, en la base de datos, solo haya dos Paises y un Presidente:

Como podemos ver, todo ha salido bien ^-^.


Espero que todo haya quedado claro, en caso contrario no duden en dejar sus dudas, comentarios y sugerencias.
En los siguientes tutoriales veremos cmo manejar los otros tipos de relaciones que podemos tener usando Hibernate.
Saludos
Descarga los archivos de este tutorial desde aqu:
Hibernate Relaciones Uno a Uno con Archivos de Mapeo
Hibernate Relaciones Uno a uno con Anotaciones

Entradas Relacionadas:
Parte 1: Persistiendo Objetos Simples usando Mapeos en XML
Parte 2: Persistiendo Objetos Simples usando Anotaciones (Metadatos)

www.javatutoriales.com/2009/06/hibernate-parte-3-relaciones-uno-uno.html

20/24

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 4: Relaciones / Uno a muchos


Compartir

Ms

Siguiente blog

Tutoriales de Programacion Java


Blog dedicado a temas de programacin actuales usando el lenguaje de programacin Java y las ltimas versiones de sus APIs y Herramientas.
Pgina principal

Pgina de Concursos

Tutoriales UPAO 2010

Presentaciones Capacitacin

SBADO, 27 DE JUNIO DE 2009

Hibernate - Parte 4: Relaciones / Uno a muchos

DONACIONES

En el tutorial anterior dijimos que en las bases de datos existen 7 tipos de relaciones, y vimos cmo crear relaciones uno a uno, tanto
unidireccionales com bidireccionales, con Hibernate usando archivos de mapeo y anotaciones (en ejemplos separados). Cubriendo con
eso 2 de los 7 tipos.
Ahora veremos como trabajar con relaciones Uno a Muchos, unidireccionales y bidireccionales. Con lo que cubriremos otros dos tipos.
Lo primero que haremos es crear un proyecto en NetBeans (men "File -> New Project... -> Java -> Java
Application"). Le damos un nombre y una ubicacin al proyecto y nos aseguramos de que las opciones "Create Main Class" y
"Set as Main Project" estn habilitadas. Presionamos el botn "Finish" y veremos aparecer en el editor nuestra clase "Main".
Agregamos la biblioteca de Hibernate, que creamos en el primer tutorial de la serie. Hacemos clic derecho en el nodo "Libraries" del
proyecto. En el men contextual que se abre seleccionamos la opcin "Add Library...":

JAVA TUTORIALES EN FACEBOOK

Java Tutoriales
Me gusta

Java Tutoriales

Amigo programador,
ests todo el da pica
cdigo, escucha esta
recomendaciones sl
hechas para ti..... q
esto?... Gracias Jorg
Rubira....

No olviden poner la
sentencia where al ha
un borraro en la base
datos..

http://www.youtube.c
watch?v=i_cVJgIz_Cs
A 7895 personas les gusta

En la ventana que se abre seleccionamos la biblioteca "Hibernate":

Plug-in social de Facebook

Presionamos el botn "Add Library" para que la biblioteca se agregue a nuestro proyecto. Aprovechamos tambin para agregar el
conector de MySQL. Debemos tener los siguientes archivos en nuestro proyecto:

www.javatutoriales.com/2009/06/hibernate-parte-4-relaciones-uno-muchos.html

1/27

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 4: Relaciones / Uno a muchos

Ahora creamos dos paquetes, uno con el nombre "modelo", que contendr las clases entidades, y otro con el nombre "mapeos" que
contendr los archivos de mapeo XML. Hacemos clic derecho en el nodo del paquete que se cre al generar el proyecto. En el men
contextual que se abre seleccionamos la opcin "New -> Java Package..." y creamos los dos paquetes

Que deben quedar as:


SEGUIDORES

Participar en este sitio


Google Friend Connect

Miembros (173) Ms

Aprovecharemos para crear nuestro archivo de configuracin de Hibernate, "hibernate.cfg.xml", el cual ser muy parecido al del
primer tutorial:

Ya eres miembro? Iniciar sesin

ARCHIVO DEL BLOG

2012 (2)

<!DOCTYPE hibernate-configuration PUBLIC


"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>

2011 (11)
2010 (10)
2009 (22)
septiembre (2)
agosto (2)

<!-- parametros para la conexion a la base de datos -->


<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="connection.url">jdbc:mysql://localhost/hibernaterelaciones</property>
<property name="connection.username">usuario</property>
<property name="connection.password">password</property>
<!-- Configuracion del pool interno -->
<property name="connection.pool_size">1</property>

julio (1)
junio (3)
Acepto Donaciones

Hibernate - Parte 4: Relacione


muchos

HIbernate - Parte 3: Relacione


uno
mayo (2)

<!-- Dialecto de la base de datos -->


<property name="dialect">org.hibernate.dialect.MySQL5Dialect</property>
<!-- Otras propiedades importantes -->
<property name="show_sql">true</property>
<property name="hbm2ddl.auto">create-drop</property>

abril (5)
marzo (2)
febrero (2)
enero (3)

<!-- Aqui iran los archivos de mapeo -->


</session-factory>
</hibernate-configuration>

Para los ejercicios usaremos una base de datos llamada "hibernaterelaciones", en MySQL.
Nota: Yo usar dos proyectos, uno para usar archivos de m apeo y otro para usar anotaciones y que el cdigo de am bos no se m ezcle.

www.javatutoriales.com/2009/06/hibernate-parte-4-relaciones-uno-muchos.html

2/27

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 4: Relaciones / Uno a muchos


Pues bien, comencemos.
En las relaciones Uno a Muchos, un objeto de la entidad "A" (el lado uno) est relacionado con muchos objetos de la entidad "B" (el lado
muchos). En el caso de que la relacin sea unidireccional, solo la entidad "A" tiene una referencia a los objetos de tipo "B" y esta
relacin est representada por una coleccin (un Listo un Set) y la entidad "A" puede acceder a cada uno de los objetos de tipo "B" de
esa coleccin. Un ejemplo de este tipo de relaciones puede ser una Personapuede tener muchos Libros. Donde la Persona es el
lado Uno de la relacin, y los Libros son el lado Muchos.
Si la relacin es bidireccional, adicionalmente, las entidades "B" tendrn una referencia a la entidad "A" con la que estn relacionados.
Un ejemplo de esto es un Jefey sus Empleados. En donde el Jefees el lado Uno y los Empleados el lado Muchos.

Programador
Java?
InfoJobs.net/Ofert
Ms de mil ofertas de
empleo Java
interesantes
Descbrelas!

Este tipo de relacin se vera de forma grfica ms o menos as:

Extend JMS to
.NET
Cursos Gratis
INEM
Kick Eclipse to
the Cloud
Bien, ahora comencemos con los ejemplos:

3 - Relaciones Uno a Muchos Unidireccionales


Primero crearemos las clases Persona y Libro (para la relacin unidireccional), dentro del paquete "modelo" que creamos hace
unos momentos. La clase Libroqueda as:

Curso
Programacin

DATOS PERSONALES

Alex

public class Libro


{
private long id;
private String titulo;

Programador Java con algunos


experiencia en mltiples poyec
mltiples APIs y herramientas d
compartir experiencias con el
programadores.
Ver todo mi perfil

public Libro()
{
}
public long getId()
{
return id;
}
protected void setId(long id)
{
this.id = id;
}
public String getTitulo()
{
return titulo;
}
public void setTitulo(String titulo)
{
this.titulo = titulo;
}
}

Como podemos ver es una clase muy simple, solo tiene dos atributos: id y titulo y, como no tiene ninguna referencia a la clase
Persona, no sabe nada de la existencia de una relacin con esta.
Pasemos a ver cmo queda la clase Persona:

www.javatutoriales.com/2009/06/hibernate-parte-4-relaciones-uno-muchos.html

3/27

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 4: Relaciones / Uno a muchos

public class Persona


{
private long id;
private String nombre;
private List<Libro> libros = new ArrayList<Libro>();
public Persona()
{
}
public long getId()
{
return id;
}
protected void setId(long id)
{
this.id = id;
}
public String getNombre()
{
return nombre;
}
public void setNombre(String nombre)
{
this.nombre = nombre;
}
public List getLibros()
{
return libros;
}
public void setLibros(List libros)
{
this.libros = libros;
}
public void addLibro(Libro libro)
{
this.libros.add(libro);
}
}

La clase Personatiene, como habamos dicho, una referencia a una coleccin (en este caso a una lista de objetos Libro, por lo que
puede acceder a cada uno de los datos de los libros. La lista se inicializa con un ArrayListen el momento de la creacin del objeto.
Esto nos ayudar a agregar libros tan pronto como creamos un nuevo objeto Persona, sin recibir una NullPointerException.
He agregado adems de los settersy los getterspara la lista de Libros un mtodo auxiliar llamado "addLibro" que permite
agregar un libro a la lista.
Ahora veremos cmo indicarle a Hibernate que existen estas relaciones, primero usando archivos de mapeo y despus usando
anotaciones:

3.1 RELACIONES UNO A MUCHOS UNIDIRECCIONALES CON ARCHIVOS DE MAPEO


Creamos un nuevo documento XML en el paquete "mapeos". Le damos el nombre de "Libro.hbm" (el asistente se encargar de colocar
el .xml):

Presionamos el botn "Next >" e indicamos que queremos crear un documento XML bien formado (la primer opcin) y presionamos el
botn "Finish".

www.javatutoriales.com/2009/06/hibernate-parte-4-relaciones-uno-muchos.html

4/27

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 4: Relaciones / Uno a muchos


Eliminamos el contenido del archivo creado y lo reemplazamos con el siguiente:

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="hibernate.relaciones.unomuchos.modelo.Libro" table="LIBROS">
</class>
</hibernate-mapping>

El mapeo de la clase Libroes similar al que expliqu en el primer tutorial de la serie y, al final, queda de la siguiente forma:

<hibernate-mapping>
<class name="hibernate.relaciones.unomuchos.modelo.Libro" table="LIBROS">
<id name="id">
<generator class="identity" />
</id>
<property name="titulo" />
</class>
</hibernate-mapping>

Ahora crearemos el mapeo para la clase "Persona", llamado "Persona.hbm.xml" en el paquete "mapeos", de la misma forma que lo
hicimos para Libro. El mapeo, excluyendo el elemento que representa la relacin debe estar de esta forma:

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="hibernate.relaciones.unomuchos.modelo.Persona" table="PERSONAS">
<id name="id" column="ID_PERSONA" >
<generator class="identity" />
</id>
<property name="nombre" />
</class>
</hibernate-mapping>

Noten que en esta ocasin agregue el atributo "column" en el elemento "<id>". Esto es importante ya que deberemos indicar el nombre
de esta columna para poder crear la relacin (cul ser la llave fornea que se usar).
Ahora ocupmonos de la relacin.
Las relaciones uno a muchos se representan usando el elemento acorde con el tipo de coleccin que estemos usando (list, set,
map, array, y primitive-array) existe otro elemento llamado "bag" usado de forma menos frecuente y que tal vez veamos en otro
tutorial.
Cada tipo de coleccin se mapea de forma un poco distinta. Como nosostros estamos usando una lista, veremos cmo mapear esta pero
pueden encontrar como mapear los otros tipos de colecciones en esta pgina.
Para mapear una lista usamos el elemento "<list>". En este elemento indicamos cul es el nombre del atributo, dentro de la clase
Persona, que representa la relacin. En este caso el atributo se llama "libros". Tambin aqu indicamos cules operaciones queremos
que se realicen en cascada. En este caso queremos que todas las operaciones de guardar, actualizar y eliminar que ocurran en el padre
sean pasadas a la coleccin, o sea que cuando guardemos, actualicemos, o eliminemos una Persona, las operaciones pasen tambin a
todos sus Libros relacionados, por lo que usamos el valor "all".

www.javatutoriales.com/2009/06/hibernate-parte-4-relaciones-uno-muchos.html

5/27

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 4: Relaciones / Uno a muchos


En las relaciones uno a muchos existe dos estilos de cascada especiales llamados "delete-orphan" y "all-delete-orphan" (que
solo existen si usamos archivos de mapeo) los cuales se encargan de que, en el caso de que se elimine el objeto padre (Persona),
todos los objetos hijos (Libros) sern eliminados de la base de datos. Adicionalmente "all-delete-orphan" se encarga de que
todas las otras operaciones que mencionamos antes (guardar, actualizar, y eliminar) tambin sean realizados en cascada, por lo que
usaremos este valor:

<list name="libros" cascade="all-delete-orphan">


</list>

Ahora indicamos cul ser el valor que se usar como llave fornea para relacionar los Libros con la Persona. Recuerdan que
indicamos el nombre de la columna para el identificador de la Persona? Pues bien, es aqu en donde usaremos este valor:

<key column="ID_PERSONA" />

Con esto indicamos que, en la tabla que se crear para mantener las entidades Libro, se debe crear una llave fornea relacionada con el
identificador de la tabla Persona, identificada en este caso por la columna "ID_PERSONA". Indicamos el nombre de la columna de forma
explcita ya que si dejamos que sea Hibernate quien lo genere, el nombre de la llave fornea (id) ser el mismo que el de la llave primara
(id) y ocurrirn errores al tratar de insertar entidades (claro que esto tambin podra solucionarse dando a los atributos nombres distintos
desde el principio, pero es cuestin de gustos).
Ahora bien, las listas son una estructura de datos con una caracterstica nica: tienen un orden. Esto significa que el orden en el que
los elementos entran en la lista es importante e, internamente, se usa un ndice para saber el orden de los elementos.
Cuando tratamos de almacenar estos datos nos interesa que en el momento que sean recuperados, los elementos de la lista estn en el
mismo orden en el que los guardamos y es por esta razn que se debe usar una columna extra en la tabla generada para guardar
este ndice (el cual comienza en cero). Para indicar el nombre que tendr esta columna usamos el elemento "index" y colocamos en su
atributo "column" el nombre que tendr esta columna:

<index column="ORDEN" />

Dejamos lo mejor para el final ^-^ ya que ahora debemos indicar qu tipo de relacin representa esta coleccin. Como en este caso
estamos representando una relacin "uno a muchos", usamos el elemento "<one-to-many>". En el cual debemos indicar de qu clase
son las entidades que estamos guardando en la lista (ya que este dato no puede ser obtenido usando reflexin):

<one-to-many class="hibernate.relaciones.unomuchos.modelo.Libro" />

Finalmente el mapeo de la relacin queda as:

<list name="libros" cascade="all-delete-orphan">


<key column="ID_PERSONA" />
<index column="ORDEN" />
<one-to-many class="hibernate.relaciones.unomuchos.modelo.Libro" />
</list>

Y el archivo de mapeo para la entidad Personacompleto as:

www.javatutoriales.com/2009/06/hibernate-parte-4-relaciones-uno-muchos.html

6/27

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 4: Relaciones / Uno a muchos

<hibernate-mapping>
<class name="hibernate.relaciones.unomuchos.modelo.Persona" table="PERSONAS">
<id name="id" column="ID_PERSONA">
<generator class="identity" />
</id>
<property name="nombre" />
<list name="libros" cascade="all-delete-orphan">
<key column="ID_PERSONA" />
<index column="ORDEN" />
<one-to-many class="hibernate.relaciones.unomuchos.modelo.Libro" />
</list>
</class>
</hibernate-mapping>

Para este ejemplo, usaremos la clase HibernateUtilque creamos en el primer tutorial de la serie.
Ahora colocaremos el siguiente cdigo (como siempre auto-explicatvo) como nuestro mtodo main:

www.javatutoriales.com/2009/06/hibernate-parte-4-relaciones-uno-muchos.html

7/27

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 4: Relaciones / Uno a muchos

public static void main(String[] args)


{
/*Primero creamos una persona y la asociamos con dos libros*/
Libro libro1 = new Libro();
libro1.setTitulo("20000 leguas de viaje submarino");
Libro libro2 = new Libro();
libro2.setTitulo("La maquina del tiempo");
Persona persona1 = new Persona();
persona1.setNombre("Persona que se eliminara");
persona1.addLibro(libro1);
persona1.addLibro(libro2);

/*Creamos una segunda persona, que sera eliminada, y la asociamos con otros
dos libros*/
Libro libro3 = new Libro();
libro3.setTitulo("El ingenioso hidalgo don Quijote de la Mancha");
Libro libro4 = new Libro();
libro4.setTitulo("La Galatea");
Persona persona2 = new Persona();
persona2.setNombre("Alex");
persona2.addLibro(libro3);
persona2.addLibro(libro4);

/*En la primer sesion guardamos las dos personas (los libros correspondientes
seran guardados en cascada*/
Session sesion = HibernateUtil.getSessionFactory().openSession();
sesion.beginTransaction();
sesion.persist(persona1);
sesion.persist(persona2);
sesion.getTransaction().commit();
sesion.close();

/*En la segunda sesion eliminamos la persona1 (los dos primeros libros seran
borrados en cascada)*/
sesion = HibernateUtil.getSessionFactory().openSession();
sesion.beginTransaction();
sesion.delete(persona1);
sesion.getTransaction().commit();
sesion.close();
}

Segn el cdigo anterior en la base de datos debera quedar una Persona, la segunda que guardamos ("Alex"), con sus dos libros
respectivos. Comprobemos que esto es verdad.

Podemos ver que efectivamente el resultado es el esperado ^-^.


Ahora veamos cmo hacer lo mismo pero usando anotaciones.

3.2 RELACIONES UNO A MUCHOS UNIDIRECCIONALES CON ANOTACIONES


Recuerden que pasa usar anotaciones debemos agregar al proyecto la biblioteca "HibernateAnotaciones" que creamos en el
segundo tutorial.
Las anotaciones (as como los archivos de configuracin) de ambas clases (omitiendo la que indica la relacin) sern las mismas que

www.javatutoriales.com/2009/06/hibernate-parte-4-relaciones-uno-muchos.html

8/27

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 4: Relaciones / Uno a muchos


expliqu en el segundo tutorial de esta serie, quedan de la siguiente forma:

@Entity
public class Libro implements Serializable
{
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private long id;
private String titulo;
public Libro()
{
}
public long getId()
{
return id;
}
protected void setId(long id)
{
this.id = id;
}
public String getTitulo()
{
return titulo;
}
public void setTitulo(String titulo)
{
this.titulo = titulo;
}
}

Y esta es la de la clase Persona:

www.javatutoriales.com/2009/06/hibernate-parte-4-relaciones-uno-muchos.html

9/27

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 4: Relaciones / Uno a muchos

@Entity
public class Persona implements Serializable
{
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private long id;
private String nombre;
private List<Libro> libros = new ArrayList<Libro>();
public Persona()
{
}
public long getId()
{
return id;
}
protected void setId(long id)
{
this.id = id;
}
public String getNombre()
{
return nombre;
}
public void setNombre(String nombre)
{
this.nombre = nombre;
}
public List getLibros()
{
return libros;
}
public void setLibros(List libros)
{
this.libros = libros;
}
public void addLibro(Libro libro)
{
this.libros.add(libro);
}
}

Ahora explicar la anotacin que usaremos para indicar la relacin. Esta anotacin es "@OneToMany" y la colocamos en el atributo de
tipo coleccin de Libros (en este caso la clase Personaser la duea de la relacin ya que es la nica que est consciente de esta).
Igual que lo hicimos en la anotacin "@OneToOne" aqui definiremos qu operaciones sern realizadas en cascada. Adems tambin
podemos indicar el tipo de "fetch" o recuperacin que tendr la coleccin. Explico: solo existen dos tipo de recuperacin: tardado
(lazy)e inmediato (eager). Si decidimos que la recuperacin sea "lazy" entonces las entidades relacionadas (los Libros de la
coleccin) no sern recuperados de la base de datos al momento que se recupera la Persona duea, sino hasta que se usen estos
elementos (siempre y cuando estemos dentro de una transaccin). Si la recuperacin es "eager" entonces los Libros relacionados se
recuperarn al mismo tiempo que la Personaduea. En este caso yo usar un fetch de tipo eager.
Al final la relacin queda de esta forma:

@OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER)
private List<Libro> libros = new ArrayList<Libro>();

Y la clase Persona, con todas sus anotaciones, as:

www.javatutoriales.com/2009/06/hibernate-parte-4-relaciones-uno-muchos.html

10/27

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 4: Relaciones / Uno a muchos

@Entity
public class Persona implements Serializable
{
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private long id;
private String nombre;
@OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER)
private List&ltLibro> libros = new ArrayList<Libro>();
public Persona()
{
}
public long getId()
{
return id;
}
protected void setId(long id)
{
this.id = id;
}
public String getNombre()
{
return nombre;
}
public void setNombre(String nombre)
{
this.nombre = nombre;
}
public List getLibros()
{
return libros;
}
public void setLibros(List libros)
{
this.libros = libros;
}
public void addLibro(Libro libro)
{
this.libros.add(libro);
}
}

Y listo, con esto ya tenemos una relacin Uno a Muchos unidireccional con la Personacomo duea de la relacin y varios Libros
como entidad inversa.
No olviden que debemos colocar en el archivo de configuracin de Hibernate estas clases:

<mapping class="hibernate.relaciones.unomuchos.anotaciones.modelo.Libro" />


<mapping class="hibernate.relaciones.unomuchos.anotaciones.modelo.Persona" />

Usaremos la clase HibernateUtilque creamos en el segundo tutorial de la serie para implementar el cdigo de prueba y el siguiente
cdigo dentro la clase main:

www.javatutoriales.com/2009/06/hibernate-parte-4-relaciones-uno-muchos.html

11/27

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 4: Relaciones / Uno a muchos

public static void main(String[] args)


{
/*Primero creamos una persona y la asociamos con dos libros*/
Libro libro1 = new Libro();
libro1.setTitulo("20000 leguas de viaje submarino");
Libro libro2 = new Libro();
libro2.setTitulo("La maquina del tiempo");
Persona persona1 = new Persona();
persona1.setNombre("Persona que se eliminara");
persona1.addLibro(libro1);
persona1.addLibro(libro2);
/*Creamos una segunda persona, que sera eliminada, y la asociamos
con otros dos libros*/
Libro libro3 = new Libro();
libro3.setTitulo("El ingenioso hidalgo don Quijote de la Mancha");
Libro libro4 = new Libro();
libro4.setTitulo("La Galatea");
Persona persona2 = new Persona();
persona2.setNombre("Alex");
persona2.addLibro(libro3);
persona2.addLibro(libro4);
/*En la primer sesion guardamos las dos personas (los libros
correspondientes seran guardados en cascada*/
Session sesion = HibernateUtil.getSessionFactory().openSession();
sesion.beginTransaction();
sesion.persist(persona1);
sesion.persist(persona2);
sesion.getTransaction().commit();
sesion.close();
/*En la segunda sesion eliminamos la persona1 (los dos primeros
libros seran borrados en cascada)*/
sesion = HibernateUtil.getSessionFactory().openSession();
sesion.beginTransaction();
sesion.delete(persona1);
sesion.getTransaction().commit();
sesion.close();
}

Segn el cdigo anterior, debera haber quedado una sola Personaen la base de datos con sus dos Libros relacionados, vemos que
esto sea as:

Como podemos ver, todo ha salido bien ^-^. Ahora podemos pasar a ver cmo funciona la relacin Uno a Muchos bidireccional.

4 - Relaciones Uno a Muchos Bidireccionales


Las relaciones bidireccionales son muy parecidas a las unidireccionales, con la diferencia que el lado inverso de la relacin tambin
sabe de esta, por lo que tiene una referencia al dueo. Veamos esto con un ejemplo para que quede ms claro. Nuevamente
comenzaremos con un ejemplo usando archivos de mapeo y posteriormente usaremos anotaciones.

4.1 RELACIONES UNO A MUCHOS BIDIRECCIONALES CON ARCHIVOS DE MAPEO


Modificaremos un poco nuestra clase "Libro" para agregar una referencia a la "Persona" (con sus correspondientes setters y
getters):

www.javatutoriales.com/2009/06/hibernate-parte-4-relaciones-uno-muchos.html

12/27

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 4: Relaciones / Uno a muchos

private Persona persona;


public Persona getPersona()
{
return persona;
}
public void setPersona(Persona persona)
{
this.persona = persona;
}

Por lo que la clase queda de la siguiente forma:

public class Libro


{
private long id;
private String titulo;
private Persona persona;
public Libro()
{
}
public long getId()
{
return id;
}
protected void setId(long id)
{
this.id = id;
}
public String getTitulo()
{
return titulo;
}
public void setTitulo(String titulo)
{
this.titulo = titulo;
}
public Persona getPersona()
{
return persona;
}
public void setPersona(Persona persona)
{
this.persona = persona;
}
}

La clase "Persona" queda intacta.


Ahora modificaremos el archivo "Libro.hbm.xml" para que refleje los campos que acabamos de realizar. Pero primero veamos como
quedo el archivo de mapeo de la ("PersonaPersona.hbm.xml"):

www.javatutoriales.com/2009/06/hibernate-parte-4-relaciones-uno-muchos.html

13/27

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 4: Relaciones / Uno a muchos

<hibernate-mapping>
<class name="hibernate.relaciones.unomuchos.modelo.Persona" table="PERSONAS">
<id name="id" column="ID_PERSONA">
<generator class="identity" />
</id>
<property name="nombre" />
<list name="libros" cascade="all-delete-orphan">
<key column="ID_PERSONA" />
<index column="ORDEN" />
<one-to-many class="hibernate.relaciones.unomuchos.modelo.Libro" />
</list>
</class>
</hibernate-mapping>

Como podemos ver la relacin de Personaa Libros esta mapeada usando el elemento "one-to-many" (una Persona puede tener
muchos Libros), por lo que para indicar la relacin de Libros a Personausamos el elemento contrario: "many-to-one" (muchos
Libros pertenecen a una Persona).
En este elemento debemos indicar el nombre del elemento que representa la relacin (en la clase Libro), que en este caso es
"persona", y el nombre de la columna donde se almacena el identificador de la Persona ("ID_PERSONA"). Por lo que el elemento
queda as:

<many-to-one name="persona" column="ID_PERSONA" />

Y al final el archivo "Libro.hbm.xml" completo as:

<hibernate-mapping>
<class name="hibernate.relaciones.unomuchos.modelo.Libro" table="LIBROS">
<id name="id" column="id">
<generator class="identity" />
</id>
<property name="titulo" />
<many-to-one name="persona" column="ID_PERSONA" />
</class>
</hibernate-mapping>

Y eso es todo ^-^. Probmoslo usando el mismo cdigo que ya tenamos en la clase Main:

www.javatutoriales.com/2009/06/hibernate-parte-4-relaciones-uno-muchos.html

14/27

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 4: Relaciones / Uno a muchos

public static void main(String[] args)


{
/*Primero creamos una persona y la asociamos con dos libros*/
Libro libro1 = new Libro();
libro1.setTitulo("20000 leguas de viaje submarino");
Libro libro2 = new Libro();
libro2.setTitulo("La maquina del tiempo");
Persona persona1 = new Persona();
persona1.setNombre("Persona que se eliminara");
persona1.addLibro(libro1);
persona1.addLibro(libro2);
/*Creamos una segunda persona, que sera eliminada, y la asociamos con otros dos libros*/
Libro libro3 = new Libro();
libro3.setTitulo("El ingenioso hidalgo don Quijote de la Mancha");
Libro libro4 = new Libro();
libro4.setTitulo("La Galatea");
Persona persona2 = new Persona();
persona2.setNombre("Alex");
persona2.addLibro(libro3);
persona2.addLibro(libro4);
/*En la primer sesion guardamos las dos personas (los libros correspondientes seran guardados
en cascada*/
Session sesion = HibernateUtil.getSessionFactory().openSession();
sesion.beginTransaction();
sesion.persist(persona1);
sesion.persist(persona2);
sesion.getTransaction().commit();
sesion.close();
/*En la segunda sesion eliminamos la persona1 (los dos primeros libros seran borrados en casca
da)*/
sesion = HibernateUtil.getSessionFactory().openSession();
sesion.beginTransaction();
sesion.delete(persona1);
sesion.getTransaction().commit();
sesion.close();
}

Ahora comprobemos que en la base de datos solo quedan los datos de la persona2, junto con sus libroscorrespondientes:

Como podemos ver, todo ha salido bien ^-^.


Para terminar este tutorial veamos cmo trabajar con relaciones Uno a Muchos usando anotaciones.

4.2 RELACIONES UNO A MUCHOS BIDIRECCIONALES CON ANOTACIONES


Como ya tenamos una relacin uno a muchos unidireccional con anotaciones, representada en el atributo "libros" de la clase
"Persona". Siendo la clase Personala nica que esta consciente de la relacin (por eso es unidireccional).
Para transformar esta relacin en bidireccional lo nico que debemos hacer es agregar un atributo que represente la relacin con la
clase "Persona" en la clase "Libro". De la misma forma que ocurre cuando usamos archivos de mapeo: Como la relacin uno a
muchos est representada en la clase "Persona" usando la anotacin "@OneToMany" (una Personapuede tener muchos Libros), en
el lado inverso de la relacin debe usarse la anotacin inversa "@ManyToOne" (muchos Libros pueden pertenecer a una Persona).
Esta anotacin es un poco distinta a la anotacin "@OneToOne" que vimos anteriormente. En este caso es importante quin es el dueo
de la relacin, ya que es el dueo quien determina cmo es que el motor de persistencia hace actualizaciones en la base de datos.
En el caso de las relaciones bidireccionales, usando anotaciones, el dueo SIEMPRE es el lado muchos (esta es una regla). Por lo que
en este caso el dueo de la relacin es la clase "Libro".
El lado inverso debe saber cul es el nombre que lo representa en el lado dueo (esto se aclarar en el ejemplo). Para esto se usa el

www.javatutoriales.com/2009/06/hibernate-parte-4-relaciones-uno-muchos.html

15/27

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 4: Relaciones / Uno a muchos


elemento "mappedBy".
Para ver cmo funciona lo dicho vayamos al ejemplo que tenamos. Primero modificaremos la clase "Libro" para agregar el atributo de
tipo Personaque representar la relacin (recuerden que debemos usar la aniotacin "@ManyToOne"):

@ManyToOne
private Persona persona;

Y eso es todo lo que hay que modificar en la clase Libro. Como ven es un cambio muy pequeo. Ahora veamos la clase Persona.
Hace unos momentos dije que la clase Libroes la clase duea de la relacin y la clase Personaes la clase inversa. Tambin dije
que la clase inversa debe indicar en la anotacin que representa la relacin el nombre con el que el lado dueo la representa (que en este
caso es "persona") y que esto se hace en el elemento "mappedBy" de la anotacin. Por lo que la relacin queda representada en la
clase "Persona" de la siguiente forma:

@OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER, mappedBy="persona")


private List libros = new ArrayList();

Y listo ^-^. Con estos pequeos cambios ya tenemos una relacin bidireccional. Al final la clase Personaqueda de la siguiente forma:

@Entity
public class Persona implements Serializable
{
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private long id;
private String nombre;
@OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER, mappedBy="persona")
private List libros = new ArrayList();
public Persona()
{
}
public long getId()
{
return id;
}
protected void setId(long id)
{
this.id = id;
}
public String getNombre()
{
return nombre;
}
public void setNombre(String nombre)
{
this.nombre = nombre;
}
public List getLibros()
{
return libros;
}
public void setLibros(List libros)
{
this.libros = libros;
}
public void addLibro(Libro libro)
{
this.libros.add(libro);
}
}

Y la clase Libroas:

www.javatutoriales.com/2009/06/hibernate-parte-4-relaciones-uno-muchos.html

16/27

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 4: Relaciones / Uno a muchos

@Entity
public class Libro implements Serializable
{
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private long id;
private String titulo;
@ManyToOne
private Persona persona;
public Libro()
{
}
public long getId()
{
return id;
}
protected void setId(long id)
{
this.id = id;
}
public String getTitulo()
{
return titulo;
}
public void setTitulo(String titulo)
{
this.titulo = titulo;
}
public Persona getPersona()
{
return persona;
}
public void setPersona(Persona persona)
{
this.persona = persona;
}
}

Probemos que todo funciona correctamente usando el cdigo que tenamos anteriormente en la clase Main:

www.javatutoriales.com/2009/06/hibernate-parte-4-relaciones-uno-muchos.html

17/27

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 4: Relaciones / Uno a muchos

public static void main(String[] args)


{
/*Primero creamos una persona y la asociamos con dos libros*/
Libro libro1 = new Libro();
libro1.setTitulo("20000 leguas de viaje submarino");
Libro libro2 = new Libro();
libro2.setTitulo("La maquina del tiempo");
Persona persona1 = new Persona();
persona1.setNombre("Persona que se eliminara");
persona1.addLibro(libro1);
persona1.addLibro(libro2);
libro1.setPersona(persona1);
libro2.setPersona(persona1);

/*Creamos una segunda persona, que sera eliminada, y la asociamos con otros dos libros*/
Libro libro3 = new Libro();
libro3.setTitulo("El ingenioso hidalgo don Quijote de la Mancha");
Libro libro4 = new Libro();
libro4.setTitulo("La Galatea");
Persona persona2 = new Persona();
persona2.setNombre("Alex");
persona2.addLibro(libro3);
persona2.addLibro(libro4);
libro3.setPersona(persona2);
libro4.setPersona(persona2);

/*En la primer sesion guardamos las dos personas (los libros correspondientes seran guardados
en cascada*/
Session sesion = HibernateUtil.getSessionFactory().openSession();
sesion.beginTransaction();
sesion.persist(persona1);
sesion.persist(persona2);
sesion.getTransaction().commit();
sesion.close();

/*En la segunda sesion eliminamos la persona1 (los dos primeros libros seran borrados en casca
da)*/
sesion = HibernateUtil.getSessionFactory().openSession();
sesion.beginTransaction();
sesion.delete(persona1);
sesion.getTransaction().commit();
sesion.close();
}

Nuevamente solo deben haber quedado en la base de datos los datos de la persona2y sus librosrelacionados. Comprobemos que
efectivamente esto es as:

Como podemos ver todo ha salido como esperbamos ^-^.


Bien, esto es todo lo que respecta a las relaciones uno a muchos. Con este tutorial ya llevamos 4 de los 7 tipos de relaciones que
podemos tener en Hibernate. En los siguientes dos tutoriales veremos los 3 tipos restantes.
Cualquier duda, comentario, o sugerencia por favor no duden en colocarlo.
Saludos.
Descarga los archivos de este tutorial desde aqu:

www.javatutoriales.com/2009/06/hibernate-parte-4-relaciones-uno-muchos.html

18/27

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 5: Relaciones / Muchos a Uno


Compartir

Ms

Siguiente blog

Tutoriales de Programacion Java


Blog dedicado a temas de programacin actuales usando el lenguaje de programacin Java y las ltimas versiones de sus APIs y Herramientas.
Pgina principal

Pgina de Concursos

Tutoriales UPAO 2010

Presentaciones Capacitacin

DOMINGO, 2 DE AGOSTO DE 2009

Hibernate - Parte 5: Relaciones / Muchos a Uno

DONACIONES

Ya hemos visto, en los tutoriales anteriores, cmo generar 4 de los 7 tipos de relaciones que podemos crear con Hibernate.
En esta ocasin veremos cmo crear relaciones uno a muchos unidireccionales (ya que, como dije en el tercer tutorial, las relaciones uno
a muchos bidireccionales son iguales a las relaciones muchos a uno bidireccionales ^-^).
Lo primero que haremos es crear un proyecto en NetBeans (men "File -> New Project... -> Java -> Java
Application"). Le damos un nombre y una ubicacin al proyecto y nos aseguramos de que las opciones "Create Main Class" y
"Set as Main Project" estn habilitadas. Presionamos el botn "Finish" y veremos aparecer nuestra clase en el editor."Main".
Agregamos la biblioteca de Hibernate, que creamos en el primer tutorial de la serie. Hacemos clic derecho en el nodo "Libraries" del
proyecto. En el men contextual que se abre seleccionamos la opcin "Add Library...":

JAVA TUTORIALES EN FACEBOOK

Java Tutoriales
Me gusta

Java Tutoriales

Amigo programador,
ests todo el da pica
cdigo, escucha esta
recomendaciones sl
hechas para ti..... q
esto?... Gracias Jorg
Rubira....

No olviden poner la
sentencia where al ha
un borraro en la base
datos..

En la ventana que se abre seleccionamos la biblioteca "Hibernate":

http://www.youtube.c
watch?v=i_cVJgIz_Cs
A 7895 personas les gusta

Plug-in social de Facebook

Presionamos el botn "Add Library" para que la biblioteca se agregue a nuestro proyecto. Aprovechamos tambin para agregar el
conector de MySQL. Debemos tener los siguientes archivos en nuestro proyecto:

Ahora creamos dos paquetes, uno con el nombre "modelo", que contendr las clases entidades, y otro con el nombre "mapeos" que

www.javatutoriales.com/2009/08/hibernate-parte-5-relaciones-muchos-uno_02.html

1/11

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 5: Relaciones / Muchos a Uno


contendr los archivos de mapeo XML. Hacemos clic derecho en el nodo del paquete que se cre al generar el proyecto. En el men
contextual que se abre seleccionamos la opcin "New -> Java Package..." y creamos los dos paquetes.

Que deben quedar as:

SEGUIDORES

Participar en este sitio


Google Friend Connect

Miembros (173) Ms
Aprovecharemos para crear nuestro archivo de configuracin de Hibernate, "hibernate.cfg.xml", el cual ser muy parecido al del
primer tutorial:

<!DOCTYPE hibernate-configuration PUBLIC


"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<!-- parametros para la conexion a la base de datos -->
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="connection.url">jdbc:mysql://localhost/hibernaterelaciones</property>
<property name="connection.username">usuario</property>
<property name="connection.password">password</property>

Ya eres miembro? Iniciar sesin

ARCHIVO DEL BLOG

2012 (2)
2011 (11)
2010 (10)
2009 (22)
septiembre (2)

<!-- Configuracion del pool interno -->


<property name="connection.pool_size">1</property>
<!-- Dialecto de la base de datos -->
<property name="dialect">org.hibernate.dialect.MySQL5Dialect</property>

agosto (2)

Hibernate - Parte 6: Relacione


a Muchos

Hibernate - Parte 5: Relacione


a Uno

<!-- Otras propiedades importantes -->


<property name="show_sql">true</property>
<property name="hbm2ddl.auto">create-drop</property>

julio (1)

<!-- Aqui iran los archivos de mapeo -->

abril (5)

junio (3)
mayo (2)

marzo (2)

</session-factory>
</hibernate-configuration>

febrero (2)
enero (3)

Para los ejercicios usaremos una base de datos llamada "hibernaterelaciones", en MySQL.
Nota: Yo usar dos proyectos, uno para usar archivos de m apeo y otro para usar anotaciones y que el cdigo de am bos no se m ezcle.

Pues bien, comencemos con este quinto tutorial:


Las relaciones muchos a uno en realidad son muy parecidas a las relaciones uno a muchos, con la excepcin de que, en el caso de las
relaciones unidireccionales, solo el lado muchos de la relacin sabe de la existencia de esta.
Es como si tuviramos una clase Televidente, que tiene una relacin muchos a uno unidireccional con una clase

www.javatutoriales.com/2009/08/hibernate-parte-5-relaciones-muchos-uno_02.html

2/11

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 5: Relaciones / Muchos a Uno


CadenaTelevisiva. Donde el Televidente(el lado muchos de la relacin) tiene una CadenaTelevisivafavorita (el lado uno de
la relacin). Pero CadenaTelevisivano tiene una referencia hacia cada uno de sus televidentes (desde los Televidentespodemos
llegar a una CadenaTelevisiva, pero desde la CadenaTelevisivano podemos llegar a los Televidentes).
Comencemos con los ejemplos para que esto quede ms claro.

File APIs for


Programmers
www.aspose.com

5 - Relaciones Muchos a Uno Unidireccionales


Primero crearemos la clase CadenaTelevisiva, dentro del paquete modelo. Esta ser una clase muy simple y solamente tendr
dos atributos: idy nombre. La clase CadenaTelevisivaqueda as:

DOC, XLS, PPT, PDF,


MSG and more .NET,
Java, SSRS &
SharePoint

public class CadenaTelevisiva


{
private long id;
private String nombre;
public CadenaTelevisiva()
{
}
public long getId()
{
return id;
}
protected void setId(long id)
{
this.id = id;
}
public String getNombre()
{
return nombre;
}
public void setNombre(String nombre)
{
this.nombre = nombre;
}
}

DATOS PERSONALES

Alex

Programador Java con algunos


experiencia en mltiples poyec
mltiples APIs y herramientas d
compartir experiencias con el
programadores.
Ver todo mi perfil

Como dije antes: esta clase no tiene ninguna referencia a la clase Televidente(aunque si fuera una relacin bidireccional debera
tener un arreglo de Televidentes), ya que ser esta ltima la que este consciente de la relacin.
La clase Televidente, tambin colocada en el paquete modelo, queda de esta forma:

www.javatutoriales.com/2009/08/hibernate-parte-5-relaciones-muchos-uno_02.html

3/11

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 5: Relaciones / Muchos a Uno

public class Televidente


{
private long id;
private String nombre;
private CadenaTelevisiva cadenaFavorita;
public Televidente()
{
}
public CadenaTelevisiva getCadenaFavorita()
{
return cadenaFavorita;
}
public void setCadenaFavorita(CadenaTelevisiva cadenaFavorita)
{
this.cadenaFavorita = cadenaFavorita;
}
public long getId()
{
return id;
}
protected void setId(long id)
{
this.id = id;
}
public String getNombre()
{
return nombre;
}
public void setNombre(String nombre)
{
this.nombre = nombre;
}
}

Como podemos ver, en este caso Televidente tiene una referencia a CadenaTelevisiva, la cual usa el identificador
cadenaFavorita.
Ahora veamos cmo representar esta relacin. Comenzaremos, como siempre haciendo uso de archivos de mapeo:

5.1 RELACIONES MUCHOS A UNO UNIDIRECCIONALES CON ARCHIVOS DE MAPEO


Creamos un nuevo documento XML en el paquete mapeos. Le damos el nombre CadenaTelevisiva.hbm (el asistente se encargar
de colocar el .xml):

Presionamos el botn Next > e indicamos que queremos crear un documento XML bien formado (la primer opcin) y presionamos el
botn Finish.
Eliminamos en el contenido del archivo creado y lo reemplazamos con el siguiente:

www.javatutoriales.com/2009/08/hibernate-parte-5-relaciones-muchos-uno_02.html

4/11

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 5: Relaciones / Muchos a Uno

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="hibernate.relaciones.modelos.CadenaTelevisiva" table="CADENAS_TELEVISIVAS">
</class>
</hibernate-mapping>

El mapeo de la clase CadenaTelevisivael similar al que expliqu en el primer tutorial de la serie y, al final, queda de la siguiente
forma:

<hibernate-mapping>
<class name="hibernate.relaciones.modelos.CadenaTelevisiva" table="CADENAS_TELEVISIVAS">
<id name="id">
<generator class="identity" />
</id>
<property name="nombre" />
</class>
</hibernate-mapping>

Ahora crearemos el mapeo de la clase Televidente, llamado Televidente.hbm.xml en el paquete mapeos, de la misma forma
que lo hicimos para CadenaTelevisiva. El mapeo, excluyendo el elemento que representa la relacin, debe estar de esta forma:

<hibernate-mapping>
<class name="hibernate.relaciones.modelos.Televidente" table="TELEVIDENTES">
<id name="id">
<generator class="identity" />
</id>
<property name="nombre" />
</class>
</hibernate-mapping>

Para representar la relacin uno a muchos usamos el elemento <many-to-one>, que ya habamos usado en el tutorial anterior. En
esta etiqueta colocamos, haciendo uso de se atributo name, el nombre de la propiedad de la clase Televidenteque hace referencia a
la CadenaTelevisiva, que en este caso es cadenaFavorita:

<many-to-one name="cadenaFavorita" />

Por lo que, finalmente, el mapeo de la clase Televidente, queda de la siguiente forma:

www.javatutoriales.com/2009/08/hibernate-parte-5-relaciones-muchos-uno_02.html

5/11

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 5: Relaciones / Muchos a Uno

<hibernate-mapping>
<class name="hibernate.relaciones.modelos.Televidente" table="TELEVIDENTES">
<id name="id">
<generator class="identity" />
</id>
<property name="nombre" />
<many-to-one name="cadenaFavorita" />
</class>
</hibernate-mapping>

Ahora probemos que la configuracin funciona. Para que la prueba sea ms fcil usaremos la clase HibernateUtilque creamos en el
primer tutorial.
No olviden que, adems, debemos colocar en el archivo hibernate.cfg.xmllas indicaciones de dnde estn los archivos de mapeo
que acabamos de crear:

<mapping resource="hibernate/relaciones/mapeos/CadenaTelevisiva.hbm.xml" />


<mapping resource="hibernate/relaciones/mapeos/Televidente.hbm.xml" />

En la prueba crearemos tres objetos CadenaTelevisiva, cadena 1, cadena 2, y cadena 3, respectivamente, y dos objetos
Televidente, televidente 1, y televidente 2, y relacionaremos la cadena 1con el televidente 1y la cadena 3con el
televidente 2.
Veamos cmo queda el cdigo en el mtodo mainde nuestra clase Main:

public static void main(String[] args)


{
/* Creamos los tres objetos CadenaTelevisiva */
CadenaTelevisiva cadena1 = new CadenaTelevisiva();
cadena1.setNombre("Cadena 1");
CadenaTelevisiva cadena2 = new CadenaTelevisiva();
cadena2.setNombre("Cadena 2");
CadenaTelevisiva cadena3 = new CadenaTelevisiva();
cadena3.setNombre("Cadena 3");

/* Guardamos estos tres objetos CadenaTelevisiva en la base de datos */


Session sesion = HibernateUtil.getSessionFactory().openSession();
sesion.beginTransaction();
sesion.save(cadena1);
sesion.save(cadena2);
sesion.save(cadena3);
sesion.getTransaction().commit();
sesion.close();

/* Creamos dos objetos Televidente */


Televidente televidente1 = new Televidente();
televidente1.setNombre("Televidente 1");
televidente1.setCadenaFavorita(cadena1);
Televidente televidente2 = new Televidente();
televidente2.setNombre("Televidente 2");
televidente2.setCadenaFavorita(cadena3);
/* Guardamos los dos objetos Televidente en la base de Datos */
sesion = HibernateUtil.getSessionFactory().openSession();
sesion.beginTransaction();
sesion.save(televidente1);
sesion.save(televidente2);
sesion.getTransaction().commit();
sesion.close();
}

Listo, esto es todo lo que necesitamos para probar nuestro ejemplo.

www.javatutoriales.com/2009/08/hibernate-parte-5-relaciones-muchos-uno_02.html

6/11

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 5: Relaciones / Muchos a Uno


Ahora veamos que, en la base de datos, estn las 3 cadenas televisivas y los 2 televidentes que creamos y que, las referencias de los
televidentes a las cadenas estn correctos:

Como podemos ver, los datos se han guardado de forma correcta ^-^.
Ahora veamos cmo podemos hacer lo mismo usando anotaciones.

5.2 RELACIONES MUCHOS A UNO UNIDIRECCIONALES ANOTACIONES


Recuerden que pasa usar anotaciones debemos agregar al proyecto la biblioteca "HibernateAnotaciones" que creamos en el
segundo tutorial.
Las anotaciones (as como los archivos de configuracin) de ambas clases (omitiendo la que indica la relacin) sern las mismas que
expliqu en el segundo tutorial de esta serie, quedan de la siguiente forma.
Esta es la clase CadenaTelevisiva:

@Entity
public class CadenaTelevisiva implements Serializable
{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
private String nombre;
public CadenaTelevisiva()
{
}
public long getId()
{
return id;
}
protected void setId(long id)
{
this.id = id;
}
public String getNombre()
{
return nombre;
}
public void setNombre(String nombre)
{
this.nombre = nombre;
}
}

Y esta es la clase Televidente:

www.javatutoriales.com/2009/08/hibernate-parte-5-relaciones-muchos-uno_02.html

7/11

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 5: Relaciones / Muchos a Uno

@Entity
public class Televidente implements Serializable
{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
private String nombre;
private CadenaTelevisiva cadenaFavorita;
public Televidente()
{
}
public CadenaTelevisiva getCadenaFavorita()
{
return cadenaFavorita;
}
public void setCadenaFavorita(CadenaTelevisiva cadenaFavorita)
{
this.cadenaFavorita = cadenaFavorita;
}
public long getId()
{
return id;
}
protected void setId(long id)
{
this.id = id;
}
public String getNombre()
{
return nombre;
}
public void setNombre(String nombre)
{
this.nombre = nombre;
}
}

Para representar la relacin usamos la anotacin @ManyToOne, que tambin vimos en el tutorial anterior. As que el atributo
cadenaFavoritaqueda anotado de esta forma:

@ManyToOne
private CadenaTelevisiva cadenaFavorita;

Y la clase Televidentequeda, por lo tanto, de esta forma:

www.javatutoriales.com/2009/08/hibernate-parte-5-relaciones-muchos-uno_02.html

8/11

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 5: Relaciones / Muchos a Uno

@Entity
public class Televidente implements Serializable
{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
private String nombre;
@ManyToOne
private CadenaTelevisiva cadenaFavorita;
public Televidente()
{
}
public CadenaTelevisiva getCadenaFavorita()
{
return cadenaFavorita;
}
public void setCadenaFavorita(CadenaTelevisiva cadenaFavorita)
{
this.cadenaFavorita = cadenaFavorita;
}
public long getId()
{
return id;
}
protected void setId(long id)
{
this.id = id;
}
public String getNombre()
{
return nombre;
}
public void setNombre(String nombre)
{
this.nombre = nombre;
}
}

Ahora usaremos la clase HibernateUtil que creamos en el segundo tutorial para comprobar que todo funcione correctamente. No
olviden agregar al archivo hibernate.cfg.xmlla ubicacin de las clases que acabamos de anotar:

<mapping class="hibernate.relaciones.muchos.uno.anotaciones.modelo.CadenaTelevisiva" />


<mapping class="hibernate.relaciones.muchos.uno.anotaciones.modelo.Televidente" />

En este ejemplo haremos lo mismo que hace unos instantes:


Crearemos tres objetos CadenaTelevisiva, cadena 1, cadena 2, y cadena 3, respectivamente, y dos objetos Televidente,
televidente 1, y televidente 2, y relacionaremos la cadena 1con el televidente 1y la cadena 3con el televidente
2.
Para lo cual colocaremos el siguiente cdigo en el mtodo mainde nuestra clase Main:

www.javatutoriales.com/2009/08/hibernate-parte-5-relaciones-muchos-uno_02.html

9/11

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 5: Relaciones / Muchos a Uno

public static void main(String[] args)


{
/* Creamos los tres objetos CadenaTelevisiva */
CadenaTelevisiva cadena1 = new CadenaTelevisiva();
cadena1.setNombre("Cadena 1");
CadenaTelevisiva cadena2 = new CadenaTelevisiva();
cadena2.setNombre("Cadena 2");
CadenaTelevisiva cadena3 = new CadenaTelevisiva();
cadena3.setNombre("Cadena 3");

/* Guardamos estos tres objetos CadenaTelevisiva en la base de datos */


Session sesion = HibernateUtil.getSessionFactory().openSession();
sesion.beginTransaction();
sesion.save(cadena1);
sesion.save(cadena2);
sesion.save(cadena3);
sesion.getTransaction().commit();
sesion.close();

/* Creamos dos objetos Televidente */


Televidente televidente1 = new Televidente();
televidente1.setNombre("Televidente 1");
televidente1.setCadenaFavorita(cadena1);
Televidente televidente2 = new Televidente();
televidente2.setNombre("Televidente 2");
televidente2.setCadenaFavorita(cadena3);
/* Guardamos los dos objetos Televidente en la base de Datos */
sesion = HibernateUtil.getSessionFactory().openSession();
sesion.beginTransaction();
sesion.save(televidente1);
sesion.save(televidente2);
sesion.getTransaction().commit();
sesion.close();
}

Ahora comprobemos que en la base de datos tengamos las 3 cadenas televisivas y los 2 televidentes:

Como podemos observar todo ha salido como lo esperbamos ^-^.


Esto es todo con respecto a las relaciones unidireccionales. Como les deca, las relaciones Muchos a Uno bidireccionales, son igual
a las relaciones Uno a Muchos bidireccionales que vimos en el tutorial anterior por lo que hemos terminado con este tutorial.
Si tienen alguna duda, comentario o sugerencia no duden en preguntar.
Saludos y gracias.
Descarga los archivos de este tutorial desde aqu:
Hibernate Relaciones Muchos a Uno con archivos de Mapeo
Hibernate Relaciones Muchos a Uno con Anotaciones

Entradas Relacionadas:
Parte 1: Persistiendo Objetos Simples usando Mapeos en XML
Parte 2: Persistiendo Objetos Simples usando Anotaciones (Metadatos)
Parte 3: Relaciones / Uno a uno
Parte 4: Relaciones / Uno a muchos
Parte 6: Relaciones / Muchos a Muchos
Parte 7: HQL Primera Parte
Parte 8: HQL Segunda Parte
Parte 9: Parmetros en HQL
Parte 10: Herencia

www.javatutoriales.com/2009/08/hibernate-parte-5-relaciones-muchos-uno_02.html

10/11

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 6: Relaciones / Muchos a Muchos


Compartir

Ms

Siguiente blog

Tutoriales de Programacion Java


Blog dedicado a temas de programacin actuales usando el lenguaje de programacin Java y las ltimas versiones de sus APIs y Herramientas.
Pgina principal

Pgina de Concursos

Tutoriales UPAO 2010

Presentaciones Capacitacin

LUNES, 24 DE AGOSTO DE 2009

Hibernate - Parte 6: Relaciones / Muchos a Muchos

DONACIONES

En ocasiones necesitamos relacionar muchas entidades de un tipo con muchas entidades de otro tipo. Este tipo de relaciones es muy
comn cuando trabajamos con bases de datos relacionales, por eso es importante saber cmo trabajar con ellas.
En este ltimo tutorial de la serie veremos cmo crear los ltimos dos tipos de relaciones el framework de Hibernate: relaciones muchos
a muchos unidireccionales y bidireccionales.
Este tipo de relaciones es especial ya que, como mencione antes, tenemos que muchos registros de la entidad tipo A estn
relacionadas con muchos registros de la entidad tipo B.
Normalmente los registros en base de datos se relacionan usando una llave fornea de una tabla con el identificador de otra tabla,
como en la siguiente imagen:

Sin embargo, como en las relaciones muchos a muchos necesitamos relacionar muchos registros de la entidad A, con muchos
registros de la entidad B, y es por esto que NO nos basta con una llave fornea en una de las tablas ya que, por ejemplo, el registro con
ID 1 de la entidad A podra estar relacionado con los registros con IDs 1, 3, y 5 de la entidad B (hasta aqu sera una relacin uno a
muchos). Sin embargo el registro 3 de la entidad Bpuede estas relacionado con los registros 1, 2, y 4 de la entidad A, como lo muestra la
siguiente figura:

Esto no puede ser logrado utilizando simplemente llaves forneas en las tablas de las entidades Ay B. En estos casos se utiliza una
tercera tabla conocida como tabla de join, o tabla de enlace, o tabla de unin.

JAVA TUTORIALES EN FACEBOOK

Java Tutoriales
Me gusta

Java Tutoriales

Amigo programador,
ests todo el da pica
cdigo, escucha esta
recomendaciones sl
hechas para ti..... q
esto?... Gracias Jorg
Rubira....

No olviden poner la
sentencia where al ha
un borraro en la base
datos..

http://www.youtube.c
watch?v=i_cVJgIz_Cs
A 7895 personas les gusta

Plug-in social de Facebook

Esta tercera tabla lo nico que hace es mantener las relaciones de las entidades Aque estn relacionadas con las entidades B, y las
entidades Bque estn relacionadas con las entidades A. Como lo nico que necesita para esto son los identificadores de ambas tablas
como llaves forneas, esto es lo que mantiene esta tabla de unin:

Afortunadamente con Hibernate no debemos preocuparnos de esta tabla de unin, ya que es el propio framework el que se encarga de
hacerlo. De lo nico que debemos preocuparnos es de hacer de forma correcta los mapeos para representar esta relacin (ya que tiene
algunos trucos).
Comencemos con el tutorial para ver cmo crear estas relaciones. Para los ejemplos usaremos dos clases: "Estudiante" y
"Materia", que veremos un poco ms adelante.
Lo primero que haremos es crear un proyecto en NetBeans (men "File -> New Project... -> Java -> Java
Application"). Le damos un nombre y una ubicacin al proyecto y nos aseguramos de que las opciones "Create Main Class" y
"Set as Main Project" estn habilitadas. Presionamos el botn "Finish" y veremos aparecer nuestra clase "Main" en el editor.
Agregamos la biblioteca de Hibernate, que creamos en el primer tutorial de la serie. Hacemos clic derecho en el nodo "Libraries" del
proyecto y en el men contextual que se abre seleccionamos la opcin "Add Library...":

www.javatutoriales.com/2009/08/hibernate-parte-6-relaciones-muchos.html

1/23

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 6: Relaciones / Muchos a Muchos

Java file
libraries
www.aspose.com
DOC, XLS, PPT, PDF,
MSG and more APIs
to Manage, Print and
Convert

En la ventana que se abre seleccionamos la biblioteca "Hibernate":

SEGUIDORES

Presionamos el botn "Add Library" para que la biblioteca se agregue a nuestro proyecto. Aprovechamos tambin para agregar el
conector de MySQL. Debemos tener los siguientes archivos en nuestro proyecto:

Participar en este sitio


Google Friend Connect

Miembros (173) Ms

Ya eres miembro? Iniciar sesin

ARCHIVO DEL BLOG

2012 (2)
2011 (11)
2010 (10)
2009 (22)
septiembre (2)
agosto (2)

Ahora creamos dos paquetes, uno con el nombre "modelo", que contendr las clases entidades, y otro con el nombre "mapeos" que
contendr los archivos de mapeo XML. Hacemos clic derecho en el nodo del paquete que se cre al generar el proyecto, en el men
contextual que se abre seleccionamos la opcin "New -> Java Package..." y creamos los dos paquetes.

Hibernate - Parte 6: Relacione


a Muchos

Hibernate - Parte 5: Relacione


a Uno
julio (1)
junio (3)
mayo (2)
abril (5)
marzo (2)
febrero (2)
enero (3)

Que deben quedar as:

www.javatutoriales.com/2009/08/hibernate-parte-6-relaciones-muchos.html

2/23

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 6: Relaciones / Muchos a Muchos

Aprovecharemos para crear nuestro archivo de configuracin de Hibernate, "hibernate.cfg.xml", el cual ser muy parecido al del
primer tutorial:

<!DOCTYPE hibernate-configuration PUBLIC


"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<!-- parametros para la conexion a la base de datos -->
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="connection.url">jdbc:mysql://localhost/hibernaterelaciones</property>
<property name="connection.username">usuario</property>
<property name="connection.password">password</property>
<!-- Configuracion del pool interno -->
<property name="connection.pool_size">1</property>
<!-- Dialecto de la base de datos -->
<property name="dialect">org.hibernate.dialect.MySQL5Dialect</property>

DATOS PERSONALES

Alex

Programador Java con algunos


experiencia en mltiples poyec
mltiples APIs y herramientas d
compartir experiencias con el
programadores.
Ver todo mi perfil

<!-- Otras propiedades importantes -->


<property name="show_sql">true</property>
<property name="hbm2ddl.auto">create-drop</property>
<!-- Aqui iran los archivos de mapeo -->
</session-factory>
</hibernate-configuration>

Para los ejercicios usaremos una base de datos llamada "hibernaterelaciones", en MySQL.
Nota: Yo usar dos proyectos, uno para usar archivos de m apeo y otro para usar anotaciones y que el cdigo de am bos no se m ezcle.

Comencemos con el tutorial.

6 - Relaciones Muchos a Muchos Unidireccionales


Primero crearemos la clase "Materia", dentro del paquete modelo. Esta clase solo contendr los elementos bsicos: idy nombre.
Por lo que la clase "Materia" queda as:

www.javatutoriales.com/2009/08/hibernate-parte-6-relaciones-muchos.html

3/23

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 6: Relaciones / Muchos a Muchos

public class Materia


{
private long id;
private String nombre;
public Materia()
{
}
public long getId()
{
return id;
}
protected void setId(long id)
{
this.id = id;
}
public String getNombre()
{
return nombre;
}
public void setNombre(String nombre)
{
this.nombre = nombre;
}
}

Materiano tiene alguna referencia a la clase Estudiante, por lo que no sabe que existe una relacin entre ellas.
La clase "Estudiante", colocada tambin en el paquete modelo, ser la duea de la relacin, as que contendr, adems de tus
atributos bsicos (idy nombre), una lista de referencias a "Materia". La clase Estudiantequeda de esta forma:

public class Estudiante


{
private long id;
private String nombre;
private List<Materia> materias = new ArrayList<Materia>();
public Estudiante()
{
}
public long getId()
{
return id;
}
protected void setId(long id)
{
this.id = id;
}
public List<Materia> getMaterias()
{
return materias;
}
public void setMaterias(List<Materia> materias)
{
this.materias = materias;
}
public String getNombre()
{
return nombre;
}
public void setNombre(String nombre)
{
this.nombre = nombre;
}
}

Agregar a la clase Estudianteun mtodo auxiliar, addMateria, que nos permitir agregar una materia nueva a la lista de materias

www.javatutoriales.com/2009/08/hibernate-parte-6-relaciones-muchos.html

4/23

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 6: Relaciones / Muchos a Muchos


de este Estudiante:

public void addMateria(Materia materia)


{
this.materias.add(materia);
}

Por lo que la clase Estudiantecompleta queda as:

public class Estudiante


{
private long id;
private String nombre;
private List<Materia> materias = new ArrayList<Materia>();
public Estudiante()
{
}
public long getId()
{
return id;
}
protected void setId(long id)
{
this.id = id;
}
public List<Materia> getMaterias()
{
return materias;
}
public void setMaterias(List<Materia> materias)
{
this.materias = materias;
}
public String getNombre()
{
return nombre;
}
public void setNombre(String nombre)
{
this.nombre = nombre;
}
public void addMateria(Materia materia)
{
this.materias.add(materia);
}
}

La lista de Materias que tiene el Estudianteser la referencia que usaremos para la relacin muchos a muchos unidireccional.
Ahora vemos cmo representar esta relacin, como de costumbre, primero veremos cmo hacerlo con archivos de mapeo en XML y
despus veremos cmo hacerlo con anotaciones:

6.1 RELACIONES MUCHOS A MUCHOS UNIDIRECCIONALES CON ARCHIVOS DE MAPEO


Creamos un nuevo documento XML en el paquete mapeos. Le damos el nombre Materia.hbm (el asistente se encargar de colocar
el .xml):

www.javatutoriales.com/2009/08/hibernate-parte-6-relaciones-muchos.html

5/23

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 6: Relaciones / Muchos a Muchos

Presionamos el botn Next > e indicamos que queremos crear un documento XML bien formado (la primer opcin) y presionamos el
botn Finish.
Eliminamos el contenido del archivo creado y lo reemplazamos por el siguiente:

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="hibernate.relaciones.muchos.muchos.modelo.Materia" table="MATERIAS">
</class>
</hibernate-mapping>

El mapeo de la clase Materiaes similar al que expliqu en el primer tutorial de la serie y, al final, queda de la siguiente forma:

<hibernate-mapping>
<class name="hibernate.relaciones.muchos.muchos.modelo.Materia" table="MATERIAS">
<id name="id" column="ID_MATERIA">
<generator class="identity" />
</id>
<property name="nombre" />
</class>
</hibernate-mapping>

Noten que he agregado el atributo column=ID_MATERIA del elemento <id>. Esto no es necesario para las relaciones
unidireccionales, pero es vital para las relaciones bidireccionales (si, como yo, le ponen a todos los identificadores de sus entidades
el mismo nombre, id), por lo que lo colocamos desde el principio.
Ahora crearemos el mapeo para la clase Estudiante. Creamos, en el paquete mapeos, el archivo Estudiante.hbm. Eliminamos el
contenido del archivo y lo reemplazamos por el siguiente:

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="hibernate.relaciones.muchos.muchos.modelo.Estudiante" table="ESTUDIANTES">

</class>
</hibernate-mapping>

www.javatutoriales.com/2009/08/hibernate-parte-6-relaciones-muchos.html

6/23

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 6: Relaciones / Muchos a Muchos


Colocamos en el archivo el mapeo de los atributos id y nombre de la clase Estudiante antes de pasar a ver el mapeo de la
relacin. Hasta ahora el mapeo debe verse as:

<hibernate-mapping>
<class name="hibernate.relaciones.muchos.muchos.modelo.Estudiante" table="ESTUDIANTES">
<id name="id" column="ID_ESTUDIANTE">
<generator class="identity" />
</id>
<property name="nombre" />
</class>
</hibernate-mapping>

Ahora podemos centrarnos en mapear la relacin.


Al igual que ocurri cuando vimos las relaciones uno a muchos en el cuarto tutorial, representamos las relaciones muchos a muchos
usando el elemento acorde al tipo de coleccin que estemos usando (list, set, map, array, y primitive-array).
En este caso estamos usando una lista, por lo que veremos cmo hacer el mapeo usando esta coleccin, pero si estn usando otra
pueden encontrar ms informacin en esta pgina.
Para mapear una lista usamos el elemento "<list>". En este elemento indicamos cul es el nombre del atributo, dentro de la clase
Estudiante, que representa la realcin. En este caso el atributo se llama materias. Tambin aqu indicamos cules operaciones
queremos que se realicen en cascada. En este caso queremos que todas las operaciones de guardar, actualizar y eliminar que
ocurran en el padre sean pasadas a la coleccin, o sea que cuando guardemos, actualicemos, o eliminemos un Estudiante, las
operaciones pasen tambin a todas sus Materias relacionadas, por lo que usamos el valor "all".
En las relaciones muchos a muchos, igual que en las relaciones uno a muchos, existen dos estilos de cascada especiales llamados
"delete-orphan" y "all-delete-orphan" (que solo pueden usarse con archivos de mapeo) los cuales se encargan de que, en el
caso de que se elimine el objeto padre ("Estudiante"), todos los objetos hijos ("Materia") sern eliminados de la base de datos.
Adicionalmente "all-delete-orphan" se encarga de que todas las otras operaciones que mencionamos antes (guardar, actualizar,
y eliminar) tambin sean realizados en cascada, por lo que usaremos este valor.
Finalmente, si recuerdan, al principio del tutorial dije que cuando tenemos relaciones muchos a muchos, se usa una tabla de unin o
tabla join para mantener los datos de qu objetos de la entidad A(Estudiante) estn relacionados con qu objetos de la entidad B
(Materia). En este caso debemos especificar cul ser el nombre de esta tabla de unin, usando el atributo "table" del elemento
<list>. Por lo que este elemento queda, por el momento, as:

<list name="materias" table="ESTUDIANTES_MATERIAS" cascade="all-delete-orphan">


</list>

La tabla de unin generada ("ESTUDIANTES_MATERIAS") tendr como columnas "id", que es la llave fornea de la tabla estudiantes, y
una segunda columna llamada "elt" (elt significa element, que es el nombre que da por default hibrnate si no especificamos uno) que es
la llave fornea de la tabla "materias".
Ahora indicamos cul ser el valor que se usar como llave fornea para relacionar las Materias con el Estudiante. Siempre, lo que
usaremos ser la llave primaria de la entidad que estamos mapeando (en este caso Estudiante), por lo que colocamos aqu el nombre
de la columna que mantiene este valor, que en este caso es "ID_ESTUDIANTE":

<key column="ID_ESTUDIANTE " />

Ahora bien, las listas son una estructura de datos con una caracterstica nica: tienen un orden. Esto significa que el orden en el que
los elementos entran en la lista es importante e, internamente, se usa un ndice para saber el orden de los elementos.
Cuando tratamos de almacenar estos datos nos interesa que en el momento que sean recuperados, los elementos de la lista estn en el
mismo orden en el que los guardamos y es por esta razn que se debe usar una columna extra en la tabla de unin generada para
guardar este ndice (el cual comienza en cero). Para indicar el nombre que tendr esta columna usamos el elemento "index" y
colocamos en su atributo "column" el nombre que tendr esta columna:

<index column="ORDEN" />

Ahora si, por fin ha llego el momento de usar el elemento que representa la relacin ^-^.

www.javatutoriales.com/2009/08/hibernate-parte-6-relaciones-muchos.html

7/23

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 6: Relaciones / Muchos a Muchos


Las relaciones muchos a muchos las representamos usando el elemento <many-to-many>. Este elemento se coloca dentro del
elemento <list>(o el elemento que esten usando para representar su relacin) que acabo de explicar, y lo nico que debemos indicarle
de qu clase son las entidades que estamos guardando en la lista (ya que este dato no puede ser obtenido usando reflexin), y cul es la
columna que se usa para almacenar el id de esta entidad:

<many-to-many class="hibernate.relaciones.muchos.muchos.modelo.Materia" column="ID_MATERIA" />

Finalmente, el mapeo del a relacin queda as:

<list name="materias" table="ESTUDIANTES_MATERIAS" cascade="all-delete-orphan" >


<key column="ID_ESTUDIANTE" />
<list-index column="ORDEN" />
<many-to-many class="hibernate.relaciones.muchos.muchos.modelo.Materia" column="ID_MATERIA" />
</list>

Y el archivo de mapeo para la entidad Estudiantequeda as:

<hibernate-mapping>
<class name="hibernate.relaciones.muchos.muchos.modelo.Estudiante" table="ESTUDIANTES">
<id name="id" column="ID_ESTUDIANTE">
<generator class="identity" />
</id>
<property name="nombre" />
<list name="materias" table="ESTUDIANTES_MATERIAS" cascade="all-delete-orphan" >
<key column="ID_ESTUDIANTE" />
<list-index column="ORDEN" />
<many-to-many class="hibernate.relaciones.muchos.muchos.modelo.Materia" column="ID_MAT
ERIA" />
</list>
</class>
</hibernate-mapping>

Ahora agregamos la ruta a los dos archivos de mapeo que acabamos de crear al archivo hibernate.cfg.xml:

<mapping resource="hibernate/relaciones/muchos/muchos/mapeos/Materia.hbm.xml" />


<mapping resource="hibernate/relaciones/muchos/muchos/mapeos/Estudiante.hbm.xml" />

Para este ejemplo usaremos la clase HibernateUtilque creamos en el primer tutorial.


Crearemos dos objetos Estudiante, estudiante1 y estudiante2. Despus crearemos 6 Materias materia1 a materia6
y asociaremos 3 Materias con cada Estudiante. Posteriormente guardaremos en la base de datos a los 2 Estudiantes, con lo que
las 6 Materias sern almacenadas en la base de datos por las operaciones en cascada que definimos. Finalmente eliminaremos al
estudiante1, con lo que esperamos que se eliminen adems materia1, materia2, y materia3.
Colocaremos el siguiente cdigo, auto-explicativo, en el mtodo mainde nuestra clase Main:

www.javatutoriales.com/2009/08/hibernate-parte-6-relaciones-muchos.html

8/23

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 6: Relaciones / Muchos a Muchos

public static void main(String[] args)


{
Estudiante estudiante1 = new Estudiante();
estudiante1.setNombre("estudiante1");
Materia materia1 = new Materia();
materia1.setNombre("materia1");
Materia materia2 = new Materia();
materia2.setNombre("materia2");
Materia materia3 = new Materia();
materia3.setNombre("materia3");
estudiante1.addMateria(materia1);
estudiante1.addMateria(materia2);
estudiante1.addMateria(materia3);

Estudiante estudiante2 = new Estudiante();


estudiante2.setNombre("estudiante2");
Materia materia4 = new Materia();
materia4.setNombre("materia4");
Materia materia5 = new Materia();
materia5.setNombre("materia5");
Materia materia6 = new Materia();
materia6.setNombre("materia6");
estudiante2.addMateria(materia4);
estudiante2.addMateria(materia5);
estudiante2.addMateria(materia6);
Session sesion = HibernateUtil.getSessionFactory().openSession();
sesion.beginTransaction();
sesion.save(estudiante1);
sesion.save(estudiante2);
sesion.getTransaction().commit();
sesion.close();
sesion = HibernateUtil.getSessionFactory().openSession();
sesion.beginTransaction();
sesion.delete(estudiante1);
sesion.getTransaction().commit();
sesion.close();
}

Probemos que todo funciona correctamente. Segn lo anterior solo debe estar el estudiante2 en la base de datos y sus 3 Materias
asociadas materia1, materia2, y materia3:

En la imagen anterior podemos comprobar que el la base de datos estn los datos correctos ^-^. Tambin podemos ver que,
efectivamente, se cre una tercera tabla que mantiene las relaciones entre Estudiantey Materia.
Ahora veremos cmo hacer lo mismo pero usando anotaciones:

6.2 RELACIONES MUCHOS A MUCHOS UNIDIRECCIONALES CON ANOTACIONES


Recuerden que pasa usar anotaciones debemos agregar al proyecto la biblioteca "HibernateAnotaciones" que creamos en el
segundo tutorial.
Las anotaciones (as como los archivos de configuracin) de ambas clases (omitiendo el atributo que indica la relacin) sern las mismas
que expliqu en el segundo tutorial de esta serie, quedan de la siguiente forma:
Esta es la clase Materia:

www.javatutoriales.com/2009/08/hibernate-parte-6-relaciones-muchos.html

9/23

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 6: Relaciones / Muchos a Muchos

@Entity
public class Materia implements Serializable
{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
private String nombre;
public Materia()
{
}
public long getId()
{
return id;
}
protected void setId(long id)
{
this.id = id;
}
public String getNombre()
{
return nombre;
}
public void setNombre(String nombre)
{
this.nombre = nombre;
}
}

Y esta es la clase Estudiante:

www.javatutoriales.com/2009/08/hibernate-parte-6-relaciones-muchos.html

10/23

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 6: Relaciones / Muchos a Muchos

@Entity
public class Estudiante implements Serializable
{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
private String nombre;
private List<Materia> materias = new ArrayList<Materia>();
public Estudiante()
{
}
public long getId()
{
return id;
}
protected void setId(long id)
{
this.id = id;
}
public List<Materia> getMaterias()
{
return materias;
}
public void setMaterias(List<Materia> materias)
{
this.materias = materias;
}
public String getNombre()
{
return nombre;
}
public void setNombre(String nombre)
{
this.nombre = nombre;
}
public void addMateria(Materia materia)
{
this.materias.add(materia);
}
}

La anotacin que nos interesa, para representar la relacin muchos a muchos es @ManyToMany. Esta anotacin debemos colocarla en
el atributo que representa la relacin (en este caso materias).
Igual que lo hicimos en la anotacin "@OneToOne", y con "@OneToMany", aqu definiremos qu operaciones sern realizadas en
cascada. Adems tambin podemos indicar el tipo de "fetch" o recuperacin que tendr la coleccin, de la misma forma que lo expliqu
en el tutorial anterior.
Al final, la relacin queda de esta forma:

@ManyToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER)
private List<Materia> materias = new ArrayList<Materia>();

Y la clase Estudiante, con todas sus anotaciones, queda as:

www.javatutoriales.com/2009/08/hibernate-parte-6-relaciones-muchos.html

11/23

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 6: Relaciones / Muchos a Muchos

@Entity
public class Estudiante implements Serializable
{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
private String nombre;
@ManyToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER)
private List<Materia> materias = new ArrayList<Materia>();
public Estudiante()
{
}
public long getId()
{
return id;
}
protected void setId(long id)
{
this.id = id;
}
public List<Materia> getMaterias()
{
return materias;
}
public void setMaterias(List<Materia> materias)
{
this.materias = materias;
}
public String getNombre()
{
return nombre;
}
public void setNombre(String nombre)
{
this.nombre = nombre;
}
public void addMateria(Materia materia)
{
this.materias.add(materia);
}
}

Y eso es todo lo que necesitamos para tener una relacin muchos a muchos unidireccionalusando anotaciones.
Recuerden que debemos colocar estas dos clases en el archivo de configuracin de Hibernate:

<mapping class="hibernate.relaciones.muchos.muchos.anotaciones.modelo.Estudiante" />


<mapping class="hibernate.relaciones.muchos.muchos.anotaciones.modelo.Materia" />

Ahora usaremos la clase HibernateUtildel segundo tutorial para implementar nuestra prueba. La prueba ser la misma que describ
anteriormente: Crearemos 2 objetos Estudiante, estudiante1 y estudiante2. Despus crearemos 6 Materias materia1 a
materia6 y asociaremos 3 materias con cada estudiante. Posteriormente guardaremos en la base de datos a los 2 estudiantes, con lo
que las 6 materias sern almacenadas en la base de datos por las operaciones en cascada que definimos. Finalmente eliminaremos al
estudiante1, con lo que esperamos que se eliminen adems materia1, materia2, y materia3.
Colocamos el siguiente cdigo como el mtodo mainde nuestra clase Main:

www.javatutoriales.com/2009/08/hibernate-parte-6-relaciones-muchos.html

12/23

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 6: Relaciones / Muchos a Muchos

public static void main(String[] args)


{
Estudiante estudiante1 = new Estudiante();
estudiante1.setNombre("estudiante1");
Materia materia1 = new Materia();
materia1.setNombre("materia1");
Materia materia2 = new Materia();
materia2.setNombre("materia2");
Materia materia3 = new Materia();
materia3.setNombre("materia3");
estudiante1.addMateria(materia1);
estudiante1.addMateria(materia2);
estudiante1.addMateria(materia3);

Estudiante estudiante2 = new Estudiante();


estudiante2.setNombre("estudiante2");
Materia materia4 = new Materia();
materia4.setNombre("materia4");
Materia materia5 = new Materia();
materia5.setNombre("materia5");
Materia materia6 = new Materia();
materia6.setNombre("materia6");
estudiante2.addMateria(materia4);
estudiante2.addMateria(materia5);
estudiante2.addMateria(materia6);
Session sesion = HibernateUtil.getSessionFactory().openSession();
sesion.beginTransaction();
sesion.save(estudiante1);
sesion.save(estudiante2);
sesion.getTransaction().commit();
sesion.close();
sesion = HibernateUtil.getSessionFactory().openSession();
sesion.beginTransaction();
sesion.delete(estudiante1);
sesion.getTransaction().commit();
sesion.close();
}

Ahora comprobemos que el ejemplo funciona:

Como podemos observar todo ha funcionado correctamente ^-^.


Ahora, veamos cmo crear relaciones muchos a muchos bidireccionales. Primero veamos cmo hacerlo mediante archivos de mapeo.

7 - Relaciones Muchos a Muchos Bidireccionales


Las relaciones muchos a muchos bidireccionales son muy parecidas a las relaciones unidireccionales, pero con la diferencia de que,
como en el caso de todas las relaciones bidireccionales, ambos lados de la relacin saben de la existencia de esta. Veamos cmo
representar estas relaciones, nuevamente usando primero archivos de mapeo y despus con anotaciones.

7.1 RELACIONES MUCHOS A MUCHOS BIDIRECCIONALES CON ARCHIVOS DE MAPEO


Las relaciones muchos a muchos bidireccionales son muy parecidas a las relaciones unidireccionales, por lo que los cambios que
deberemos hacer son mnimos.
Modificaremos un poco nuestra clase Materia para que contenga una referencia a todos los Estudiantes que estn tomando esa

www.javatutoriales.com/2009/08/hibernate-parte-6-relaciones-muchos.html

13/23

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 6: Relaciones / Muchos a Muchos


Materia. Como muchos Estudiantes pueden tomar una Materia, deberemos agregar una lista de objetos Estudiante a la clase
Materia, de esta forma:

private List<Estudiante> estudiantes = new ArrayList<Estudiante>();

Tambin agregamos los setters y los getters para este atributo.

public List<Estudiante> getEstudiantes()


{
return estudiantes;
}
public void setEstudiantes(List<Estudiante> estudiantes)
{
this.estudiantes = estudiantes;
}

Adems pondr un mtodo auxiliar extra que nos permitir que se agregue un Estudiante a la lista de Estudiantes para esta
Materia. Adems, al mismo tiempo, agregar esta Materiaa la lista de Materiaspara el Estudiante:

public void addEstudiante(Estudiante estudiante)


{
this.estudiantes.add(estudiante);
estudiante.addMateria(this);
}

La clase Materiaqueda de esta forma:

www.javatutoriales.com/2009/08/hibernate-parte-6-relaciones-muchos.html

14/23

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 6: Relaciones / Muchos a Muchos

public class Materia


{
private long id;
private String nombre;
private List<Estudiante> estudiantes = new ArrayList<Estudiante>();
public Materia()
{
}
public long getId()
{
return id;
}
protected void setId(long id)
{
this.id = id;
}
public String getNombre()
{
return nombre;
}
public void setNombre(String nombre)
{
this.nombre = nombre;
}
public List<Estudiante> getEstudiantes()
{
return estudiantes;
}
public void setEstudiantes(List<Estudiante> estudiantes)
{
this.estudiantes = estudiantes;
}
public void addEstudiante(Estudiante estudiante)
{
this.estudiantes.add(estudiante);
estudiante.addMateria(this);
}
}

La clase Estudiantequeda igual, por lo que no es necesario modificarle nada.


Ahora hay que indicar esta relacin en el archivo de mapeo Materia.hbm.xml.
Esta relacin la indicamos exactamente como lo hicimos en el archivo Estudiante.hbm.xml: Agregamos un elemento <list>, con
el nombre del atributo que representa la relacin en la clase Materia, que en este caso es estudiantes, y, de la misma forma que
hicimos antes, indicamos el nombre de la tabla de unin para estas dos entidades.
El siguiente paso es muy importante. Recuerdan que cuando habl sobre las relaciones uno a muchos bidireccionales dije que exista
un lado dueo de la relacin y un lado inverso. Pues bien, en este caso ocurre lo mismo, una de las entidades es la duea de la
relacin y el otro es el lado inverso. Quin debe ser el dueo y quin el inverso depende de la lgica de su aplicacin. Para este
ejemplo, supondr que Estudiante es el dueo de la relacin (para no tener que modificar su archivo de mapeo), y que Materias
es el lado inverso. Esto lo indicamos usando el atributo inverse con valor true en el elemento <list>.
El resto de los elementos que representan el mapeo de la relacin son exactamente los mismos que expliqu en el mapeo de la relacin
unidireccional, por lo que el mapeo queda de esta forma:

<list name="estudiantes" table="ESTUDIANTES_MATERIAS" inverse="true" >


<key column="ID_MATERIA" />
<list-index column="ORDEN" />
<many-to-many class="hibernate.relaciones.muchos.muchos.modelo.Estudiante" column="ID_ESTUDIAN
TE" />
</list>

Y el archivo completo de mapeo as:

www.javatutoriales.com/2009/08/hibernate-parte-6-relaciones-muchos.html

15/23

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 6: Relaciones / Muchos a Muchos

<hibernate-mapping>
<class name="hibernate.relaciones.muchos.muchos.modelo.Materia" table="MATERIAS">
<id name="id" column="ID_MATERIA">
<generator class="identity" />
</id>
<property name="nombre" />
<list name="estudiantes" table="ESTUDIANTES_MATERIAS" inverse="true" >
<key column="ID_MATERIA" />
<list-index column="ORDEN" />
<many-to-many class="hibernate.relaciones.muchos.muchos.modelo.Estudiante" column="ID_
ESTUDIANTE" />
</list>
</class>
</hibernate-mapping>

El archivo Estudiante.hbm.xml queda exactamente igual.


Modificaremos un poco el cdigo del mtodo main de la clase Main para usar el mtodo auxiliar addEstudiante de la clase
Materia, dejndolo as:

public static void main(String[] args)


{
Estudiante estudiante1 = new Estudiante();
estudiante1.setNombre("estudiante1");
Materia materia1 = new Materia();
materia1.setNombre("materia1");
Materia materia2 = new Materia();
materia2.setNombre("materia2");
Materia materia3 = new Materia();
materia3.setNombre("materia3");
materia1.addEstudiante(estudiante1);
materia2.addEstudiante(estudiante1);
materia3.addEstudiante(estudiante1);

Estudiante estudiante2 = new Estudiante();


estudiante2.setNombre("estudiante2");
Materia materia4 = new Materia();
materia4.setNombre("materia4");
Materia materia5 = new Materia();
materia5.setNombre("materia5");
Materia materia6 = new Materia();
materia6.setNombre("materia6");
materia4.addEstudiante(estudiante2);
materia5.addEstudiante(estudiante2);
materia6.addEstudiante(estudiante2);
Session sesion = HibernateUtil.getSessionFactory().openSession();
sesion.beginTransaction();
sesion.save(estudiante1);
sesion.save(estudiante2);
sesion.getTransaction().commit();
sesion.close();
sesion = HibernateUtil.getSessionFactory().openSession();
sesion.beginTransaction();
sesion.delete(estudiante1);
sesion.getTransaction().commit();
sesion.close();
}

www.javatutoriales.com/2009/08/hibernate-parte-6-relaciones-muchos.html

16/23

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 6: Relaciones / Muchos a Muchos


Debe ocurrir lo mismo que en la ocasin anterior: se crean 2 Estudiantes y 6 Materias, relacionando 3 Materias con cada
Estudiante. Despus se almacenan los Estudiantes, y sus Materias en cascada, y finalmente se elimina el primer Estudiante.
Por lo que solo deben quedar en la base el estudiante2 y las materias 4 a 6:

Podemos comprobar que todo sali como esperbamos ^-^. Por lo que solo queda que veamos cmo crear relaciones bidireccionales con
anotaciones:

7.2 RELACIONES MUCHOS A MUCHOS BIDIRECCIONALES CON ANOTACIONES


Finalmente, y para terminar este tutorial, modificaremos el ejemplo de la relacin muchos a muchos unidireccional con anotaciones para
transformarlo en bidireccional.
Para hacer eso, debemos agregar un atributo que represente la relacin dentro de la clase Materia. Como la relacin es muchos a
muchos, esta relacin estar representada por un atributo de tipo lista de Estudiantes, de esta forma:

private List<Estudiante> estudiantes = new ArrayList<Estudiante>();

A este atributo lo marcamos con la anotacin @ManyToMany, de la misma forma que lo est el atributo materias de la clase
Estudiante:

@ManyToMany
private List<Estudiante> estudiantes = new ArrayList<Estudiante>();

Agregamos adems los setters y los getters de este atributo y el mtodo auxiliar addEstudiante, igual que lo hicimos en el caso de
los archivos de mapeo:

public List<Estudiante> getEstudiantes()


{
return estudiantes;
}
public void setEstudiantes(List<Estudiante> estudiantes)
{
this.estudiantes = estudiantes;
}
public void addEstudiante(Estudiante estudiante)
{
this.estudiantes.add(estudiante);
estudiante.addMateria(this);
}

Bien, con esto ya casi hemos terminado. Si recuerdan, cuando hable de las relaciones uno a muchos bidireccionales con anotaciones
dije que uno de los dos lados de la relacin debe ser el dueo y el otro el inverso, y que existe una regla: el lado muchos
SIEMPRE es el lado dueo. Pues bien, esto tambin aplica para las relaciones muchos a muchos. Claro que como aqu ambos lados
son el lado mucho, podemos elegir el que nosotros queramos para que sea el dueo.
En mi caso escoger la entidad Estudiantecomo el dueo, solo para no modificar la clase, y por lo tanto, la entidad Materiaser el
lado inverso, por lo que debemos indicarlo colocando, en la anotacin @ManyToManyel atributo mappedBy, como expliqu en el cuarto
tutorial, cuyo valor ser el nombre del atributo que representa la lista de Materias en la clase Estudiante, que en este caso es
materias. Por lo que el atributo queda de esta forma:

www.javatutoriales.com/2009/08/hibernate-parte-6-relaciones-muchos.html

17/23

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 6: Relaciones / Muchos a Muchos

@ManyToMany(mappedBy="materias")
private List<Estudiante> estudiantes = new ArrayList<Estudiante>();

Y la clase Estudianteas:

@Entity
public class Materia implements Serializable
{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
private String nombre;
@ManyToMany(mappedBy = "materias")
private List<Estudiante> estudiantes = new ArrayList<Estudiante>();
public Materia()
{
}
public long getId()
{
return id;
}
protected void setId(long id)
{
this.id = id;
}
public String getNombre()
{
return nombre;
}
public void setNombre(String nombre)
{
this.nombre = nombre;
}
public List<Estudiante> getEstudiantes()
{
return estudiantes;
}
public void setEstudiantes(List<Estudiante> estudiantes)
{
this.estudiantes = estudiantes;
}
public void addEstudiante(Estudiante estudiante)
{
this.estudiantes.add(estudiante);
estudiante.addMateria(this);
}
}

Ahora comprobemos que todo est bien configurado colocando el siguiente cdigo en el mtodo mainde nuestra clase Main:

www.javatutoriales.com/2009/08/hibernate-parte-6-relaciones-muchos.html

18/23

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 6: Relaciones / Muchos a Muchos

public static void main(String[] args)


{
Estudiante estudiante1 = new Estudiante();
estudiante1.setNombre("estudiante1");
Materia materia1 = new Materia();
materia1.setNombre("materia1");
Materia materia2 = new Materia();
materia2.setNombre("materia2");
Materia materia3 = new Materia();
materia3.setNombre("materia3");
materia1.addEstudiante(estudiante1);
materia2.addEstudiante(estudiante1);
materia3.addEstudiante(estudiante1);

Estudiante estudiante2 = new Estudiante();


estudiante2.setNombre("estudiante2");
Materia materia4 = new Materia();
materia4.setNombre("materia4");
Materia materia5 = new Materia();
materia5.setNombre("materia5");
Materia materia6 = new Materia();
materia6.setNombre("materia6");
materia4.addEstudiante(estudiante2);
materia5.addEstudiante(estudiante2);
materia6.addEstudiante(estudiante2);
Session sesion = HibernateUtil.getSessionFactory().openSession();
sesion.beginTransaction();
sesion.save(estudiante1);
sesion.save(estudiante2);
sesion.getTransaction().commit();
sesion.close();
sesion = HibernateUtil.getSessionFactory().openSession();
sesion.beginTransaction();
sesion.delete(estudiante1);
sesion.getTransaction().commit();
sesion.close();
}

El cual hace lo mismo que en el caso anterior: se crean 2 Estudiantes y 6 Materias, relacionando 3 Materias con cada
Estudiante. Despus se almacenan los Estudiantes, y sus Materias en cascada, y finalmente se elimina el primer Estudiante.
Por lo que solo deben quedar en la base el estudiante2 y las materias 4 a 6:

Como podemos ver todo ha salido bien ^-^ (Notaron que cuando usamos anotaciones, en la tabla de unin no se genera una columna de
orden?), por lo que podemos dar por terminado este tutorial, y lo que respecta a las relaciones con hibrnate ^-^.
En el siguiente post mostrar cmo hacer consultas con Hibernate usando un lenguaje especial de consultas llamado HQL (Hibernate
Query Language) para ver cmo podemos recuperar las entidades con las distintas relaciones que hemos visto.
Si tienen alguna duda, comentario o sugerencia no duden en escribir un comentario.
Saludos.
Descarga los archivos de este tutorial desde aqu:
Hibernate Relaciones Muchos a Muchos con archivos de Mapeo
Hibernate Relaciones Muchos a Muchos con Anotaciones

Entradas Relacionadas:
Parte 1: Persistiendo Objetos Simples usando Mapeos en XML

www.javatutoriales.com/2009/08/hibernate-parte-6-relaciones-muchos.html

19/23

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 7: HQL Primera Parte


Compartir

Ms

Siguiente blog

Tutoriales de Programacion Java


Blog dedicado a temas de programacin actuales usando el lenguaje de programacin Java y las ltimas versiones de sus APIs y Herramientas.
Pgina principal

Pgina de Concursos

Tutoriales UPAO 2010

Presentaciones Capacitacin

LUNES, 21 DE SEPTIEMBRE DE 2009

Hibernate - Parte 7: HQL Primera Parte

DONACIONES

Hibernate proporciona un lenguaje de consultas muy poderoso llamado "Hibernate Query Language" (HQL).
HQL es muy parecido al SQL estndar, con la diferencia de que es completamente orientado a objetos (usamos nombres de clases y
sus atributos en lugar de nombres de tablas y columnas), por lo que podemos usar cosas como herencia, polimorfismo y asociaciones.
Nosotros escribimos las consultas en HQL y Hibernate se encarga de convertirlas al SQL usado por la base de datos con la que estemos
trabajando y ejecutarla para realizar la operacin indicada.

JAVA TUTORIALES EN FACEBOOK

Java Tutoriales
Me gusta

En este tutorial veremos cmo usar este lenguaje para hacer algunas consultas tpicas dentro de nuestras aplicaciones para poder
recuperar objetos simples, y arboles de objetos.
Lo primero que hay que saber sobre HQL es que es case-insensitive, o sea que sus sentencias pueden escribirse en maysculas y
minsculas. Por lo tanto "SeLeCt", "seleCT", "select", y "SELECT" se entienden como la misma cosa.
Lo nico con lo que debemos tener cuidado es con los nombres de las clases que estamos recuperando y con sus propiedades, ah si se
distinguen maysculas y minsculas. O sea, en este caso "pruebas.hibernate.Usuario" NO ES LO MISMO que
"PrueBAs.HibernatE.UsuArio".
En este tutorial colocar las clausulas HQL (SELECT, WHERE, ORDER BY, etc.) en maysculas.
Comencemos con el tutorial creando un nuevo proyecto en NetBeans.
Lo primero que haremos es crear un proyecto en NetBeans (men "File -> New Project... -> Java -> Java
Application"). Le damos un nombre y una ubicacin al proyecto y nos aseguramos de que las opciones "Create Main Class" y
"Set as Main Project" estn habilitadas. Presionamos el botn "Finish" y veremos aparecer nuestra clase "Main" en el editor.

Java Tutoriales

Amigo programador,
ests todo el da pica
cdigo, escucha esta
recomendaciones sl
hechas para ti..... q
esto?... Gracias Jorg
Rubira....

No olviden poner la
sentencia where al ha
un borraro en la base
datos..

http://www.youtube.c
watch?v=i_cVJgIz_Cs
A 7895 personas les gusta

En el tutorial usaremos anotaciones en vez de archivos de mapeo para que sea un poco ms claro, as que agregamos las bibliotecas de
"Hibernate" y "HibernateAnotaciones", que creamos en el primer y segundo tutoriales. Hacemos clic derecho en el nodo
"Libraries" del proyecto y en el men contextual que se abre seleccionamos la opcin "Add Library...":

Plug-in social de Facebook

En la ventana que se abre seleccionamos las bibliotecas "Hibernate" y HibernateAnotaciones:

www.javatutoriales.com/2009/09/hibernate-parte-7-hql-primera-parte.html

1/25

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 7: HQL Primera Parte

Presionamos el botn "Add Library" para que la biblioteca se agregue a nuestro proyecto. Aprovechamos tambin para agregar el
conector de MySQL. Debemos tener los siguientes archivos en nuestro proyecto:

Ahora creamos un paquete con el nombre modelo que contendr las clases entidad. Hacemos clic derecho en el nodo del paquete que
se cre al generar el proyecto, en el men contextual que se abre seleccionamos la opcin "New -> Java Package..." y creamos el
paquete.

SEGUIDORES

Participar en este sitio


Google Friend Connect

Miembros (173) Ms

Que debe quedar as:


Ya eres miembro? Iniciar sesin

ARCHIVO DEL BLOG

2012 (2)
2011 (11)
2010 (10)
2009 (22)
septiembre (2)

Hibernate - Parte 7: HQL Prim


Da del programados

Ahora crearemos el archivo de configuracin, el cual ser muy parecido al del segundo tutorial. Recuerden que este archivo debe llamarse
"hibernate.cfg.xml" y debe encontrarse en la raz del classpath del proyecto (el paquete default)

agosto (2)
julio (1)
junio (3)
mayo (2)
abril (5)
marzo (2)
febrero (2)
enero (3)

www.javatutoriales.com/2009/09/hibernate-parte-7-hql-primera-parte.html

2/25

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 7: HQL Primera Parte

<!DOCTYPE hibernate-configuration PUBLIC


"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<!-- parametros para la conexion a la base de datos -->
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="connection.url">jdbc:mysql://localhost:3306/hibernatehql</property>
<property name="connection.username">root</property>
<property name="connection.password">123</property>
<!-- Configuracion del pool interno -->
<property name="connection.pool_size">1</property>
<!-- Dialecto de la base de datos -->
<property name="dialect">org.hibernate.dialect.MySQL5Dialect</property>
<!-- Otras propiedades importantes -->
<property name="show_sql">true</property>
<property name="hbm2ddl.auto">none</property>
<!-- Aqui iran las clases entidades -->

</session-factory>
</hibernate-configuration>

Por ahora dejaremos el archivo de configuracin como est mientras creamos nuestras clases entidades:

NUESTRAS ENTIDADES

DATOS PERSONALES

Alex

Para este ejemplo crearemos tres clases entidad: "Usuario", "Direccion" y "Permiso". La relacin que existir sobre estas tres
clases es una relacin uno a uno entre "Usuario" y "Direccin" y una relacin uno a muchos de "Usuario" con "Permiso"; o
sea, un "Usuario" puede tener una "Direccin" y un "Usuario" puede tener muchos "Permisos".

Programador Java con algunos


experiencia en mltiples poyec
mltiples APIs y herramientas d
compartir experiencias con el
programadores.

Aunque estas relaciones son simples, nos ayudaran a mostrar las consultas que realizamos con mayor frecuencia en las aplicaciones.

Ver todo mi perfil

Primero, crearemos la clase Permiso. Creamos una nueva clase en el paquete modelo con el siguiente contenido:

www.javatutoriales.com/2009/09/hibernate-parte-7-hql-primera-parte.html

3/25

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 7: HQL Primera Parte

@Entity
@Table(name="permisos")
public class Permiso implements Serializable
{
public enum Estatus {PENDIENTE, ACTIVO, INACTIVO};
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private long id;
private String nombre;
private Estatus estatus = Estatus.PENDIENTE;
public Permiso()
{
}
public Estatus getEstatus()
{
return estatus;
}
public void setEstatus(Estatus estatus)
{
this.estatus = estatus;
}
public long getId()
{
return id;
}
public void setId(long id)
{
this.id = id;
}
public String getNombre()
{
return nombre;
}
public void setNombre(String nombre)
{
this.nombre = nombre;
}
}

La entidad Permiso es muy sencilla pero nos permitir observar el comportamiento de las consultas HQL. Usa las anotaciones que
expliqu en el segundo tutorial.
Noten que agregu una enum para restringir los valores de los estatus solo para ejemplificar en uso de las mismas dentro de las
entidades.
La siguiente clase que crearemos es Direccin, creamos esta clase en el paquete modelo. Este clase mantendr una relacin uno
a uno bidireccional con "Usuario". La clase queda de esta forma:

www.javatutoriales.com/2009/09/hibernate-parte-7-hql-primera-parte.html

4/25

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 7: HQL Primera Parte

@Entity
@Table(name="direcciones")
public class Direccion implements Serializable
{
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private long id;
private String calle;
private String codigoPostal;
@OneToOne(mappedBy="direccion")
private Usuario usuario;
public Direccion()
{
}
public String getCalle()
{
return calle;
}
public void setCalle(String calle)
{
this.calle = calle;
}
public String getCodigoPostal()
{
return codigoPostal;
}
public void setCodigoPostal(String codigoPostal)
{
this.codigoPostal = codigoPostal;
}
public long getId()
{
return id;
}
protected void setId(long id)
{
this.id = id;
}
public Usuario getUsuario()
{
return usuario;
}
public void setUsuario(Usuario usuario)
{
this.usuario = usuario;
}
}

Como dije antes: la clase Direccion mantiene una relacin uno a uno bidireccional con la clase Usuario y, como lo indica el
elemento mappedBy de la anotacin @OneToOne, la entidad Usuario es la duea de la relacin.
Ahora veamos la clase Usuario.
Creamos la clase Usuario en el paquete modelo. Esta clase mantendr la relacin uno a muchos con Permiso y la relacin uno
a uno con Direccion; y queda de la siguiente forma:

www.javatutoriales.com/2009/09/hibernate-parte-7-hql-primera-parte.html

5/25

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 7: HQL Primera Parte

@Entity
@Table(name="usuarios")
public class Usuario implements Serializable
{
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private long id;
private String nombre;
private String username;
private String password;
@OneToMany(cascade=CascadeType.ALL, fetch=FetchType.LAZY)
private List<Permiso> permisos = new ArrayList<Permiso>();
@OneToOne(cascade=CascadeType.ALL, fetch=FetchType.EAGER)
private Direccion direccion;
public long getId()
{
return id;
}
protected void setId(long id)
{
this.id = id;
}
public String getNombre()
{
return nombre;
}
public void setNombre(String nombre)
{
this.nombre = nombre;
}
public String getPassword()
{
return password;
}
public void setPassword(String password)
{
this.password = password;
}
public List<Permiso> getPermisos()
{
return permisos;
}
public void setPermisos(List<Permiso> permisos)
{
this.permisos = permisos;
}
public String getUsername()
{
return username;
}
public void setUsername(String username)
{
this.username = username;
}
public Direccion getDireccion()
{
return direccion;
}
public void setDireccion(Direccion direccion)
{
this.direccion = direccion;
direccion.setUsuario(this);
}
}

Usuario es una entidad muy similar a las que hemos visto a lo largo de estos tutoriales, as que no debera haber problemas para
entenderla. Lo nico interesante sobre son las relaciones que mantiene con las otras entidades.

www.javatutoriales.com/2009/09/hibernate-parte-7-hql-primera-parte.html

6/25

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 7: HQL Primera Parte


Ahora que tenemos las entidades no olvidemos que debemos indicarlas en el archivo hibernate.cfg.xml:

<mapping class="hql.modelo.Permiso" />


<mapping class="hql.modelo.Usuario" />
<mapping class="hql.modelo.Direccion" />

Ahora que tenemos todo configurado comencemos propiamente con el tutorial.


Para los ejercicios usaremos una base de datos llamada "hibernatehql", en MySQL.
Lo siguiente que debemos saber sobre las consultas en HQL es que, como mencione antes, trabajamos usando los nombres de las
clases; esto quiere decir que si tenemos una clase entidad llamada Usuario en el paquete hql.modelo, cuyos registros se guardan
en una tabla usuarios, NO colocamos el nombre de la tabla en las consultas, sino el nombre de la clase. O sea en vez de hacer algo
asi:

SELECT u.col_username FROM usuarios u

Haramos

SELECT u.username FROM hql.modelo.Usuario u

O tambin podemos hacer:

SELECT u.username FROM Usuario u

De la misma forma si el valor del atributo username del usuario se guarda en la columna col_username hacemos referencia a este
valor con el nombre del atributo: username y no con el nombre de la columna.
Ahora veremos las clausulas con las que podemos formar una sentencia:

CARACTERSTICAS DE HQL
Estas son algunas de las caractersticas ms importantes que nos proporciona HQL:
Soporte completo para operaciones relacionales: HQL permite representar consultas SQL en forma de objetos. HQL usa
clases y atributos o propiedades en vez de tablas y columnas.
Regresa sus resultados en forma de objetos: Las consultas realizadas usando HQL regresan los resultados de las mismas
en la forma de objetos o listas de objetos, que son ms fciles de usar, ya que eliminan la necesidad de crear un objeto y
llenarlo con los datos obtenidos de un ResultSet (como hacemos normalmente cuando trabajamos con JDBC).
Consultas Polimrficas: Podemos declarar el resultado usando el tipo de la superclase y Hibernate se encargara de crear los
objetos adecuados de las subclases correctas de forma automtica.
Fcil de Aprender: Es muy similar a SQL estndar, as que si has trabajado con SQL, HQL te resultar muy fcil.
Soporte para caractersticas avanzadas: HQL contiene muchas caractersticas avanzadas que son muy tiles y que no
siempre estn presentes en todas las bases de datos, o no es fcil usarlas, como paginacin, fetch joins con perfiles
dinmicos, inner y outer joins, etc. Adems soporta proyecciones, funciones de agregacin (max, avg), y agrupamientos,
ordenamientos, y subconsultas.
Independiente del manejador de base de datos: Las consultas escritas en HQL son independientes de la base de datos
(siempre que la base de dats soporte la caracterstica que estamos intentando utilizar ^-^).
Bueno, ahora que sabemos un poco de HQL veamos cmo usarlo. Para ver los resultados arrojados por las consultas no necesitaremos
crear una aplicacin, ya que NetBeans nos permite ejecutar estas directamente desde un editor especial. Pero para usarlo debemos
configurar algunas otras cosas, que explicar a continuacin.

CONFIGURANDO EL NETBEANS PARA LOS EJEMPLOS


Lo primero que debemos hacer es crear nuestra base de datos en MySQL con las tablas y datos de prueba necesarios. Creamos una
base de datos llamada hibernatehql con cuatro tablas: direcciones, permisos, usuarios, y usuarios_permisos.

www.javatutoriales.com/2009/09/hibernate-parte-7-hql-primera-parte.html

7/25

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 7: HQL Primera Parte


Esta ltima tabla mantendr las relaciones entre usuariosy permisos. Pueden usar el siguiente script para crear y poblar la base de
datos, o si lo desean pueden descargarlo desde aqu:

CREATE DATABASE IF NOT EXISTS `hibernatehql`;


USE `hibernatehql`;
/*Estructura de la tabla `direcciones` */
DROP TABLE IF EXISTS `direcciones`;
CREATE TABLE `direcciones` (
`id` BIGINT(20) NOT NULL AUTO_INCREMENT,
`calle` VARCHAR(255) DEFAULT NULL,
`codigoPostal` VARCHAR(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=INNODB DEFAULT CHARSET=latin1;

/*Datos de la tabla `direcciones` */


insert into `direcciones`(`id`,`calle`,`codigoPostal`) values (1,'Calle1','12345'),(2,'Calle2','5
4321');
/*Estructura de la tabla `permisos` */
DROP TABLE IF EXISTS `permisos`;
CREATE TABLE `permisos` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`estatus` int(11) DEFAULT NULL,
`nombre` varchar(255) DEFAULT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=latin1;
/*Datos de la tabla `permisos` */
insert into `permisos`(`id`,`estatus`,`nombre`) values (1,0,'Lectura Archivos'),(2,0,'Creacion Ar
chivos'),(3,1,'Eliminacion Archivos'),(4,1,'Moficacion Archivos'),(5,2,'Sin Permisos');
/*Estructura de la tabla `usuarios` */
DROP TABLE IF EXISTS `usuarios`;
CREATE TABLE `usuarios` (
`id` bigint(20) NOT NULL AUTO_INCREMENT,
`nombre` varchar(255) DEFAULT NULL,
`password` varchar(255) DEFAULT NULL,
`username` varchar(255) DEFAULT NULL,
`direccion_id` BIGINT(20) DEFAULT NULL,
PRIMARY KEY (`id`),
KEY `FK_DIRECCIONES` (`direccion_id`),
CONSTRAINT `FK_DIRECCIONES` FOREIGN KEY (`direccion_id`) REFERENCES `direcciones` (`id`)
) ENGINE=INNODB AUTO_INCREMENT=2 DEFAULT CHARSET=latin1;

/*Datos de la tabla `usuarios` */


insert into `usuarios`(`id`,`nombre`,`password`,`username`,`direccion_id`) values (1,'Usuario 1',
'abcdefg','usr001',1),(2,'Usuario1','hijklm','usr456',2),(3,'Usuario3','alex','alex',null);
/*Estructura de la tabla `usuarios_permisos` */
DROP TABLE IF EXISTS `usuarios_permisos`;
CREATE TABLE `usuarios_permisos` (
`usuarios_id` bigint(20) NOT NULL,
`permisos_id` bigint(20) NOT NULL,
UNIQUE KEY `permisos_id` (`permisos_id`),
KEY `FK_USUARIOS` (`usuarios_id`),
KEY `FK_PERMISOS` (`permisos_id`),
CONSTRAINT `FK_PERMISOS` FOREIGN KEY (`permisos_id`) REFERENCES `permisos` (`id`),
CONSTRAINT `FK_USUARIOS` FOREIGN KEY (`usuarios_id`) REFERENCES `usuarios` (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1;
/*Datos de la tabla `usuarios_permisos` */
INSERT INTO `usuarios_permisos`(`usuarios_id`,`permisos_id`) VALUES (1,1),(1,2),(2,3),(2,4),(3,5)
;

Ahora vayamos al NetBeans.


Anteriormente, cuando instalamos plugins en el NetBeans y lo configuramos para usar el tomcat, usamos un panel llamado Services,
el cual nos permite agregar servicos y herramientas externas (servidores web y de aplicaciones, bases de datos, servicios web, etc.) para

www.javatutoriales.com/2009/09/hibernate-parte-7-hql-primera-parte.html

8/25

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 7: HQL Primera Parte


tener acceso a ellos dentro de NetBeans.
En esta ocasin agregaremos un servicio que nos permitir tener una conexin a nuestra base de datos de prueba.

En el panel Services hacemos clic derecho sobre el nodo Databases y en el men contextual que se abre seleccionamos la opcin
New Connection

Con lo que se abrir la ventana New Database Connection. En esta ventana podemos escribir directamente la URL de la conexin
(jdbc:mysql://), o escribir algunos parmetros y dejar que la URL se genere automticamente. Nosotros haremos este ltimo.
Lo primero que hacemos es seleccionar, en el campo Name la opcin MySQL (Connector/J driver). El resto de los datos se
obtienen de su conexin a su servidor de base de datos.

Usen los datos propios de su servidor para conectarse. Al final, con los datos de mi conexin, la ventana queda as:

Les recomiendo que habiliten la opcin Remember password y Show JDBC URL. Hacemos clic en el botn OK y veremos que en
el panel Services, en el nodo Databases aparecer la conexin a nuestra base de datos. En caso de que haya un error aparecer
el mensaje correspondiente para que podamos corregirlo.

www.javatutoriales.com/2009/09/hibernate-parte-7-hql-primera-parte.html

9/25

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 7: HQL Primera Parte

Gracias a esta configuracin ahora podremos ejecutar sentencias de SQL directamente en NetBeans:

Pero, lo ms importante, es que tambin podemos ejecutar sentencias HQL desde el NetBeans, sin necesidad de crear una aplicacin:

Ser esta forma en la que ejecutaremos las clausulas durante este tutorial.
Veremos las clausulas ms comunes de este lenguaje y haremos ejemplos usando nuestras entidades.

LA CLAUSULA FROM
La clausula ms simple que existe en Hibernate es FROM. Esta clausula regresa todas las instancias de la clase indicada que se
encuentran en la base de datos, es como si hiciramos un SELECT * en MySQL. Por ejemplo, para recuperar todos los usuarios de la
base de datos ejecutamos la consulta de esta forma:

FROM hql.modelo.Usuario

Normalmente no necesitamos el fully qualified name de la clase, as que esta misma sentencia podramos escribirla de esta forma:

FROM Usuario

Al ejecutar esta sentencia en NetBeans, con los datos de la base de pruebas que creamos, obtendremos el siguiente resultado:

www.javatutoriales.com/2009/09/hibernate-parte-7-hql-primera-parte.html

10/25

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 7: HQL Primera Parte

Dentro de esta clausula FROM podemos colocar el nombre de ms de una clase, lo que resultar en un producto cartesiano entre las
entidades que coloquemos. Podemos colocar el nombre de dos de nuestras entidades en la clausula, de esta forma:

FROM Usuario, Permiso

Resultando en la siguiente salida:

Aqu se muestra un todos contra todos (producto cartesiano) ya que no colocamos ninguna restriccin en cuanto a las condiciones que
deben cumplir los objetos.
Cuando tenemos que referirnos a nuestras clases en otras partes de la consulta, como en las restricciones, debemos asignarle un alias y
hacer referencia a la clase a travs de este alias. No podemos usar directamente el nombre del objeto ya que resultara en una excepcin.
Por ejemplo, continuando con la consulta anterior, si quisiramos hacer referencia al id del Usuario, si lo hacemos de esta forma:

FROM Usuario, Permiso WHERE Usuario.id = 1

Obtendramos la siguiente excepcin:

En vez de esto debemos asignarle un alias a la clase entidad "Usuario" y hacer referencia a los atributos de esta entidad usando el
alias, de esta forma:

www.javatutoriales.com/2009/09/hibernate-parte-7-hql-primera-parte.html

11/25

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 7: HQL Primera Parte

FROM Usuario as u, Permiso WHERE u.id = 1

O as:

FROM Usuario u, Permiso WHERE u.id = 1

Resultando en la salida esperada:

ASOCIACIONES Y JOINS
HQL tambin permite los siguientes cuatro tipos de joins entre entidades:
Inner Join
Left Outer Join
Right Outer Join
Full Join (siempre que la base de datos que estemos usando los soporte)
Adems tambin podemos asignar alias a las entidades asociadas o a los elementos de una coleccin de valores usando un join, por
ejemplo:

FROM Usuario u inner join u.permisos as p

Con su correspondiente salida

Tambin podemos proporcionar condiciones extra al join con la palabra reservada WITH:

FROM Usuario u inner join u.permisos as p WITH p.estatus = 1

www.javatutoriales.com/2009/09/hibernate-parte-7-hql-primera-parte.html

12/25

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 7: HQL Primera Parte

La parte que voy a explicar es muy importante y nos resultar muy til cuando trabajemos con colecciones de objetos. Recuerdan que
cuando vimos las relaciones uno a muchos, dije que en la relacin podemos indicar la forma de fetcho recuperacin de los elementos
de la coleccin? Y que estos tipos solo son 2: EAGERy LAZY?
Cuando tenemos una coleccin con tipo de fetch EAGER no hay problema, al recuperar la entidad recuperaremos tambin todos los
objetos de la coleccin. Pero qu ocurre cuando el tipo de fetch es LAZY? En ese caso necesitamos recuperar los elementos de la
coleccin de otra forma.
Pues bien, esto puede hacerse usando un tipo especial de join llamado "fetch" join, el cual nos permite inicializar los elementos de
estas asociaciones o colecciones. Este fetch join sobreescribe la declaracin de fetch LAZYde la coleccin (solo para la consulta que
se est realizando).
Por ejemplo, nosotros tenemos en nuestra entidad "Usuario" declarada la lista de permisos de la siguiente forma:

@OneToMany(cascade=CascadeType.ALL, fetch=FetchType.LAZY)
private List<Permiso> permisos = new ArrayList<Permiso>();

Esto quiere decir que cuando recuperemos, ya dentro de una aplicacin, al Usuario, sus permisos no sern recuperados e
inicializados en ese momento. Esto es til si estamos, por ejemplo, mostrando una lista de usuarios y no nos interesa mostrar nada
relacionado con sus permisos en ese momento. Pero qu ocurre cuando el usuario ingresa a la aplicacin y nos interesa validar los
permisos que tiene? En ese caso si debemos recuperar la lista de permisos. Pues bien, es para esto que nos sirve el fetch join, y se usa
de la siguiente forma:

FROM Usuario u inner join fetch u.permisos

Recuerden que aunque la instruccin se llama fetch join la usamos al revs ("join fetch"). Y con esto se recuperarn los permisos del
usuario al mismo tiempo que el usuario. En el editor de HQL de NetBeans esto no se logra apreciar bien, pero cranme, cuando estn
realizando una aplicacin esto puede salvarnos la vida ^-^.

SINTAXIS DE LOS JOINS


HQL soporta dos sintaxis para los joins: implcita y explcita.
En los ejemplos anteriores hemos estado usando la forma explcita, o sea, que colocamos la palabra joindentro de la clausula. Esta
es la forma recomendada ya que es ms clara, sin embargo si queremos ahorrar un poco de espacio podemos usar la forma implcita
de esta manera:

www.javatutoriales.com/2009/09/hibernate-parte-7-hql-primera-parte.html

13/25

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 7: HQL Primera Parte


Como vemos, ocurre un join implcito entre "Usuario" y "Direccin", usando el atributo direccinde la clase Usuario. Lo malo de
este tipo de joins es que solo puede hacerse cuando tenemos una relacin uno a uno o muchos a uno, o sea, no
funciona cuando la propiedad es una coleccin:

PREGUNTANDO POR EL IDENTIFICADOR


En HQL existen dos formas de referirnos a la propiedad que sirve como identificador de la entidad:
La propiedad especial id (as con minsculas). No importa si la clase entidad no tiene una propiedad llamada id.
Si la entidad define una propiedad identificador, podemos referirnos a ella a travs del nombre de dicha propiedad (en el caso
de estos ejemplos la propiedad identificadora es llamada id, as que no me ser posible ejemplificar esto claramente).
Importante: Esto quiere decir que si nuestra entidad tiene un atributo llamado id, pero esto no es el identificador de la entidad, no
habr forma de hacer referencia a l.

LA CLAUSULA SELECT
La clausula SELECT indica cules objetos y propiedades se regresarn en el conjunto de resultados de la consulta (as es, podemos
regresar solamente algunas propiedades de los objetos y no todo el objeto, pero esto lo veremos ms adelante).
Supongamos que tenemos la siguiente consulta:

SELECT dir FROM Usuario as u inner join u.direccion as dir

Esta consulta regresar la direccionde los usuarios. Podemos expresar esta misma consulta de una forma ms compacta haciendo
uso de los joins implcitos:

SELECT u.direccion FROM Usuario as u

Como dije hace un momento: podemos recuperar solo algunos atributos o valores del objeto que estemos regresando. Por ejemplo, la
siguiente consulta regresa solo el nombre del usuario:

SELECT u.nombre FROM Usuario as u

En la ventana de ejecucin del HQL en el NetBeans, vemos el resultado de esta forma:

www.javatutoriales.com/2009/09/hibernate-parte-7-hql-primera-parte.html

14/25

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 7: HQL Primera Parte

Intentar dar una explicacin al porqu se ven de esta forma los datos. Si me equivoco en la explicacin por favor corrjanme.
Cuando recuperamos solo un atributo de un objeto, recuperamos una lista de objetos del tipo del atributo que queremos recuperar (si es
Stringrecuperamos Strings, si es intrecuperamos ints, etc.).
Sin embargo, si recuperamos ms de un atributo de un objeto, Hibernate NO nos regresa una lista del tipo de objeto (en este caso
"Usuario"), si no que nos regresa una lista de arreglos de objetos, o sea, una lista en la que cada uno de los elementos es un arreglo
de objetos. Cada uno de los objetos del arreglo representa uno de los valores recuperados. Como nosotros solo estamos recuperando
el valor de una propiedad (el nombre del usuario) vemos que en el NetBeans solo tenemos un valor en cada fila (no tengo idea de porqu
muestra varias filas). Como Hibernate no sabe (o no le importa) el tipo del objeto que es el valor del atributo cuando lo regresa, solo que es
un objeto, nos regresa un arreglo de bytes (finalmente todo objeto es un arreglo de bytes) y es esto lo que vemos en los valores
regresados (cuando tenemos que un valor empieza solo con un corchete que abre ([) significa que el valor es un arreglo.
Como supongo que algunos de ustedes no me creern que esto funciona, tendr que demostrarlo en cdigo ^_^.
Como siempre, usaremos la clase HibernateUtil desarrollada antes, la del segundo tutorial, ya que estamos trabajando con
anotaciones.
Como vamos a hacer varios pequeos ejemplos, crearemos un mtodo para cada uno y lo invocaremos en el constructor de la clase
Main. Despus iremos comentando y des-comentando las invocaciones a los mtodos para ver su funcionamiento individual.
Adems crearemos un atributo de instancia en nuestra clase Mainque nos ayudar a manejar las conexiones en todos los mtodos.
Esta variable ser de tipo org.hibernate.Session, la declararemos de esta forma:

private Session sesion;

Y dos mtodos de utilidad. El primero crear una nueva sesin a la base de datos e iniciar una transaccin. El segundo mtodo terminar
la transaccin y cerrar la conexin.
Este es el mtodo que inicia la sesin:

private void inciaOperacion()


{
SessionFactory sessionFactory = new AnnotationConfiguration().configure().buildSessionFact
ory();
sesion = sessionFactory.openSession();
sesion.getTransaction().begin();
}

Y este es el mtodo que la termina:

private void terminaOperacion()


{
sesion.getTransaction().commit();
sesion.close();
}

Ahora crearemos el mtodo que recuperar solo el nombre del usuario haciendo uso de la consulta anterior.
Hasta ahora no habamos realizado consultas con HQL, as que tendr que explicar cmo usarlas en cdigo.
Con Hibernate normalmente haremos consultas el HQL (tambin podemos hacer consultas en el SQL de la base de datos que estemos
usando, pero no hablar de eso). Para ejecutar una consulta en HQL necesitamos un objeto de tipo org.hibernate.Query. Query
es una interface, por lo que necesitamos una clase que la implemente para usarla.
Afortunadamente el objeto org.hibernate.Session que estamos usando (sesion) tiene un mtodo que nos permite obtener un

www.javatutoriales.com/2009/09/hibernate-parte-7-hql-primera-parte.html

15/25

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 7: HQL Primera Parte


objeto de este tipo:

Query query = sesion.createQuery("Aqu ira nuestra consulta");

En el lugar que he indicado con la cadena Aqu ira nuestra consulta es donde colocaremos el HQL que estemos usando.
Estas consultas pueden ser bsicamente de tres tipos:
Bsquedas de listas de resultados (este es el tipo de consulta que hemos estado haciendo hasta el momento)
Bsquedas de un objeto nico
Actualizaciones de datos (actualizaciones o eliminaciones)
Cada una de estas operaciones la realizamos con un mtodo especfico de la interface Query:

query.list();
//Para las listas de resultados
query.uniqueResult(); //Para los objetos unicos
query.executeUpdate(); //Para las actualizaciones de datos

Nosotros usaremos el primer mtodo (list()) en los siguientes ejemplos.


Bien, ahora si veamos el mtodo.
Crear este mtodo ser muy sencillo. Bsicamente lo que haremos es crear un nuevo mtodo, colocar los dos mtodos auxiliares que
creamos anteriormente, obtener un objeto query, colocarle la consulta anterior, e invocar a su mtodo list.
El mtodo, para no hacer la explicacin ms aburrida, queda de esta forma:

private void obtenNombres()


{
iniciaOperacion();
Query query = sesion.createQuery("SELECT u.nombre FROM Usuario as u");
List<String> listaResultados = query.list();
for (int i = 0; i < listaResultados.size(); i++)
{
System.out.println("Nombre " + i + ": " + listaResultados.get(i));
}
terminaOperacion();
}

Ahora, solo nos queda colocar la siguiente llamada en el mtodo main:

new Main();

y esto en el constructor de Main:

obtenNombres();

La clase Maindebe quedar as:

www.javatutoriales.com/2009/09/hibernate-parte-7-hql-primera-parte.html

16/25

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 7: HQL Primera Parte

public class Main


{
private Session sesion;
public Main()
{
obtenNombres();
}
public static void main(String[] args)
{
new Main();
}
private void iniciaOperacion()
{
SessionFactory sessionFactory = new AnnotationConfiguration().configure().buildSessionFact
ory();
sesion = sessionFactory.openSession();
sesion.getTransaction().begin();
}
private void terminaOperacion()
{
sesion.getTransaction().commit();
sesion.close();
}
private void obtenNombres()
{
iniciaOperacion();
Query query = sesion.createQuery("SELECT u.nombre FROM Usuario as u");
List<String> listaResultados = query.list();
for (int i = 0; i < listaResultados.size(); i++)
{
System.out.println("Nombre " + i + ": " + listaResultados.get(i));
}
terminaOperacion();
}
}

Ahora, al ejecutar la aplicacin vemos la siguiente salida:

Como vemos, obtuvimos solamente los nombres, justo como esperbamos ^-^.
La clausula SELECTtambin nos permite recuperar mltiples objetos y/o propiedades de objetos. Es este caso ocurre lo que expliqu
anteriormente: recuperamos una lista de arreglos de objetos. Para comprobar esto, crearemos una consulta que recuperar el
nombrey el passwordde un usuario.
Coloquemos la siguiente clausula en el ejecutor de HQLde NetBeans:

SELECT u.nombre, u.password FROM Usuario as u

Con lo que obtenemos la siguiente salida:

www.javatutoriales.com/2009/09/hibernate-parte-7-hql-primera-parte.html

17/25

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 7: HQL Primera Parte

Como esta salida tambin es poco clara, crearemos un nuevo mtodo para ver que, efectivamente, estemos recuperando una lista de
arreglos de objetos con los valores indicados.
Como en este caso estamos recuperando dos valores (nombre y password), el primer elemento del arreglo (el elemento 0) ser el
nombre, y el segundo (el elemento 1) ser el password:

private void obtenNombresYPasswords()


{
iniciaOperacion();
Query query = sesion.createQuery("SELECT u.nombre, u.password FROM Usuario as u ");
List<Object[]> listaResultados = query.list();
for (int i = 0; i < listaResultados.size(); i++)
{
System.out.println("Nombre " + i + ": " + listaResultados.get(i)[0] + ", password: " +
listaResultados.get(i)[1]);
}
terminaOperacion();
}

Cuando ejecutamos este cdigo obtenemos la siguiente salida:

Como vemos, al hacer

listaResultados.get(i)[0]

Obtenemos el nombreque se encuentra en el primer elemento del arreglo, y al hacer

listaResultados.get(i)[1]

Obtenemos el passwordque se encuentra en el segundo elemento del arreglo, justo como habamos predicho ^-^.
Aunque esto que acabamos de ver nos resultar bastante til cuando no necesitemos todo el objeto (ya que nos ahorrar mucha
memoria) puede parecernos un poco raro trabajar con arreglos de objetos; ms a los que estamos acostumbrados solo a las listas ( ^-^!).
Para personas como yo, Hibernate nos permite recuperar estos valores dentro de una lista, en vez del arreglo de objetos, usando una
notacin especial. A partir de aqu veremos algunas sintaxis extraas, pero no se preocupen, que con el tiempo nos acostumbraremos a
verlas.

www.javatutoriales.com/2009/09/hibernate-parte-7-hql-primera-parte.html

18/25

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 7: HQL Primera Parte


Para recuperar los mismos datos que en el ejemplo anterior, pero con una lista en vez de un arreglo de objetos, debemos escribir la
consulta de la siguiente forma:

SELECT new list(u.nombre, u.password) FROM Usuario as u

Como vemos la consulta es muy similar a la anterior, pero con ese extrao elemento new list. Coloqumonos en el NetBeans:

Como podemos ver el NetBeans tampoco nos ayuda mucho cuando trabajamos con este tipo de consultas u.u, as que tendremos que
crear nuevamente un mtodo:

private void obtenNombresYPasswordsComoLista()


{
iniciaOperacion();
Query query = sesion.createQuery("SELECT new list(u.nombre, u.password) FROM Usuario as u ");
List<List> listaResultados = query.list();
for (int i = 0; i < listaResultados.size(); i++)
{
System.out.println("Nombre " + i + ": " + listaResultados.get(i).get(0) + ", password: " +
listaResultados.get(i).get(1));
}
terminaOperacion();
}

Con lo que obtenemos la siguiente salida:

Como podemos ver, obtuvimos el mismo resultado que en la ocasin anterior, pero ahora en vez de hacer esto:

listaResultados.get(i)[0]
listaResultados.get(i)[1]

Hacemos esto:

www.javatutoriales.com/2009/09/hibernate-parte-7-hql-primera-parte.html

19/25

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 7: HQL Primera Parte

listaResultados.get(i).get(0)
listaResultados.get(i).get(1)

Podemos incluso recuperar un objeto propio pasando los valores a su constructor o recuperar un Map. Pero eso escapa al propsito de
este tutorial.
Y como me he tardado ms de lo esperado en escribir este tutorial, lo dejar hasta aqu en este momento y lo terminar en una segunda
parte. Falta ver un poco de la sentencia WHERE, funciones de agregacin, y sub-consultas, as que espero sea un poco ms corto.
No olviden dejar todas sus dudas y comentarios. Tambin pongan lo que les gustara ver en el siguiente tutorial.
Saludos.
Entradas Relacionadas:
Parte 1: Persistiendo Objetos Simples usando Mapeos en XML
Parte 2: Persistiendo Objetos Simples usando Anotaciones (Metadatos)
Parte 3: Relaciones / Uno a uno
Parte 4: Relaciones / Uno a muchos
Parte 5: Relaciones / Muchos a uno
Parte 6: Relaciones / Muchos a Muchos
Parte 8: HQL Segunda Parte
Parte 9: Parmetros en HQL
Parte 10: Herencia
Parte 11: Interceptores y Eventos
Publicado por Alex en 21:18

divertido (0)

Reacciones:

interesante (0)

increible (0)

no me gusta (0)

+5 Recomendar esto en Google


Etiquetas: hibernate, hql, java

33 comentarios:
erictwo2 7 de octubre de 2009 16:38
Que tal Alex. Te doy las gracias por esforzarte y ayudarnos a todos los que nos iniciamos en hibernate! Eh bajado un monton de
tutoriales pero ninguno tiene tu calidad y claridad. De verdad muchas Gracias! Lo que me gustaria ver mas adelante es si podes dar una
pasadita en como usar Hibernmate junto con Spring ya que por lo que eh visto es muy interesante, pero todavia no tengo claro ciertas
cosas! Eh logrado hacer andar un programa usando esta tecnologia con un par de relaciones medias complejas y la verdad que Spring
simplifica bastante ciertas cosas y me gustaria mucho ver tu explicacion! Desde ya muchas gracias por todo. Saludos Eric Hidalgo
Responder

Alex

7 de octubre de 2009 20:06

Hola Eric;
Muchas gracias por tus comentarios, hago lo mejor que puedo.
Me gustara pronto poder escribir un tutorial de Spring ya que me gusta mucho; y como dices simplifica mucho las cosas.
Ser cosa de que me haga un tiempo y lo escriba, tal vez terminando esta serie sobre Hibernate ^-^.
Saludos
Responder

Jorge Luis 14 de octubre de 2009 16:06


Hola Amigo Gracias por tus tutoriales. Mi pregunta sale un poco del tema de HQl, lo que quiero saber es como creo reportes en ireport
con hibernate.
el ireport lo tengo como plugin en netbeans, mis clases son con anotaciones.
lo que hago es agrego el jar de mi aplicacion al classpach de ireport. Al realizar un nuevo reporte y creo la coneccion con hibernate y al
hacer el test obtengo como resultado que se realizo correctamente, pero para realizar mi consulta no carga ninguna de mis clases, y
cuando escribo la consulta directa osea escribo "From com.MegaSoft.endrago.Clases.Clientes" esa es la direccion de mi clase, obtengo
como resultado null. y no se como hacerlo, agradeceria mucho si me ayudaras con mi problema gracias.
Responder

Alex

14 de octubre de 2009 21:19

Hola Jorge;
Muchas gracias por tus comentarios, hago lo que puedo para que se encientan lo mejor posible.
Lamentablemente creo que no puedo ayudarte con tu pregunta ya que nunca he utilizado Hibernate junto con JasperReports como me
parece que tu lo estas usando, as que no se que es lo que pueda estar ocurriendo.
Tratar de hacer un ejemplo para darme una idea de cmo funcionan estas dos tecnologas juntas para ver si puedo ayudarte.

www.javatutoriales.com/2009/09/hibernate-parte-7-hql-primera-parte.html

20/25

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 8: HQL Segunda Parte


Compartir

Ms

Siguiente blog

Tutoriales de Programacion Java


Blog dedicado a temas de programacin actuales usando el lenguaje de programacin Java y las ltimas versiones de sus APIs y Herramientas.
Pgina principal

Pgina de Concursos

Tutoriales UPAO 2010

Presentaciones Capacitacin

SBADO, 22 DE MAYO DE 2010

Hibernate - Parte 8: HQL Segunda Parte

DONACIONES

En el tutorial anterior vimos una introduccin al lenguaje de consultas de Hibernate, el Hibernate Query Language(HQL) y vimos
algunas de sus caractersticas.
Tambin vimos como ejecutar consultas desde el editor del NetBeans, y desde cdigo dentro de una aplicacin de ejemplo.
En esta segunda parte veremos el resto de las clausulas que componen este lenguaje y seguiremos con ejemplos en cdigo.
Lo ltimo que vimos fue como recuperar una lista con solo algunos valores de un objeto y colocarlos en un objeto java.util.List
usando una sentencia SELECTcon la sintaxis SELECT NEW LIST.
Esta no es la nica forma en la que podemos recuperar valores de un objeto dentro de una coleccin. Adems tenemos la opcin de
recuperar una lista de objetos tipo java.util.Map, en donde las llaves son las columnas que queremos consultar, y los valores
son los valores recuperados de la base de datos.
Por ejemplo, si queremos recuperar el "identificador", "nombre", y "password" de los usuarios, dejando estos datos en un
java.util.Map usamos la siguiente sentencia:

SELECT new map(u.id AS identificador, u.nombre AS nombre, u.password AS pass) FROM Usuario as u

JAVA TUTORIALES EN FACEBOOK

Java Tutoriales
Me gusta

Java Tutoriales

Amigo programador,
ests todo el da pica
cdigo, escucha esta
recomendaciones sl
hechas para ti..... q
esto?... Gracias Jorg
Rubira....

No olviden poner la
sentencia where al ha
un borraro en la base
datos..

http://www.youtube.c
watch?v=i_cVJgIz_Cs
En donde vemos que ahora usamos la clausula SELECTseguido de la sentencia NEW MAP, y los valores que deseamos recuperar dentro
del mapa. Dentro de esta clausula colocamos como alias lo que sern las llaves, y como valores las columnas que queremos
recuperar. As tendremos como llaves identificador, nombre, y pass, y como valores el id, nombre, y password del
Usuario.

A 7895 personas les gusta

Creamos un mtodo para comprobar la salida de esta consulta:

private void obtenNombresYPasswordsComoMapa()


{
iniciaOperacion();

Plug-in social de Facebook

Query query = sesion.createQuery("SELECT new map(u.id as identificador, u.nombre as nombre, u.


password as pass) FROM Usuario as u ");
List<Map> listaResultados = query.list();
for (int i = 0; i < listaResultados.size(); i++)
{
Map mapa = listaResultados.get(i);
System.out.println("Datos del mapa " + i);
Set llaves = mapa.keySet();
for(Iterator<String> it = llaves.iterator(); it.hasNext();)
{
String llaveActual = it.next();
System.out.println("\tLlave: " + llaveActual + ", valor: " + mapa.get(llaveActual));
}
}
terminaOperacion();
}

Cuando ejecutamos este mtodo obtenemos la siguiente salida:

www.javatutoriales.com/2010/05/hibernate-parte-8-hql-segunda-parte.html

1/19

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 8: HQL Segunda Parte

Podemos ver que, efectivamente, obtenemos como llave lo que colocamos como alias, y los valores de las columnas que solicitamos, de
los tres Usuarios que existen en la base de datos.
El recuperar los valores dentro de listas o dentro de mapas es algo muy til y que nos ahorrar mucho esfuerzo en nuestras aplicaciones.
Sin embargo Hibernate nos proporciona una forma an ms til que podemos usar. De hecho podemos recuperar una lista de objetos
propios, el cual reciba en su constructor los valores que estamos recuperando. Esto es muy til cuando tenemos que recuperar datos
que posteriormente debern ser mostrados en un reporte. Podramos, por ejemplo, querer recuperar los datos de un usuario y la cantidad
total de las compras que ha realizado en un sitio y colocar estos datos en objeto para luego solo extraer los datos de estos objetos en el
reporte.
Crearemos una clase UsuarioDireccion, en el paquete modelo, que mantendr el nombre del Usuario, su calle y cdigo
postal, y el nmero de permisos que tiene (an no hemos visto las funciones de agregacin, de las que COUNTforma parte, pero
nos servir para ir practicando).
La clase "UsuarioDireccin" se muestra a continuacin:

SEGUIDORES

Participar en este sitio


Google Friend Connect

Miembros (173) Ms

Ya eres miembro? Iniciar sesin

ARCHIVO DEL BLOG

2012 (2)
2011 (11)
2010 (10)
diciembre (1)
octubre (3)
septiembre (2)
agosto (2)
julio (1)
mayo (1)

Hibernate - Parte 8: HQL Segu


2009 (22)

www.javatutoriales.com/2010/05/hibernate-parte-8-hql-segunda-parte.html

2/19

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 8: HQL Segunda Parte

public class UsuarioDireccion


{
private String nombre;
private String calle;
private String codigoPostal;
private long numeroPermisos;
public UsuarioDireccion(String nombre, String calle, String codigoPostal, long numeroPermisos)
{
this.nombre = nombre;
this.calle = calle;
this.codigoPostal = codigoPostal;
this.numeroPermisos = numeroPermisos;
}
public String getCalle()
{
return calle;
}
public void setCalle(String calle)
{
this.calle = calle;
}
public String getCodigoPostal()
{
return codigoPostal;
}
public void setCodigoPostal(String codigoPostal)
{
this.codigoPostal = codigoPostal;
}

DATOS PERSONALES

Alex

public String getNombre()


{
return nombre;
}
public void setNombre(String nombre)
{
this.nombre = nombre;
}

Programador Java con algunos


experiencia en mltiples poyec
mltiples APIs y herramientas d
compartir experiencias con el
programadores.
Ver todo mi perfil

public long getNumeroPermisos()


{
return numeroPermisos;
}
public void setNumeroPermisos(long numeroPermisos)
{
this.numeroPermisos = numeroPermisos;
}
}

Como podemos ver, esta clase solo tiene un constructor que recibe los cuatro parmetros que mencion antes.
Regresaremos una lista con los valores de Usuario Direccin, adems del nmero de Permisos que tiene cada uno de los
Usuarios, que hay en la base de datos. Estos valores sern regresados en objetos de la clase UsuarioDireccion. Para lograr esto
usamos la siguiente sentencia:

SELECT NEW hql.modelo.UsuarioDireccion(u.nombre, d.calle, d.codigoPostal, COUNT(p)) FROM Usuario u


left outer join u.direccion as d left outer join u.permisos as p GROUP BY u.id

Como vemos ahora usamos la sentencia SELECT seguida de algo que parece la invocacin del constructor de la clase
hql.modelo.UsuarioDireccion, de esta forma:

hql.modelo.UsuarioDireccion(u.nombre, d.calle, d.codigoPostal, COUNT(p))

A la cual le pasamos los cuatro parmetros que recibe el siguiente constructor:

www.javatutoriales.com/2010/05/hibernate-parte-8-hql-segunda-parte.html

3/19

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 8: HQL Segunda Parte

public UsuarioDireccion(String nombre, String calle, String codigoPostal, long numeroPermisos)

En la sentencia anterior es necesario usar la clausula GROUP BY, con el identificador del Usuario, ya que estamos usando una funcin
de agregacin (COUNT). Ms adelante me adentrar un poco ms en esto.
Adems podemos ver que estamos usando un LEFT OUTER JOINpara que nos regrese los datos de los Usuarios aunque estos no
tengan ni Direcciones ni Permisos. Pueden encontrar ms informacin de cmo funcionan los distintos joins en esta pgina.
Si ejecutamos esta sentencia en el NetBeans obtendremos el siguiente resultado:

Con lo que podemos ver que los Usuarios 1 y 2 tienen sus datos de Direcciony 2 Permisos cada uno, mientras que el Usuario3
no tiene datos de Direccion, y tiene un Permiso.
Creemos un mtodo para poder recuperar estos mismos datos desde nuestra aplicacin:

private void obtenUsuariDireccion()


{
iniciaOperacion();
Query query = sesion.createQuery("SELECT NEW hql.modelo.UsuarioDireccion(u.nombre, d.calle, d.
codigoPostal, COUNT(p)) FROM Usuario u left outer join u.direccion as d left outer join u.permisos
as p GROUP BY u.nombre");
List<UsuarioDireccion> listaResultados = query.list();
for (int i = 0; i < listaResultados.size(); i++)
{
UsuarioDireccion usuarioDireccion = listaResultados.get(i);
System.out.println("->" + usuarioDireccion.getNombre() + ", permisos: " + usuarioDireccion
.getNumeroPermisos());
}
terminaOperacion();
}

Con lo que obtenemos la siguiente salida:

La cual podemos observar que es la misma que obtuvimos del editor HQL del NetBeans.
Con esto terminamos todo lo relativo a la clausula SELECTque Hibernate nos proporciona. Ahora veremos cmo funcionan las funciones
de agregacin.

Las funciones de Agregacin


En el mundo de SQL las funciones de agregacin trabajan sobre conjuntos de filaspara dar un resultado correspondiente a ese
grupo. Afortunadamente para nosotros en HQL las funciones de agregacin funcionan exactamente igual que en SQL. De hecho HQL
soporte las mismas funciones que SQL:

www.javatutoriales.com/2010/05/hibernate-parte-8-hql-segunda-parte.html

4/19

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 8: HQL Segunda Parte


AVG(), SUM(), MIN(), MAX()
COUNT(*)
COUNT(), COUNT(DISTINCT ), COUNT(ALL )
En el ejemplo anterior hicimos uso de la funcin COUNT para obtener el nmero de Permisos que cada Usuario tiene relacionado.
Ahora bien, como se menciona en el prrafo anterior, las funciones de agregacin operan sobre grupos de datos o resultados (en el
caso anterior era el grupo de Usuarios que se encuentran en la base de datos) por lo tanto, cada vez que usemos una funcin de
agregacin obtendremos como resultado una nica fila. Si no queremos que esto ocurra deberemos agrupar nuestros resultados
(usando la clausula GROUP BY) usando el criterio apropiado.
Explicar esto usando el ejemplo anterior. En l recuperamos la lista de Usuarios de la base de datos, obteniendo adems su
Direcciony el nmero de permisos que tienen asociados. Para recuperar este nmero de permisos usamos la funcin de agregacin
COUNT. Sin embargo si no hubiramos agrupado el resultado habra sido el siguiente:

Como podemos ver solo obtuvimos una fila como resultado, en el cual se muestra el total de permisos de los Usuarios que cumplen con
el criterio de bsqueda (2 del primero + 2 del segundo + 1 del tercero). Adems muestra los datos de Usuarioy Direccionde uno de
los Usuarios, seleccionado usando algn criterio del manejador de base de datos que estamos usando.
Como podemos ver esto difiere del resultado que queramos obtener, ya que la intencin era obtener los datos de cada uno de los
Usuarios y, adicional a esto, en nmero de permisos que tena. Esto nos demuestra que debemos tener cuidado cuando hacemos
uso de las funciones de agregacin.
Qu podemos hacer para obtener los datos que deseamos? Pues lo que hicimos en el ejemplo anterior, o sea, agrupar los resultados
obtenidos mediante algn criterio que nos parezca adecuado. En este caso como lo que queremos es obtener los datos de cada uno de
los Usuarios, debemos agrupar por algn atributo de Usuarioque nos parezca adecuado. En este caso podra ser el "nombre" o el
"identificador". Como la vez pasada usamos el "identificador", ahora usemos el "nombre" para ver que tambin nos da el
resultado esperado:

El resto de las funciones de agregacin funcionan de forma similar, as que dejaremos est parte hasta aqu para saltar a la explicacin
referente a la clausula WHERE.

La clausula WHERE
Esta clausula nos permite reducir o limitar el nmero de registros que recuperamos al hacer una consulta a nuestra base de datos,
seleccionando aquellos registros que cumplan con la condicin establecida dentro de esta clausula.
Dentro de esta clausula podemos colocar condiciones como que un valor sea igual a otro, que este dentro de ciertos rangos, que un
objeto sea de cierta clase, etc. Bsicamente lo mismo que podemos hacer con una sentencia WHEREde SQL estndar, pero agregndole
algunos detalles extra para el trabajo con objetos.
El trabajo con la clausula WHEREes en realidad muy sencillo, solo debemos colocar el nombre del atributo que queremos restringir,
y la restriccin que tendr. Podemos colocar ms de una restriccin, separando cada una con la palabra reservada AND.
Si queremos limitar el resultado de la consulta para regresar los usuarios de la base de datos, limitndonos a los que su username sea
usr456 restringiremos la consulta de la siguiente forma:

FROM Usuario u WHERE u.username='usr456'

Como el atributo que estamos restringiendo es una cadena colocamos el valor esperado entre comillas simples.
Al ejecutar esta consulta en el editor HQL de NetBeans obtenemos el siguiente resultado:

www.javatutoriales.com/2010/05/hibernate-parte-8-hql-segunda-parte.html

5/19

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 8: HQL Segunda Parte

Como podemos ver, la restriccin funcion sin problemas.


Ahora supongamos que queremos restringir para recuperar los permisos cuyo id sea mayor a 2 y menor a 5 (o sea, 3 y 4 ^-^). La
consulta tendra que ser de la siguiente forma:

FROM Permiso p WHERE p.id> 2 AND p.id < 5

Obteniendo el siguiente resultado:

Estas restricciones pueden extenderse para valores de propiedades de objetos relacionados (componentes), como por ejemplo:

FROM Usuario u WHERE u.direccion.codigoPostal = 123456

Tambin podemos obtener los valores de los Usuarios que tienen una Direccionasociada, o sea, cuya Direccionno est nula:

FROM Usuario u WHERE u.direccion IS NOT NULL

www.javatutoriales.com/2010/05/hibernate-parte-8-hql-segunda-parte.html

6/19

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 8: HQL Segunda Parte

Algo interesante en HQL es que el operador "=" no solo sirve para comparar valores de atributos, sino que tambin nos sirva para
comparar instancias:

FROM Usuario u1, Usuario u2 WHERE u1.direccion = u2.direccion

En el ejemplo anterior se recuperan las instancias de Usuariodonde usuario 1 tiene la misma Direccinque usuario 2, este ejemplo
es poco til pero sirve para probar el punto de la comparacin de instancias. Si tuviramos una base de datos ms compleja tal vez
podramos encontrar un uso ms adecuado a esta funcionalidad.
Otra cosa interesante es que Hibernate proporciona una propiedad especial llamada class, que nos ayuda cuando trabajamos con
persistencia polimrfica (o sea cuando tenemos clases persistentes que heredan de otras clases persistentes, hablaremos de esto en un
futuro tutorial ya que es un tema un poco amplio como para tocarlo aqu mismo).
Por ejemplo, imaginemos que tenemos una estructura de clases de esta forma:

Donde tenemos una clase Animalde la cual extienden dos clases: Domesticoy Salvaje. En cdigo sera algo ms o menos as:

public abstract class Animal


{
}
public class Domestico extends Animal
{
}
public class Salvaje extends Animal
{
}

Si quisiramos recuperar todas los Animales guardados en nuestra base de datos, sin importar si son Domesticos o Salvajes lo
haramos a travs de una consulta como la siguiente:

FROM Animal a

Y listo, con esto recuperaramos todos los Animales, dentro de una lista de referencias de tipo Animal, de la siguiente forma:

www.javatutoriales.com/2010/05/hibernate-parte-8-hql-segunda-parte.html

7/19

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 8: HQL Segunda Parte

List<Animal> listaAnimales;

Qu pasara si quisiramos seguir usando la referencia anterior pero solo recuperar los Animales Domesticos de la base de datos?
Es ah donde entra en juego la propiedad especial class que nos proporciona Hibernate. Por lo que la consulta quedara de la siguiente
forma:

FROM Animal a WHERE a.class = Domestico

Tendrn que confiar un poco en m sobre el funcionamiento de esto ya que, como mencion antes, explicar las consultas polimrficas
requiere un tutorial completo ya que tiene bastantes detalles que explicar.

EXPRESIONES
Las expresiones se usan dentro de la clausula WHEREe incluyen las siguientes:
matemticas: +, -, *, /
comparacin binaria: =, >=, <=, <>, !=, LIKE
lgicos: AND, OR, NOT
IN, NOT IN, BETWEEN, IS NULL, IS NOT NULL, IS EMPTY, IS NOT EMPTY, MEMBER OF, y NOT MEMBER
OF
case simple: CASE WHEN THEN ELSE END
case searched: CASE WHEN THEN ELSE END
concatenacin de cadenas: || o CONCAT(,)
CURRENT_DATE(),CURRENT_TIME(), y CURRENT_TIMESTAMP()
SECOND(), MINUTE(), HOUR(), DAY() , MONTH(), y YEAR()
SUBSTRING(), TRIM(), LOWER(), UPPER(), LENGTH(), LOCATE(), ABS(), SQRT(), BIT_LENGTH(),
MOD()
COALESCE() y NULLIF()
STR()
CAST( AS ), y EXTRACT( FROM )
Funciones HQL que toman expresiones con valores de tipo coleccin: SIZE(), MINELEMENT(), MAXELEMENT(),
MININDEX(), MAXINDEX(), junto con las funciones especiales ELEMENTS() e INDICES() que pueden ser
cuantificadas usando SOME, ALL, EXISTS, ANY, e IN
Cualquier funcin escalar soportado por el SQL del manejador de base de datos como SIGN(), TRUNC(), RTRIM(), y
SIN()
Parmetros posicionales estilo PreparedStatement de JDBC (usando ?)
Parmetros con nombre (usando :)
Literales SQL: foo, 123, 6.66E+2, 1970-01-01 10:00:01.0
Constantes java: (public static final)

LA CLAUSULA ORDER BY
La lista regresada por una consulta puede ser ordenada por una propiedad de uno de los componentes de las clases regresadas usando
esta clausula. Podemos indicar si queremos que los resultados sean ordenados de forma ascendente (de menor a mayor) o descendente
(de mayor a menor) con asc (la default) o desc, respectivamente.
Por ejemplo, si recuperamos la lista de todos los Permisos existentes en la base de datos, con la siguiente clausula:

FROM Permiso p

El resultado que obtenemos queda de la siguiente forma:

www.javatutoriales.com/2010/05/hibernate-parte-8-hql-segunda-parte.html

8/19

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 8: HQL Segunda Parte

Como vemos los resultados son ordenados por su "id", pero y si quisiramos regresarlos ordenamos por "nombre" para mostrarlos a
nuestros clientes? En ese caso tendramos que usar la clausula ORDER BY en el atributo nombre de la clase Permiso, de la
siguiente forma:

FROM Permiso p ORDER BY p.nombre

Obteniendo el siguiente resultado:

Como vemos ahora los resultados estn ordenamos por el "nombre" del Permiso de forma ascendente que, como mencion, es la
forma por default. Si quisiramos ordenarlos de forma descendente nuestra consulta quedara as:

Si queremos ordenar por ms de un atributo, colocamos la lista de atributos en esta clausula separados por comas: ORDER BY
atributo1, atributo2, atributo3, atributo n.

LA CLAUSULA GROUP BY
Un query que regresa valores de agregacin puede ser agrupado por cualquier propiedad de una clase o componente regresado por dicho
query.
Si por ejemplo, queremos obtener en nmero de Permisos de cada tipo que tenemos en la base de datos, haramos una consulta como
la siguiente:

SELECT p.estatus, COUNT(p.estatus) FROM Permiso p GROUP BY p.estatus

Si colocamos esta consulta en el NetBeans obtenemos el siguiente resultado:

www.javatutoriales.com/2010/05/hibernate-parte-8-hql-segunda-parte.html

9/19

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 8: HQL Segunda Parte

Como este resultado no nos dice mucho ^-^! Crearemos un mtodo que ejecute esta consulta:

private void cuentaPermisos()


{
iniciaOperacion();
Query query = sesion.createQuery("SELECT p.estatus, COUNT(p.estatus) FROM Permiso p GROUP BY p
.estatus");
List<Object[]> datos = query.list();
for (int i = 0; i < datos.size(); i++)
{
Object[] datoActual = datos.get(i);
System.out.println(datoActual[0] + "(" + datoActual[1] + ")");
}
terminaOperacion();
}

Al ejecutar este mtodo obtenemos la siguiente salida:

Que como podemos ver nos muestra el nmero de permisos de cada tipo que tenemos en la base de datos.
De la misma forma que con la clausula ORDER BY, si queremos agrupar por ms de un atributo, colocamos la lista de atributos en esta
clausula separados por comas: GROUP BY atributo1, atributo2, atributo3, atributo n.
Si queremos usar la clausula ORDER BYen una consulta en la que tambin usemos la clausula GROUP BY, esta ultima debe aparecer
antes que ORDER BY, de la siguiente forma:

SELECT FROM WHERE GROUP BY ORDER BY

De lo contrario no obtendremos algn mensaje de error, pero podemos obtener resultados inesperados.

SUBCONSULTAS
En las bases de datos que soportan subselects, Hibernate soporta subconsultas dentro de consultas. Las subconsultas deben estar
encerradas entre parntesis. An las subconsultas correlacionadas (subconsultas que hacen referencia a un alias en la consulta
externa) son permitidas siempre que la base de datos lo haga.
Por ejemplo, si quisiramos obtener todos los Usuarios de la base de datos que tengan al menos un Permiso en estado ACTIVO
(cuyo "estatus" sea igual a 1) lo haramos con la siguiente consulta:

SELECT DISTINCT(u) FROM Usuario u inner join u.permisos as p WHERE p in (SELECT p FROM Permiso p W
HERE p.estatus = 1)

Si colocamos esta consulta en el editor HQL de NetBeans obtenemos el siguiente resultado:

www.javatutoriales.com/2010/05/hibernate-parte-8-hql-segunda-parte.html

10/19

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 8: HQL Segunda Parte

Como podemos ver solo el Usuariocon id= 2 tiene Permisos con el estatusde ACTIVO.
Para terminar esta seccin dir que las subconsultas solo pueden estar dentro de clausulas SELECTo WHERE.

SINTAXIS ROW VALUE CONSTRUCTOR


HQL soporta el uso de la sintaxis de SQL ANSI row value constructor, algunas veces llamado sintaxis AS tuple, aun cuando
el manejador de base de datos que estemos usando podra no soportar dicha notacin. Aqu, por lo general nos referimos a
comparaciones multi-valuadas, tpicamente asociadas con componentes. Por ejemplo, consideremos nuestra entidad Usuario, la cual
define un componente Direccion:

FROM Usuario u WHERE u.direccion.calle = 'Calle1' AND u.direccion.codigoPostal = '12345'

La anterior es una consulta valida aunque un poco larga. La documentacin de Hibernate dice que podemos hacerla ms corta con la
sintaxis row value constructor, de la siguiente forma:

SELECT u.direccion FROM Usuario u WHERE u.direccion=('Calle1', '12345')

Sin embargo no he logrado hacerlo funcionar, ni al ejecutarlo desde NetBeans, ni desde una aplicacin. Obteniendo el siguiente error:

Afortunadamente (para este ejemplo ^_^!) la sintaxis row value constructor tambin puede ser usada en subconsultas que necesitan
comparar multiples valores. Por ejemplo, si queremos obtener los datos del Usuario cuya Direccion tiene la misma "calle" y
"codigoPostal" que la Direccioncon "id" = 2 podemos usar la siguiente consulta:

FROM Usuario u WHERE (u.direccion.calle, u.direccion.codigoPostal) in (SELECT d.calle, d.codigoPos


tal FROM Direccion d WHERE d.id = 2)

Con la cual obtenemos el siguiente resultado:

Lo que nos indica que el Usuariocon id= 2 es el dueo de la Direccioncon id= 2 ^-^.

COMPONENTES
www.javatutoriales.com/2010/05/hibernate-parte-8-hql-segunda-parte.html

11/19

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 8: HQL Segunda Parte


La mayora de las veces que creamos un modelo de datos, nuestras clases entidad estn construidas haciendo uso de la composicin de
objetos, teniendo una relacin de tipo HAS-A(objetos construidos en base a otros objetos) como en el caso de la relacin UsuarioDireccion; en donde un Usuariotiene una Direcciony una Direcciontiene un Usuario.
Cuando tenemos una relacin de este tipo, y esta relacin es de Uno a Unoo de Muchos a Muchos al Objeto incluido dentro de
nuestra clase le llamamos componente. En este Caso si estamos dentro de la clase Usuarioa la referencia que tenemos a un objeto
de la clase Direccion(private Direccion direccion;) la llamamos el componente direccin del Usuario.
HQL nos permite hacer consultas a propiedades de los componentes de nuestras clases de la misma forma en la que lo hacemos con las
propiedades de nuestro objeto principal. Estos valores pueden aparecen en la clausula SELECTde la siguiente forma:

SELECT u.nombre, u.direccion.calle, u.direccion.codigoPostal FROM Usuario u

Crearemos un mtodo llamado "obtenNombreDireccion" en nuestra clase "Main" para asegurarnos que la consulta anterior
efectivamente nos devuelve los valores que hemos pedido:

private void obtenNombreDireccion()


{
iniciaOperacion();
Query query = sesion.createQuery("SELECT u.nombre, u.direccion.calle, u.direccion.codigoPostal
FROM Usuario u");
List<Object[]> listaResultados = query.list();
for(int i = 0; i < listaResultados.size(); i++)
{
Object[] resultadoActual = listaResultados.get(i);
System.out.println("Nombre: " + resultadoActual[0] + ", calle: " + resultadoActual[1] + ",
codigo postal: " + resultadoActual[2]);
}
terminaOperacion();
}

Recuerden que cuando hacemos un SELECTcon solo algunas propiedades de nuestra entidad estas se obtienen en una lista de arreglos
de objetos, donde cada uno de los valores pedidos est almacenado en los objetos recuperados en el mismo orden en el que aparecen en
la clausula SELECT; esto lo aprendimos en el tutorial anterior.
Al ejecutar el cdigo anterior obtenemos el siguiente resultado:

El cual, como podemos ver, obtiene adems del nombre del Usuario la calle y el codigoPostal de su componente "direccion".
De esta misma forma podemos usar los atributos de los componentes en las clausulas WHEREy ORDER BY:

FROM Usuario u WHERE u.direccion.codigoPostal = '12345'

www.javatutoriales.com/2010/05/hibernate-parte-8-hql-segunda-parte.html

12/19

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 8: HQL Segunda Parte

SELECT u, u.direccion FROM Usuario u ORDER BY u.direccion.codigoPostal desc

Es importante recordar que, como dije antes, esto solo podemos usarlo cuando tenemos relaciones de tipo Uno a Unoo Muchos a
Muchos, o sea cuando nuestro componente es una referencia simple (no es un arreglo o una lista o algn otro tipo de coleccin).

TIPS Y TRUCOS
Para terminar este tutorial dar una serie de trucos que pueden facilitarnos un poco la vida al trabajar con HQL en nuestras aplicaciones
del da a da.

Contar en nmero de resultados:


Podemos contar en nmero de resultados que regresar una consulta sin tener que ejecutarla. Esto nos permitir evitar obtener un
OutOfMemoryErrorsi es que pensamos que nuestra consulta regresar muchos resultados.
Por ejemplo, tenemos la siguiente consulta, que es el producto cartesiano de todos los Usuarios y todos los Permisos que tenemos
en la base de datos (si, s que no debemos hacer eso, que debemos usar joins en vez de productos cartesianos, pero no se preocupen,
es solo para ejemplificar u_u):

FROM Usuario u, Permiso p

Solo para que nos demos una idea, si ejecutamos esta consulta obtendremos lo siguiente:

Para obtener el nmero de resultados que regresar esta consulta sin regresar los resultados, podemos usar la siguiente consulta:

SELECT COUNT(*) FROM Usuario u, Permiso p

Crearemos un mtodo llamado cuentaResultadosConsultapara poder ejecutar la consulta anterior:

www.javatutoriales.com/2010/05/hibernate-parte-8-hql-segunda-parte.html

13/19

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 8: HQL Segunda Parte

public void cuentaResultadosConsulta()


{
iniciaOperacion();
int numeroResultados = ((Long) sesion.createQuery("SELECT COUNT(*) FROM Usuario u, Permiso p")
.iterate().next()).intValue();
System.out.println("Numero de resultados que regresara la consulta: " + numeroResultados);
terminaOperacion();
}

El mtodo anterior nos da el siguiente resultado:

Como podemos ver, si ejecutamos la consulta esta nos regresar 15 resultados. Podemos comprobar que esto es correcto si contamos
el nmero de resultados que nos regres la consulta cuando la ejecutamos hace unos momentos.

Resultados en base al tamao de una coleccin:


Si queremos ordenar los resultados que nos regresa una consulta en base al nmero de elementos que tiene una coleccin
podemos hacerlo usando la funcin de agregacin COUNT dentro de la clausula ORDER BY. Por ejemplo, si queremos ordenar los
Usuarios obtenidos de la base de datos, en base al nmero de Permisos que tiene cada uno, podemos hacerlo con la siguiente
consulta:

SELECT u FROM Usuario u left join u.permisos p GROUP BY u ORDER BY COUNT(p) asc

Si ejecutamos esta consulta en el NetBeans obtendremos el siguiente resultado:

Tambin, si nuestra base de datos soporte subconsultas, podemos colocar una condicin sobre el tamao de la condicin en la clausula
SELECT de la consulta. Por ejemplo si queremos obtener todos los Usuarios que tienen menos de dos Permisos, utilizamos la
siguiente consulta:

FROM Usuario u WHERE size(u.permisos) < 2

Si ejecutamos esta consulta obtendremos el siguiente resultado:

www.javatutoriales.com/2010/05/hibernate-parte-8-hql-segunda-parte.html

14/19

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 8: HQL Segunda Parte

Si nuestra base de datos NO soporta subconsultas podemos usar la siguiente consulta para obtener el mismo resultado que con la
consulta anterior (alguien ha contado cuntas veces he escrito la palabra consulta en este post?):

SELECT u FROM Usuario u join u.permisos p GROUP BY u HAVING COUNT(p) < 2

Obteniendo el mismo resultado que con la consulta anterior:

Con esto terminamos por fin este tutorial sobre HQL ^_^, espero que les sea de utilidad.
Ahora que sabemos cmo hacer consultas con HQL veremos, en el siguiente tutorial, como utilizar todo lo que hemos aprendido dentro
de nuestras aplicaciones java.
Saludos
Descarga los archivos de este tutorial desde aqu:
HQL parte 2

Entradas Relacionadas:
Parte 1: Persistiendo Objetos Simples usando Mapeos en XML
Parte 2: Persistiendo Objetos Simples usando Anotaciones (Metadatos)
Parte 3: Relaciones / Uno a uno
Parte 4: Relaciones / Uno a muchos
Parte 5: Relaciones / Muchos a uno
Parte 6: Relaciones / Muchos a Muchos
Parte 7: HQL Primera Parte
Parte 9: Parmetros en HQL
Parte 10: Herencia
Parte 11: Interceptores y Eventos
Publicado por Alex en 16:05

divertido (0)

Reacciones:

interesante (0)

increible (0)

no me gusta (0)

Recomendar esto en Google


Etiquetas: funciones de agregacion, group by, hibernate, hql, order by, row value constructor

12 comentarios:
luchonet 29 de mayo de 2010 19:41
Gracias Alex son un maestro en esto desde el primer tutorial te voy siguiendo..
Aqui un pequeo aporte por si no conocias esta pagina de recursos gratuitos me imagino que es muy conocida por todos pero aqui esta
por si acaso es http;//www.illasaron.com/ tiene muy buenos recursos de varios lenguajes!!!
Responder

Alex

29 de mayo de 2010 19:50

Hola luchonet;
Gracias por tu comentario, y muy interesante el sitio que comentas de http://www.illasaron.com/ de videotutoriales, lo voy a revisar
Responder

JUAN CARLOS 15 de junio de 2010 21:58

www.javatutoriales.com/2010/05/hibernate-parte-8-hql-segunda-parte.html

15/19

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 9: Parmetros en HQL


Compartir

Ms

Siguiente blog

Tutoriales de Programacion Java


Blog dedicado a temas de programacin actuales usando el lenguaje de programacin Java y las ltimas versiones de sus APIs y Herramientas.
Pgina principal

Pgina de Concursos

Tutoriales UPAO 2010

Presentaciones Capacitacin

DOMINGO, 25 DE JULIO DE 2010

Hibernate - Parte 9: Parmetros en HQL

DONACIONES

En los dos tutoriales anteriores aprendimos cmo crear sentencias en el Hibernate Query Language (HQL) para poder hacer
consultas ms especficas, que las que por default nos proporciona Hibernate, a objetos almacenados en nuestra base de datos.
Hasta ahora nuestras consultas siempre han sido estticas, pero en nuestras aplicaciones usualmente deberemos pasarles parmetros
para obtener los datos correctos, como por ejemplo una cadena que represente un criterio de bsqueda, o el usernamey passwordde
un usuario que queramos buscar.
Ahora veremos cmo poder pasar parmetros a estas consultas de una forma correcta; y digo correcta porque siempre podramos
concatenar los parmetros al String que usemos para generar nuestra consulta.
Afortunadamente existen dos formas de pasar los parmetros sin tener que recurrir a la concatenacin. Y como solo existen dos formas
este tutorial ser corto, se los prometo ^_^!
Comencemos recordando un poco cmo hacemos, desde nuestro cdigo Java, una consulta en HQL.
Nota: Aunque uso el trm ino general consulta, no solo m e refiero a pedir datos de la base, tam bin uso este trm ino para referirm e a
inserciones o actualizaciones de datos.

Hibernate proporciona la interface org.hibernate.Query, la cual representa una consulta a la base de datos. Para obtener una
instancia de Query usamos el mtodo createQuery del objeto org.hibernate.Session, que a su vez obtenemos de la clase
org.hibernate.SessionFactory (si no recuerdan cmo obtener Session pueden revisarlo en la clase HibernateUtil que
creamos en el primer y en el segundo tutorial).
El mtodo createQuery recibe como parmetro una cadena que es nuestra consulta HQL, sin embargo, como mencion antes, hasta
ahora solo hemos usado consultas estticas. Sin embargo solo en raras ocasiones estas consultas estticas nos sern del todo tiles.
Hibernate proporciona dos formas de pasar parmetros a nuestras consultas:

JAVA TUTORIALES EN FACEBOOK

Java Tutoriales
Me gusta

Java Tutoriales

Amigo programador,
ests todo el da pica
cdigo, escucha esta
recomendaciones sl
hechas para ti..... q
esto?... Gracias Jorg
Rubira....

No olviden poner la
sentencia where al ha
un borraro en la base
datos..

http://www.youtube.c
watch?v=i_cVJgIz_Cs
A 7896 personas les gusta

Parmetros con nombre (named query parameters).


Parmetros posicionales estilo JDBC.
Antes de entrar en el detalle de cada una de ellas veamos el modelo de datos que usaremos para los ejemplos.
La aplicacin que crearemos ser un mini sistema de ventas. Tendremos un Usuario que puede realizar Compras de Productos.
Este Usuario tendr una Direccion de entrega a la que llegarn los Productos que compre.
Plug-in social de Facebook

Por lo tanto, tendremos una clase entidad Usuario que tendr una relacin uno a uno con la clase entidad Direccion. El
Usuario adems tendr una relacin uno a muchos con la clase entidad Compra que a su vez tendr una relacin muchos a
muchos con la clase entidad Producto.
Como podemos ver el ejemplo es pequeo pero podremos usar varias de las cosas que hemos aprendido a lo largo de estos tutoriales.
En los tutoriales solamente usar anotaciones para el ejemplo, sin embargo pueden descargar tambin la versin con archivos de mapeo
desde la liga que se encuentra al final del tutorial.
Creamos un nuevo proyecto en NetBeans (men File -> New Project -> Java -> Java Application). Le damos un
nombre y una ubicacin, y nos aseguramos de que las opciones "Create Main Class" y "Set as Main Project" estn
habilitadas. Presionamos el botn "Finish" y veremos aparecer en el editor nuestra clase "Main".
Agregamos la biblioteca de "Hibernate" que creamos en el primer tutorial de la serie. Hacemos clic derecho en el nodo "Libraries"
del proyecto. En el men contextual que se abre seleccionamos la opcin "Add Library...":

www.javatutoriales.com/2010/07/hibernate-parte-9-parametros-en-hql.html

1/19

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 9: Parmetros en HQL

En la ventana que se abre seleccionamos la biblioteca "Hibernate":

SEGUIDORES

Participar en este sitio


Google Friend Connect

Presionamos el botn "Add Library" para que la biblioteca se agregue a nuestro proyecto. De la misma forma agregamos la biblioteca
HibernateAnotaciones que creamos en el segundo tutorial. Aprovechamos tambin para agregar el conector de MySQL. Debemos
tener los siguientes archivos en nuestro proyecto:

Miembros (173) Ms

Ya eres miembro? Iniciar sesin

ARCHIVO DEL BLOG

2012 (2)
2011 (11)
2010 (10)
diciembre (1)
octubre (3)
septiembre (2)
agosto (2)
julio (1)

Hibernate - Parte 9: Parmetro

Ahora creamos dos paquetes, uno con el nombre "modelo", que contendr las clases entidades, y otro con el nombre "dao" que
contendr las clases que se encargarn del manejo de los datos que almacenaremos en la base de datos.

mayo (1)
2009 (22)

Hacemos clic derecho en el nodo del paquete que se cre al generar el proyecto. En el men contextual que se abre seleccionamos la
opcin "New -> Java Package..." y creamos los dos paquetes.

Que deben quedar as:

www.javatutoriales.com/2010/07/hibernate-parte-9-parametros-en-hql.html

2/19

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 9: Parmetros en HQL

Tambin crearemos el archivo de configuracin hibernate.cfg.xml que ser prcticamente igual que el de los ltimos 8 tutoriales:

<!DOCTYPE hibernate-configuration PUBLIC


"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<!-- parametros para la conexion a la base de datos -->
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="connection.url">jdbc:mysql://localhost/ hibernateparametros </property>
<property name="connection.username">usuario</property>
<property name="connection.password">password</property>
<!-- Configuracion del pool interno -->
<property name="connection.pool_size">1</property>
<!-- Dialecto de la base de datos -->
<property name="dialect">org.hibernate.dialect.MySQL5Dialect</property>
DATOS PERSONALES

<!-- Otras propiedades importantes -->


<property name="show_sql">true</property>
<property name="hbm2ddl.auto">create-drop</property>
<!-- Aqui iran las clases mapeadas -->
</session-factory>
</hibernate-configuration>

Alex

Programador Java con algunos


experiencia en mltiples poyec
mltiples APIs y herramientas d
compartir experiencias con el
programadores.
Ver todo mi perfil

Para los tutoriales usaremos una base de datos llamada hibernateparametros. Las tablas sern creadas de forma automtica en
base a nuestras entidades anotadas.
Comencemos con la creacin de nuestro modelo de datos, dentro del paquete modelo, con la clase Direccion que queda de esta
forma:

www.javatutoriales.com/2010/07/hibernate-parte-9-parametros-en-hql.html

3/19

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 9: Parmetros en HQL

@Entity
public class Direccion implements Serializable
{
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private int id;
private String calle;
private String codigoPostal;
public Direccion()
{
}
public Direccion(String calle, String codigoPostal)
{
this.calle = calle;
this.codigoPostal = codigoPostal;
}
public String getCalle()
{
return calle;
}
public void setCalle(String calle)
{
this.calle = calle;
}
public String getCodigoPostal()
{
return codigoPostal;
}
public void setCodigoPostal(String codigoPostal)
{
this.codigoPostal = codigoPostal;
}
public int getId()
{
return id;
}
private void setId(int id)
{
this.id = id;
}
}

No hay mucho que explicar sobre esta clase, es prcticamente la misma que hemos visto en los tutoriales anteriores: una clase marcada
con la anotacin @Entitye indicando cul de sus atributos servir como identificador usando la anotacin @Id.
La clase Direccion es muy parecida a la clase Producto que queda as:

www.javatutoriales.com/2010/07/hibernate-parte-9-parametros-en-hql.html

4/19

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 9: Parmetros en HQL

@Entity
public class Producto implements Serializable
{
public static enum Estatus{ACTIVO, INACTIVO};
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String nombre;
private String codigoBarras;
private float precio;
private Estatus estatus = Estatus.ACTIVO;
public Producto()
{
}
public Producto(String nombre, String codigoBarras, float precio)
{
this.nombre = nombre;
this.codigoBarras = codigoBarras;
this.precio = precio;
}
public String getCodigoBarras()
{
return codigoBarras;
}
public void setCodigoBarras(String codigoBarras)
{
this.codigoBarras = codigoBarras;
}
public Estatus getEstatus()
{
return estatus;
}
public void setEstatus(Estatus estatus)
{
this.estatus = estatus;
}
public int getId()
{
return id;
}
public void setId(int id)
{
this.id = id;
}
public String getNombre()
{
return nombre;
}
public void setNombre(String nombre)
{
this.nombre = nombre;
}
public float getPrecio()
{
return precio;
}
public void setPrecio(float precio)
{
this.precio = precio;
}
}

Esta clase es un poco ms interesante ya que, como podemos ver arriba, incluye una enumeracin llamada Estatus que nos indica
si el producto est ACTIVO o INACTIVO. Esta enumeracin es publicy staticpara que podamos acceder a ella desde afuera de
la clase Productode esta forma: Producto.Estatus.ACTIVOy Producto.Estatus.INACTIVO, y podamos usarlos en nuestras
consultas.
Tambin, la clase Producto incluye un atributo de tipo Estatus, llamado estatus y que inicializamos con el valor
Estatus.ACTIVO, o sea, cada vez que se cree un producto este estar activo por default.

www.javatutoriales.com/2010/07/hibernate-parte-9-parametros-en-hql.html

5/19

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 9: Parmetros en HQL


Ahora comenzaremos a ver las clases entidad que tienen relacin con otras entidades. La entidad Usuario queda de la siguiente
manera:

@Entity
public class Usuario implements Serializable
{
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private long id;
private String nombre;
private String username;
private String password;
@OneToOne(cascade = CascadeType.ALL)
private Direccion direccion;
@OneToMany(cascade = CascadeType.ALL)
private List<Compra> compras = new ArrayList<Compra>();
public Usuario()
{
}
public Usuario(String nombre, String username, String password)
{
this.nombre = nombre;
this.username = username;
this.password = password;
}
public List<Compra> getCompras()
{
return compras;
}
public void setCompras(List<Compra> compras)
{
this.compras = compras;
}
public void addCompra(Compra compra)
{
this.compras.add(compra);
compra.setUsuario(this);
}
public Direccion getDireccion()
{
return direccion;
}
public void setDireccion(Direccion direccion)
{
this.direccion = direccion;
}
public long getId()
{
return id;
}
protected void setId(long id)
{
this.id = id;
}
public String getNombre()
{
return nombre;
}
public void setNombre(String nombre)
{
this.nombre = nombre;
}
public String getPassword()
{
return password;
}
public void setPassword(String password)
{
this.password = password;
}

www.javatutoriales.com/2010/07/hibernate-parte-9-parametros-en-hql.html

6/19

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 9: Parmetros en HQL

public String getUsername()


{
return username;
}
public void setUsername(String username)
{
this.username = username;
}
}

La entidad Usuario es un poco ms interesante que las dos que vimos anteriormente, ya que, adems de indicar cul es su atributo
identificador y mostrar algunos atributos ms, vemos que tiene las anotaciones que indican las relaciones que tiene con las otras
entidades.
La relacin uno a uno que tiene con Direccion la representamos mediante la anotacin @OneToOne, que como podemos ver
realizar todas las operaciones en cascada con esta entidad, en su atributo direccion.
Tambin podemos ver que tiene una relacin uno a muchos, representada mediante la anotacin @OneToMany, con la entidad Compra
en su atributo compras.
Finalmente, la entidad Compra queda de esta manera:

www.javatutoriales.com/2010/07/hibernate-parte-9-parametros-en-hql.html

7/19

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 9: Parmetros en HQL

@Entity
public class Compra implements Serializable
{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
@ManyToMany(fetch=FetchType.EAGER)
private List<Producto> productos = new ArrayList<Producto>();
private double importeTotal;
@ManyToOne
private Usuario usuario;
public Usuario getUsuario()
{
return usuario;
}
public void setUsuario(Usuario usuario)
{
this.usuario = usuario;
}
public double getImporteTotal()
{
return importeTotal;
}
public void setImporteTotal(double importeTotal)
{
this.importeTotal = importeTotal;
}
public List<Producto> getProductos()
{
return productos;
}
public void setProductos(List<Producto> productos)
{
this.productos = productos;
}
public void addProducto(Producto producto)
{
this.productos.add(producto);
importeTotal += producto.getPrecio();
}
public long getId()
{
return id;
}
protected void setId(long id)
{
this.id = id;
}
}

Como vemos, la entidad Compra tiene una relacin muchos a muchos con la entidad Producto, a travs de su atributo
listaProductos, en la cual colocamos la anotacin @ManyToMany que representa la relacin. En esta anotacin tambin hemos
colocado el valor FetchType.EAGER al atributo fetch ya que queremos que al momento de recuperar una compra, se recuperen de
forma automtica todos los productos que la conforman.
Como dije antes, esta relacin ser de tipo muchos a muchos, por lo que, adems de saber qu Productos estn en una Compra,
tambin podremos saber quin compr qu Productos, a travs de la relacin muchos a uno que Compra tiene con la entidad
Usuario.
Ahora ya tenemos las cuatro entidades que usaremos para este ejemplo. No olviden indicar estas clases en el archivo
hibernate.cfg.xml, que queda de esta forma:

www.javatutoriales.com/2010/07/hibernate-parte-9-parametros-en-hql.html

8/19

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 9: Parmetros en HQL

<?xml version="1.0" encoding="UTF-8"?>


<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http:
//hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/hibernateparametros<
/property>
<property name="hibernate.connection.username">root</property>
<property name="hibernate.connection.password">123</property>
<!-- Configuracion del pool interno -->
<property name="connection.pool_size">1</property>
<!-- Dialecto de la base de datos -->
<property name="dialect">org.hibernate.dialect.MySQL5Dialect</property>
<!-- Otras propiedades importantes -->
<property name="show_sql">true</property>
<property name="hbm2ddl.auto">create-drop</property>
<!-- Aqui iran las clases mapeadas -->
<mapping class="hibernate.parametros.modelo.Direccion" />
<mapping class="hibernate.parametros.modelo.Compra" />
<mapping class="hibernate.parametros.modelo.Producto" />
<mapping class="hibernate.parametros.modelo.Usuario" />
</session-factory>
</hibernate-configuration>

Para continuar esta parte de configuracin crearemos la clase HibernateUtil como lo hicimos en el segundo tutorial de la serie.
A continuacin crearemos una clase de utilidad que nos ayudar a para realizar las operaciones de consultas a la base de datos y de
paso nos ayudar a mostrar un poco como debe ser la separacin de capas de lgica y de persistencia en nuestra aplicacin. Esta ser
una clase abstracta que contendr unos mtodos de utilidad para las operaciones de base de datos y de las cuales extender el resto de
nuestras clases de persistencia.
Hacemos clic derecho sobre nuestro paquete dao y en el men contextual que aparece seleccionamos las opciones New -> Java
Class. En la ventana que se abre colocamos como nombre de la clase AbstractDAO y presionamos el botn Finish.

Como dije antes, esta clase servir de base para el resto de nuestras clases de persistencia. Pero no queremos que alguien pueda crear
una instancia de esta clase directamente, as que la marcamos como abstract, de la siguiente forma:

public abstract class AbstractDAO


{
}

No entrar mucho en los detalles de lo que hace esta clase porque es bsicamente lo mismo que hemos venido viendo a lo largo de los
tutoriales, as que solo colocar el cdigo final, que queda de esta forma:

public abstract class AbstractDAO


{
private Session sesion;
protected void iniciaOperacion()
{
sesion = HibernateUtil.getSessionFactory().openSession();
sesion.getTransaction().begin();
}

www.javatutoriales.com/2010/07/hibernate-parte-9-parametros-en-hql.html

9/19

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 9: Parmetros en HQL


protected void terminaOperacion()
{
sesion.getTransaction().commit();
sesion.close();
}
protected void manejaExcepcion(HibernateException he) throws HibernateException
{
sesion.getTransaction().rollback();
throw he;
}
protected Session getSession()
{
return sesion;
}
public static void almacenaEntidad(Object entidad) throws HibernateException
{
AbstractDAO dummy = new AbstractDAO(){};
try
{
dummy.iniciaOperacion();
dummy.getSession().saveOrUpdate(entidad);
dummy.getSession().flush();
}
catch (HibernateException he)
{
dummy.manejaExcepcion(he);
}
finally
{
dummy.terminaOperacion();
}
}
public static <T> T getEntidad(Serializable id, Class<T> claseEntidad) throws HibernateExcepti
on
{
AbstractDAO dummy = new AbstractDAO(){};
T objetoRecuperado = null;
try
{
dummy.iniciaOperacion();
objetoRecuperado = (T) dummy.getSession().get(claseEntidad, id);
}
catch (HibernateException he)
{
dummy.manejaExcepcion(he);
}
finally
{
dummy.terminaOperacion();
}
return objetoRecuperado;
}
public static <T> List<T> getListaEntidades(Class<T> claseEntidad) throws HibernateException
{
AbstractDAO dummy = new AbstractDAO(){};
List<T> listaResultado = null;
try
{
dummy.iniciaOperacion();
listaResultado = dummy.getSession().createQuery("FROM " + claseEntidad.getSimpleName()
).list();
}
catch (HibernateException he)
{
dummy.manejaExcepcion(he);
}
finally
{
dummy.terminaOperacion();
}
return listaResultado;
}
}

www.javatutoriales.com/2010/07/hibernate-parte-9-parametros-en-hql.html

10/19

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 9: Parmetros en HQL

Como podemos ver, los mtodos iniciaOperacion, terminaOperacion, y manejaExcepcion son los mismos que hemos
venido viendo hasta ahora. El resto de los mtodos podran parecer un poco extraos as que los explicar sin entrar mucho en detalles.
El mtodo almacenaEntidad es un mtodo esttico que nos permite almacenar cualquier tipo de objeto entidad. El tener este
mtodo aqu nos evitar el tener que crear mtodos especficos para cada una de las entidades, y como el mtodo es esttico ni siquiera
tendremos que crear una instancia de una clase para guardar una entidad. Cranme que esto resulta muy til en los proyectos ^-^.
Como podemos ver, es necesario crear un objeto dummy, el cual es una clase que extiende a la misma AbstractDAO para poder
acceder a los mtodos iniciaOperacion, terminaOperacion, y manejaOperacion que estn marcados como protected.
El mtodo getEntidad nos permite recuperar cualquier objeto entidad del cual sepamos su identificador. Como vemos, este recibe
como parmetros un Serializable que es el identificador (que puede ser un Long, String, Integer, en fin, casi cualquier clase
que queramos), y la clase a la cual pertenece la entidad que queremos recuperar.
El mtodo getListaEntidades es muy parecido al anterior con la diferencia que aqu se recuperan todas las entidades de un tipo
que tengamos almacenadas.
Tanto en getEntidad y getListaEntidades podemos ver que se hace uso de generics (indicado por <T>) para recuperar los
objetos de una clase determinada.
Pues bien, comencemos viendo cmo pasar parmetros a nuestras consultas usando parmetros con nombre.

Parmetros con nombre


Es la forma ms simple de pasar parmetros a una consulta en HQL ya que, como su nombre lo indica, se le da un nombre al
parmetro y posteriormente se hace uso de este nombre para hacer referencia al parmetro.
El nombre del parmetro debe ir dentro del Stringde la consulta, este debe ir precedido por :.
Como primer ejemplo haremos una consulta para buscar a un Usuarioque nos proporciona su nombre de usuario y contrasea (como
en un login). Esta consulta estar dentro de un mtodo de la clase UsuariosDAO que extender a la clase AbstractDAO que
creamos hace un momento.
Hacemos clic derecho en el paquete dao. En el men que se abre seleccionamos New -> Java Class, ponemos como nombre de
la clase UsuariosDAO y presionamos el botn Finish. La clase que se crea ser una subclase de AbstractDAO por lo que lo
indicamos con la palabla clave extends.

public class UsuariosDAO extends AbstractDAO


{
}

Ahora pasaremos a ver la consulta. Primero explicar cada una de las partes y posteriormente veremos cmo queda el mtodo completo.
Si recuerdan, en el tutorial de HQL vimos cmo hacer una consulta simple para recuperar un objeto. En este caso la consulta quedara
inicialmente de la siguiente forma:

FROM Usuario u

La consulta anterior nos regresar a todos los Usuariosque tengamos en la base de datos. Sin embargo esto no es lo que queremos,
lo que queremos es recuperar a un Usuario especfico cuyos nombres de usuario y contrasea coincidan con los valores que le
proporcionaremos. Para esto debemos usar una restriccin con la clausula WHERE, y despus indicarle los parmetros que usaremos.
Como dije hace un momento: para indicar los parmetros lo hacemos con el smbolo : seguido del nombre que tendr el parmetro,
este nombre puede ser cualquiera que nosotros queramos. De esta forma:

FROM Ususario u WHERE u. username = :nombreUsuario AND u. password = :password

La consulta anterior est esperando recibir dos parmetros nombreUsuario y password, una vez que reciba estos dos parmetros
reemplazar las cadenas :nombreUsuario y :password con los valores correspondientes.
Ahora la pregunta es: Cmo establecemos estos parmetros? Pues bien, la respuesta a la pregunta anterior es que la interface
org.hibernate.Query tiene un mtodo llamado setParameter que recibe como primer argumento el nombre del parmetro que
queremos establecer, y como segundo argumento el valor de dicho parmetro. El hecho de que el segundo parmetro sea un objeto
nos permite que le pasemos valores de tipos arreglo, colecciones, bytes, booleanos, o prcticamente cualquier cosa que necesitemos,
como enumeraciones (lo cual haremos en unos momentos). La forma de usar este mtodo es la siguiente:

www.javatutoriales.com/2010/07/hibernate-parte-9-parametros-en-hql.html

11/19

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 9: Parmetros en HQL

query.setParameter(nombreUsuario, username);
query.setParameter(password, password);

Finalmente, para recuperar el valor que regresa esta consulta usamos el


org.hibernate.Query, como en los tutoriales anteriores:

mtodo uniqueResult() de la interface

Usuario usuario = (Usuario) query.uniqueResult();

Ahora pondremos todo lo anterior en un mtodo llamado getUsuario que queda de la siguiente forma (ya agregndole los mtodos de
utilidad que obtenemos por herencia de la clase AbstractDAO.

public Usuario getUsuario(String username, String password) throws HibernateException


{
Usuario usuario = null;
try
{
iniciaOperacion();
Query query = getSession().createQuery("FROM Ususario u WHERE u. username = :nombreUsu
ario AND u. password = :password");
query.setParameter("nombreUsuario", username);
query.setParameter("password", password);
usuario = (Usuario)query.uniqueResult();
}
catch (HibernateException he)
{
manejaExcepcion(he);
}
finally
{
terminaOperacion();
}

return usuario;
}

Y listo, con esto podremos recuperar a un Usuariodado su nombre de usuario y contrasea (usernamey password). Probemos que
este mtodo funciona. Para esto, en nuestra clase Main crearemos un mtodo llamado creaUsuarios que se encargar de llenar
nuestra tabla de Usuarioscon algunos datos. Colocamos el mtodo como sigue:

private void creaUsuarios()


{
try
{
AbstractDAO.almacenaEntidad(new Usuario("Usuario de Prueba numero 1", "estudioso", "de
svelado"));
AbstractDAO.almacenaEntidad(new Usuario("Usuario de Prueba numero 2", "caperucita", "l
oboFeroz"));
AbstractDAO.almacenaEntidad(new Usuario("Usuario de Prueba numero 3", "empleado", "inf
elicidad"));
AbstractDAO.almacenaEntidad(new Usuario("Usuario de Prueba numero 4", "usuarioComun",
"password"));
}
catch (HibernateException he)
{
System.err.println("Ocurri un error al agregar los usuarios...");
he.printStackTrace();
}
}

Como vemos, aqu usamos el mtodo esttico almacenaEntidad de clase AbstractDAO para guardar 4 Usuarios en la base de
datos. Mandamos llamar a este mtodo en el constructor de nuestra clase Main.
Ahora creamos un mtodo para probar la recuperacin de Usuarios, el cual intentar recuperar al "Usuario de prueba 2", usando
su nombre de usuario caperucita y su contrasea loboFeroz. Si el Usuario se encuentra mostraremos su nombre en la

www.javatutoriales.com/2010/07/hibernate-parte-9-parametros-en-hql.html

12/19

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 9: Parmetros en HQL


consola, si no mostraremos un mensaje de error. El mtodo queda de la siguiente forma:

private void buscaUsuario()


{
Usuario usuario = null;
UsuariosDAO usuariosDAO = new UsuariosDAO();
try
{
usuario = usuariosDAO.getUsuario("caperucita", "loboFeroz");
}catch (HibernateException e)
{
System.err.println("Ocurri un error al recuperar usuario");
e.printStackTrace();
}
if(usuario == null)
{
System.out.println("No se encontr al usuario");
}
else
{
System.out.println("El usuario es: " + usuario.getNombre());
}
}

Invocamos a este mtodo en el constructor de la clase Main, justo despus de la llamada a creaUsuarios.

public Main()
{
creaUsuarios();
buscaUsuario();
}

Ejecutamos la aplicacin y vemos que la salida generada nos indica que, efectivamente, el Usuariorecuperado es el Usuario2, con
nombre Usuario de Prueba numero 2:

En realidad creo que no hay mucho ms que decir en este punto sobre parmetros con nombre, as que lo dejar hasta aqu para pasar a
la siguiente y ltima parte de este tutorial en la que veremos cmo pasar parmetros a una consulta por si posicin.

Parmetros Posicionales estilo JDBC


Este estilo de paso de parmetros les ser muy conocido a los qu han trabajado con PreparedStatementen JDBC ya que, igual que
en estos ltimos establecemos en qu parte de la consulta deseamos que se coloquen los parmetros, haciendo uso de signos de cierre
de interrogacin ?, que establecemos despus usando la posicin de los signos de interrogacin (iniciando en 0).
Para establecer los parmetros usando esta forma, nuevamente hacemos uso del mtodo setParameter de la interface
org.hibernate.Query que hemos venido usando hasta el momento.
Para este segundo ejemplo haremos algo un poco ms complejo. En primer lugar lo que intentaremos hacer es recuperar todos los
Usuariosque han comprado un Productoque ya ha sido dado de baja del catlogo (que su estado sea INACTIVO) en el catlogo de
Productos y que adems, queremos que el cdigo postal de su Direccion sea igual al que le pasemos como parmetro a la
funcin.
Como lo que queremos hacer es recuperar una lista de Usuariosla primera parte de nuestra consulta queda de la siguiente manera:

www.javatutoriales.com/2010/07/hibernate-parte-9-parametros-en-hql.html

13/19

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 9: Parmetros en HQL

SELECT u FROM Usuario u

En este caso el SELECT u es necesario ya que haremos joins con varias otras entidades. Ahora, recordemos que cada Usuario
est relacionado con la entidad Producto mediante las Compras que ha realizado, por lo que el siguiente paso ser hacer un join
entre estas dos entidades. El joinser de tipo fetch joinya que queremos que la Compradel Usuariosea recuperada junto con
los datos del Usuario, de la siguiente forma:

SELECT u FROM Usuario u JOIN FETCH u.compras c

Y despus hacemos nuevamente un join entre las Compras y los Productos:

SELECT u FROM Usuario u JOIN FETCH u.compras c JOIN c.productos p

El paso anterior es necesario ya que tanto las Compras del lado de del Usuario como los Productos del lado de la Compra son
colecciones.
Finalmente, colocaremos las dos restricciones que mencionamos anterioremente: que el estatus sea igual a un valor (que
posteriormente estableceremos como inactivo y que el cdigo postal sea igual al que le pasemos como parmetros). Recordemos que
colocaremos signos de ? en los lugares en los que queremos que posteriormente sean colocados nuestros parmetros, por lo que la
consulta final queda de la siguiente forma:

SELECT u FROM Usuario u JOIN FETCH u.compras c JOIN c.productos p WHERE p.estatus = ? AND u.direcc
ion.codigoPostal = ?

Ahora estableceremos los valores de los parmetros. Como dije antes, para eso usaremos un nmero que representa la posicin de cada
uno de los signos de ?, iniciando en 0. Por lo tanto, la posicin del parmetro asociado a p.estatus ser 0 y la posicin del
parmetro asociado a u.direccion.codigoPostal ser "1".
Establecemos los valores de la siguiente forma:

query.setParameter(0, Producto.Estatus.INACTIVO);
query.setParameter(1, codigoPostal);

Finalmente, como lo que queremos hacer es obtener una lista de Usuarios usamos el mtodo list de la interface
org.hibernate.Query:

List<Usuario> listaUsuarios = query.list();

Y ya est. Con esto tenemos todo lista la consulta. Pondremos


getUsuariosConComprasInactivas en la clase UsuadiosDAO:

www.javatutoriales.com/2010/07/hibernate-parte-9-parametros-en-hql.html

todo

lo

anterior

en

un

mtodo

llamado

14/19

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 9: Parmetros en HQL

public List<Usuario> getUsuariosConComprasInactivas(String codigoPostal) throws HibernateExcep


tion
{
List<Usuario> listaUsuarios = null;
try
{
iniciaOperacion();
Query query = getSession().createQuery("FROM Usuario u JOIN u.compras c JOIN c.product
os p WHERE p.estatus = ? AND u.direccion.codigoPostal = ?");
query.setParameter(0, Producto.Estatus.INACTIVO);
query.setParameter(1, codigoPostal);

listaUsuarios = query.list();
}catch(HibernateException he)
{
he.printStackTrace();
manejaExcepcion(he);
}finally
{
terminaOperacion();
}
return listaUsuarios;
}

Ahora probemos que este mtodo funciona correctamente. Primero coloquemos algunos datos en la base creando un mtodo llamado
creaCompras en la clase Main. El mtodo queda de la siguiente forma:

www.javatutoriales.com/2010/07/hibernate-parte-9-parametros-en-hql.html

15/19

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 9: Parmetros en HQL

private void creaCompras()


{
Producto libros
= new Producto("Libro", "ABC123456", 120.0F);
Producto iPads
= new Producto("iPad", "RAF755576", 1315.45F);
Producto televisor = new Producto("T.V.", "AOF765984", 379.64F);
Producto postales = new Producto("Postal", "ELF",
15.65F);
Producto juegos
= new Producto("Videojuego", "MEN", 158.24F);
libros.setEstatus(Producto.Estatus.INACTIVO);
postales.setEstatus(Producto.Estatus.INACTIVO);
Usuario usuario1 = new Usuario("Usuario de Prueba numero 1", "estudioso", "desvelado");
usuario1.setDireccion(new Direccion("calle principal", "12345"));
Usuario usuario2 = new Usuario("Usuario de Prueba numero 2", "caperucita", "loboFeroz");
usuario2.setDireccion(new Direccion("primera avenida", "AVR-175"));
Usuario usuario3 = new Usuario("Usuario de Prueba numero 3", "empleado", "infelicidad");
usuario3.setDireccion(new Direccion("puesta del sol", "12345"));
Usuario usuario4 = new Usuario("Usuario de Prueba numero 4", "usuarioComun", "password");
usuario4.setDireccion(new Direccion("Este 145", null));
Compra compraUsuario1 = new Compra();
compraUsuario1.addProducto(libros);
usuario1.addCompra(compraUsuario1);
compraUsuario1 = new Compra();
compraUsuario1.addProducto(televisor);
compraUsuario1.addProducto(juegos);
usuario1.addCompra(compraUsuario1);
Compra compraUsuario2 = new Compra();
compraUsuario2.addProducto(iPads);
compraUsuario2.addProducto(televisor);
compraUsuario2.addProducto(juegos);
usuario2.addCompra(compraUsuario2);
Compra compraUsuario3 = new Compra();
compraUsuario3.addProducto(iPads);
compraUsuario3.addProducto(televisor);
usuario3.addCompra(compraUsuario3);
compraUsuario3 = new Compra();
compraUsuario3.addProducto(postales);
compraUsuario3.addProducto(juegos);
usuario3.addCompra(compraUsuario3);
Compra compraUsuario4 = new Compra();
compraUsuario4.addProducto(libros);
usuario4.addCompra(compraUsuario4);
try
{
AbstractDAO.almacenaEntidad(libros);
AbstractDAO.almacenaEntidad(iPads);
AbstractDAO.almacenaEntidad(televisor);
AbstractDAO.almacenaEntidad(postales);
AbstractDAO.almacenaEntidad(juegos);
AbstractDAO.almacenaEntidad(usuario1);
AbstractDAO.almacenaEntidad(usuario2);
AbstractDAO.almacenaEntidad(usuario3);
AbstractDAO.almacenaEntidad(usuario4);
}
catch (HibernateException he)
{
System.err.println("Ocurri un error al agregar los usuarios...");
he.printStackTrace();
}
}

El mtodo anterior se encarga de crear algunos Productos, Usuarios y Compras para estos Usuarios. Ahora crearemos el mtodo
que se encargar de ejecutar la consulta que hemos realizado y mostrar en la salida el nombre de los Usuarios que cumplan con la
condicin y los Productos que compraron:

www.javatutoriales.com/2010/07/hibernate-parte-9-parametros-en-hql.html

16/19

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 9: Parmetros en HQL

private void buscaUsuariosProductosInactivos()


{
List<Usuario> listaUsuarios = new UsuariosDAO().getUsuariosConComprasInactivas("12345");
for(int i = 0; i < listaUsuarios.size(); i++)
{
Usuario usuarioActual = listaUsuarios.get(i);
System.out.println("\nUsuario: " + usuarioActual.getNombre());
List<Compra> listaCompras = usuarioActual.getCompras();
for(int numeroCompra = 0; numeroCompra < listaCompras.size(); numeroCompra++)
{
List<Producto> listaProductos = listaCompras.get(numeroCompra).getProductos();
for(int numeroProducto = 0; numeroProducto < listaProductos.size(); numeroProducto
++)
{
Producto producto = listaProductos.get(numeroProducto);
System.out.println("\t" + producto.getNombre());
}
}
}
}

El mtodo anterior solo muestra en la salida el nombre del Usuario que cumple con las condiciones que establecimos, y los
Productos que compr.
Coloquemos los dos mtodos anteriores en el constructor de nuestra clase Main y ejecutemos la aplicacin para ver cul es la salida
generada:

Como podemos ver, hay dos Usuarios que cumplen con la condicin de habar comprado un Productoinactivo (Libroy Postal) y
que tienen como cdigo postal 12345.
Pues bien, con esto concluye este tutorial sobre paso de parmetros a consultas HQL. Espero que les sea de utilidad. En el prximo
tutorial mostrar cmo usar Hibernate cuando tenemos clases entidad que hacen uso de Herencia (clases que extienden de otras clases).
No olviden dejar sus dudas, comentarios y sugerencias en la seccin de comentarios.
Saludos.
Descarga los archivos de este tutorial desde aqu:
Parmetros en HQL con Anotaciones
Parmetros en HQL con Archivos de Mapeo

Entradas Relacionadas:
Parte 1: Persistiendo Objetos Simples usando Mapeos en XML
Parte 2: Persistiendo Objetos Simples usando Anotaciones (Metadatos)
Parte 3: Relaciones / Uno a uno
Parte 4: Relaciones / Uno a muchos
Parte 5: Relaciones / Muchos a uno
Parte 6: Relaciones / Muchos a Muchos
Parte 7: HQL Primera Parte
Parte 8: HQL Segunda Parte
Parte 10: Herencia
Parte 11: Interceptores y Eventos
Publicado por Alex en 19:18
Reacciones:

divertido (0)

interesante (0)

increible (0)

no me gusta (0)

Recomendar esto en Google


Etiquetas: hibernate, hql, parametros, parametros por nombre, parametros posicionales

www.javatutoriales.com/2010/07/hibernate-parte-9-parametros-en-hql.html

17/19

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 10: Herencia


Compartir

Ms

Siguiente blog

Tutoriales de Programacion Java


Blog dedicado a temas de programacin actuales usando el lenguaje de programacin Java y las ltimas versiones de sus APIs y Herramientas.
Pgina principal

Pgina de Concursos

Tutoriales UPAO 2010

Presentaciones Capacitacin

MARTES, 3 DE AGOSTO DE 2010

Hibernate - Parte 10: Herencia

DONACIONES

La herencia es uno de los mecanismos que nos proporciona la orientacin a objetos ms poderosos, ya que gracias a ella surgen cosas
como la sobreescritura, la reutilizacin y extensibilidad de cdigo, etc.
Ya que le herencia facilita la creacin de clases a partir de otras clases ya existentes en algunas ocasiones nuestras clases entidad
necesitarn extender de otras clases, entidades o no. Como por ejemplo, podemos tener una clase "Usuario" de las cuales extiendan
las clases "Administrador", "Operador" y "SuperUsuario".
Mapear una jerarqua de clases a tablas relacionales puede ser un problema un poco complejo. Afortunadamente Hibernate nos
proporciona 3 formas o estrategias de manejar la herencia con nuestras clases entidad. En este tutorial veremos cmo usar estas tres
formas de herencia y las implicaciones que tienen el uso de una u otra. Veremos cmo hacer esto tanto con anotaciones como con
archivos de mapeo.
Las tres estrategias de herencia que soporta Hibernate son:
Una tabla por toda la jerarqua de clases
Una tabla por cada subclase (joins)
Una tabla por cada clase concreta (uniones)

JAVA TUTORIALES EN FACEBOOK

Java Tutoriales
Me gusta

Java Tutoriales

Amigo programador,
ests todo el da pica
cdigo, escucha esta
recomendaciones sl
hechas para ti..... q
esto?... Gracias Jorg
Rubira....

A continuacin veremos cmo funciona cada una de estas estrategias, pero primero veamos el modelo de datos que usaremos para este
tutorial.

No olviden poner la
sentencia where al ha
un borraro en la base
datos..

Crearemos un proyecto en NetBeans para mostrar los ejemplos (men "File -> New Project... -> Java -> Java
Application"). Le damos un nombre y una ubicacin al proyecto y nos aseguramos de que las opciones "Create Main Class" y
"Set as Main Project" estn habilitadas. Presionamos el botn "Finish" y veremos aparecer en el editor nuestra clase "Main".

http://www.youtube.c
watch?v=i_cVJgIz_Cs

Agregamos la biblioteca de "Hibernate", que creamos en el primer tutorial de la serie. Hacemos clic derecho en el nodo "Libraries"
del proyecto. En el men contextual que se abre seleccionamos la opcin "Add Library...":

A 7896 personas les gusta

Plug-in social de Facebook

En la ventana que se abre seleccionamos la biblioteca "Hibernate":

Presionamos el botn "Add Library" para que la biblioteca se agregue a nuestro proyecto. Si van a usar anotaciones adems deben
agregar la biblioteca "HibernateAnotaciones" que creamos en el segundo tutorial. Aprovechamos tambin para agregar el conector
de MySQL. Debemos tener los siguientes archivos en nuestro proyecto:

www.javatutoriales.com/2010/08/hibernate-parte-10-herencia.html

1/35

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 10: Herencia

Java file
libraries
www.aspose.com
DOC, XLS, PPT, PDF,
MSG and more APIs
to Manage, Print and
Convert

Ahora creamos dos paquetes, uno con el nombre "modelo", que contendr las clases entidades, y otro con el nombre "dao" que
contendr nuestras clases para operaciones de persistencia. Adicionalmente si van a trabajar con archivos de mapeo agreguen el paquete
"mapeos" que contendr los archivos de mapeo XML. Hacemos clic derecho en el nodo del paquete que se cre al generar el proyecto.
En el men contextual que se abre seleccionamos la opcin "New -> Java Package..." y creamos los paquetes.

SEGUIDORES

Participar en este sitio


Que deben quedar as:

Google Friend Connect

Miembros (173) Ms

Ya eres miembro? Iniciar sesin

ARCHIVO DEL BLOG

Aprovecharemos para crear nuestro archivo de configuracin de Hibernate, "hibernate.cfg.xml", el cual ser muy parecido al del
primer tutorial:

2012 (2)
2011 (11)
2010 (10)
diciembre (1)

<?xml version="1.0" encoding="UTF-8"?>


<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<!-- parametros para la conexion a la base de datos -->
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="connection.url">jdbc:mysql://localhost/hibernateherencia</property>
<property name="connection.username">usuario</property>
<property name="connection.password">password</property>

octubre (3)
septiembre (2)
agosto (2)

Hibernate - Parte 11: Intercept


Eventos

Hibernate - Parte 10: Herencia


julio (1)
mayo (1)
2009 (22)

<!-- Configuracion del pool interno -->


<property name="connection.pool_size">1</property>
<!-- Dialecto de la base de datos -->
<property name="dialect">org.hibernate.dialect.MySQL5Dialect</property>
<!-- Otras propiedades importantes -->
<property name="show_sql">true</property>
<property name="hbm2ddl.auto">create-drop</property>
<!-- Clases o Archivos de mapeo -->
</session-factory>
</hibernate-configuration>

www.javatutoriales.com/2010/08/hibernate-parte-10-herencia.html

2/35

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 10: Herencia

Tambin agregaremos nuestra clase "HibernateUtil" al proyecto. Si quieren usar archivos de mapeo deben usar la que creamos en
el primer tutorial; si van a usar anotaciones deben usar la que creamos en el segundo tutorial.
Tambin agregaremos la clase "AbstractDAO", que creamos en el tutorial anterior, en el paquete "dao".
Para los ejercicios usaremos una base de datos llamada "hibernateherencia", en MySQL.
Nota: Yo usar dos proyectos para cada una de las estrategias de herencia, uno para usar archivos de m apeo y otro para usar anotaciones y que
el cdigo de am bos no se m ezcle.

Para los ejemplos usaremos un modelo de datos sencillo, que se muestra en la siguiente imagen:

Tenemos una clase base abstracta llamada "Persona", de la cual extienden dos clases: "Tecnologo" y "Normal" (porque por ah
dicen que los tecnlogos no somos normales ;)). Finalmente de la clase "Tecnologo" extienden "Programador" y "Tester".
Como podemos ver en el diagrama, cada una de las clases tiene una serie de atributos propios, lo que nos ayudar a ver cmo se
comportan estos en las distintas estrategias de herencia que veremos en un momento.
Las clases quedan de la siguiente manera:
La clase "Persona":

www.javatutoriales.com/2010/08/hibernate-parte-10-herencia.html

DATOS PERSONALES

Alex

Programador Java con algunos


experiencia en mltiples poyec
mltiples APIs y herramientas d
compartir experiencias con el
programadores.
Ver todo mi perfil

3/35

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 10: Herencia

public abstract class Persona implements Serializable


{
private long id;
private String nombre;
private int edad;
public Persona()
{
}
public Persona(String nombre, int edad)
{
this.nombre = nombre;
this.edad = edad;
}
public int getEdad()
{
return edad;
}
public void setEdad(int edad)
{
this.edad = edad;
}
public long getId()
{
return id;
}
protected void setId(long id)
{
this.id = id;
}
public String getNombre()
{
return nombre;
}
public void setNombre(String nombre)
{
this.nombre = nombre;
}
}

La clase "Normal" queda as:

public class Normal extends Persona


{
private String ocupacion;
public Normal()
{
}
public Normal(String nombre, int edad, String ocupacion)
{
super(nombre, edad);
this.ocupacion = ocupacion;
}
public String getOcupacion()
{
return ocupacion;
}
public void setOcupacion(String ocupacion)
{
this.ocupacion = ocupacion;
}
}

La clase "Tecnologo" queda de la siguiente forma:

www.javatutoriales.com/2010/08/hibernate-parte-10-herencia.html

4/35

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 10: Herencia

public class Tecnologo extends Persona


{
private int aniosDeEstudios;
public Tecnologo()
{
}
public Tecnologo(String nombre, int edad, int aniosDeEstudios)
{
super(nombre, edad);
this.aniosDeEstudios = aniosDeEstudios;
}
public int getAniosDeEstudios()
{
return aniosDeEstudios;
}
public void setAniosDeEstudios(int aniosDeEstudios)
{
this.aniosDeEstudios = aniosDeEstudios;
}
}

La clase "Programador" se ve as:

public class Programador extends Tecnologo


{
private String lenguajeFavorito;
private int aniosDeExperiencia;
public Programador()
{
}
public Programador(String nombre, int edad, int aniosDeEstudios, String lenguajeFavorito, int
aniosDeExperiencia)
{
super(nombre, edad, aniosDeEstudios);
this.lenguajeFavorito = lenguajeFavorito;
this.aniosDeExperiencia = aniosDeExperiencia;
}
public int getAniosDeExperiencia()
{
return aniosDeExperiencia;
}
public void setAniosDeExperiencia(int aniosDeExperiencia)
{
this.aniosDeExperiencia = aniosDeExperiencia;
}
public String getLenguajeFavorito()
{
return lenguajeFavorito;
}
public void setLenguajeFavorito(String lenguajeFavorito)
{
this.lenguajeFavorito = lenguajeFavorito;
}
}

Finalmente la clase "Tester" queda de la siguiente forma:

www.javatutoriales.com/2010/08/hibernate-parte-10-herencia.html

5/35

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 10: Herencia

public class Tester extends Tecnologo


{
private String herramientaDeTesteo;
public Tester()
{
}
public Tester(String nombre, int edad, int aniosDeEstudios, String herramientaDeTesteo)
{
super(nombre, edad, aniosDeEstudios);
this.herramientaDeTesteo = herramientaDeTesteo;
}
public String getHerramientaDeTesteo()
{
return herramientaDeTesteo;
}
public void setHerramientaDeTesteo(String herramientaDeTesteo)
{
this.herramientaDeTesteo = herramientaDeTesteo;
}
}

Bien, ya que tenemos las clases entidades que estaremos usando, comencemos con el tutorial.

Tabla por Jerarqua de Clases


En esta estrategia se genera una sola tabla en la que se guardan todas las instancias del rbol completo de herencia. O sea, que se
genera una sola tabla, y en esta tiene una columna para cada una de las propiedades de cada una de las clases que confirman la
jerarqua.
Para saber a qu clase concreta pertenece una fila de esta tabla se usa un valor en una columna discriminadora. Esta columna
discriminadora es muy importante ya que gracias a ella sabemos a qu clase pertenece cada una de las filas de nuestra tabla. El valor
contenido puede ser cualquiera que nosotros indiquemos para cada una de nuestras entidades, y puede ser una cadena, un carcter, o un
entero.
En este caso nuestra base de datos estara formada por una sola tabla, la cual quedara de la siguiente forma:

Donde "DISC" es nuestra columna discriminadora, o sea que en esta columna se guardar el valor que nos indicar a cul de nuestras
clases pertenece cada una de las instancias que almacenemos en la base de datos.
Como podemos ver en la imagen anterior, la tabla de nuestra base de datos tiene las propiedades de todas las clases que conforman la
jerarqua de "Persona".
Esta estrategia es buena en el sentido de que, como solo tenemos una tabla, no es necesario hacer joinso unionespara recuperar
los datos de uno a varios objetos, por lo que es ideal en situaciones en las que necesitamos un rendimiento muy alto, como para la
generacin de reportes.
Sin embargo no todo siempre es color de rosa, ya que las columnas que representan a los atributos de las subclases deben declararse
con la posibilidad de tener valores nulos, ya que como solo guardaremos un objeto de una clase por fila, la columnas que representen a
los atributos que no tenga ese objeto quedarn vacas. Debido a esto puede ser que se tengan problemas de integridad.
Ahora veremos cmo implementar esta estrategia de herencia en nuestras aplicaciones.

TABLA POR JERARQUA DE CLASES USANDO ARCHIVOS DE MAPEO


Creamos, en el paquete "mapeos" un nuevo documento XML. Le damos el nombre de "Persona.hbm" (el asistente se encargar de
colocar el ".xml")

www.javatutoriales.com/2010/08/hibernate-parte-10-herencia.html

6/35

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 10: Herencia


Presionamos el botn "Next >" e indicamos que queremos crear un documento XML bien formado (la primera opcin) y presionamos el
botn "Finish".
Eliminamos el contenido del archivo creado y colocamos el siguiente:

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="hibernate.herencia.modelo.Persona" table="personas">
</class>
</hibernate-mapping>

El mapeo de la clase "Persona" es muy simple, como el del primer tutorial de la serie, con la nica diferencia de que debemos indicarle
cul ser el nombre y el tipo de la columna discriminadora de la siguiente forma:

<discriminator column="DISC" type="string" />

En donde indicamos que el nombre de nuestra columna discriminaora ser "DISC" (aunque puede tener el nombre que ustedes elijan) y
que ser de tipo "string". Este elemento debe ir despus del elemento "id" en el archivo de mapeo de esa forma:

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="hibernate.herencia.modelo.Persona" table="personas">
<id name="id">
<generator class="identity" />
</id>
<discriminator column="DISC" type="string" />
</class>
</hibernate-mapping>

El mapeo completo de "Persona" queda de la siguiente forma:

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="hibernate.herencia.modelo.Persona" table="personas">
<id name="id">
<generator class="identity" />
</id>
<discriminator column="DISC" type="string" />
<property name="nombre" />
<property name="edad" />
</class>
</hibernate-mapping>

Como podemos ver, es prcticamente igual al que vimos en el primer tutorial. Pasemos ahora a ver cmo comenzar a mapear cada una
de sus subclases.
Para mapear una subclase en la estrategia de una sola tabla por jerarqua de clases usamos el elemento "<subclass>" en vez de "
<class>" en el archivo de mapeo. Por ejemplo, para mapear la clase "Normal" creamos un nuevo archivo de mapeo llamado

www.javatutoriales.com/2010/08/hibernate-parte-10-herencia.html

7/35

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 10: Herencia


"Normal.hbm.xml" en el paquete "mapeos". Eliminamos el contenido del archivo generado y colocamos el siguiente:

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<subclass name="hibernate.herencia.modelo.Normal" >
</subclass>
</hibernate-mapping>

Como vemos, ahora en vez de colocar el elemento "<class>" colocamos "<subclass>". En este elemento indicamos, como se
muestra arriba, el nombre de la clase que estamos mapeando (que en este caso es nuestra clase "Normal"); pero adems debemos
indicar otras cosas. Recuerdan que en el mapeo de la clase base indicamos una columna discriminadora? Y recuerdan que cuando lo
colocamos dijimos que cada subclase debe indicar su valor tener un valor para esa columna discriminadora? Pues bien, el elemento "
<subclass>" es el lugar para indicar este valor. Para el caso de la clase "Normal" indicamos que su valor para la columna
discriminadora ser "nrm" usando el atributo "discriminator-value":

<subclass name="hibernate.herencia.modelo.Normal" discriminator-value="nrm">

Finalmente, indicamos de cul de nuestras clases extiende, con el atributo "extends":

<subclass name="hibernate.herencia.modelo.Normal" discriminator-value="nrm" hibernate.herencia.mod


elo.Persona">

Y listo, esto es todo lo que necesitamos hacer para indicar en nuestro mapeo que usaremos la estrategia de una sola tabla.
El resto del archivo de mapeo de la clase "Normal" es igual a los que ya hemos visto, y queda de la siguiente forma:

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<subclass name="hibernate.herencia.modelo.Normal" discriminator-value="nrm" extends="hibernate
.herencia.modelo.Persona">
<property name="ocupacion" />
</subclass>
</hibernate-mapping>

Como podemos ver, no es muy diferente a los mapeos que hemos hecho hasta ahora, solo hay que recordar cambiar el elemento "
<class>" por "<subclass>" y agregar algunos atributos.
Fijense que en la clase "Normal" no fu necesario colocar un "id", ya que este ser heredado de su clase padre "Persona".
El resto de los mapeos son prcticamente iguales, solo hay que tener cuidado en cambiar el valor del discriminador en cada una de
nuestras subclases, viendo que no haya dos iguales, y qu clase extiende cul subclase. Para el resto de los mapeos los
discriminadores quedarn de esta forma:
Clase

Disc

Normal

nrm

Tecnologo

tec

Programador

pro

Tester

tes

Y los archivos de mapeo quedan de la siguiente forma:


Para la clase "Tecnlologo":

www.javatutoriales.com/2010/08/hibernate-parte-10-herencia.html

8/35

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 10: Herencia

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<subclass name="hibernate.herencia.modelo.Tecnologo" discriminator-value="tec" extends="hibern
ate.herencia.modelo.Persona">
<property name="aniosDeEstudios" />
</subclass>
</hibernate-mapping>

Para la clase "Programador":

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<subclass name="hibernate.herencia.modelo.Programador" discriminator-value="pro" extends="hibe
rnate.herencia.modelo.Tecnologo">
<property name="lenguajeFavorito" />
<property name="aniosDeExperiencia" />
</subclass>
</hibernate-mapping>

Y para la clase "Tester":

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<subclass name="hibernate.herencia.modelo.Tester" discriminator-value="tes" extends="hibernate
.herencia.modelo.Tecnologo">
<property name="herramientaDeTesteo" />
</subclass>
</hibernate-mapping>

Como vemos, esta forma de indicar la herencia es realmente simple. No olviden indicar todos estos archivos de mapeo en el archivo
"hibernate.cfg.xml":

<mapping resource="hibernate/herencia/mapeos/Persona.hbm.xml" />


<mapping resource="hibernate/herencia/mapeos/Normal.hbm.xml" />
<mapping resource="hibernate/herencia/mapeos/Tecnologo.hbm.xml" />
<mapping resource="hibernate/herencia/mapeos/Programador.hbm.xml" />
<mapping resource="hibernate/herencia/mapeos/Tester.hbm.xml" />

Adicionalmente tambin es posible indicar toda la jerarqua en un solo archivo de mapeo de esta forma:

www.javatutoriales.com/2010/08/hibernate-parte-10-herencia.html

9/35

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 10: Herencia

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="hibernate.herencia.modelo.Persona" table="personas">
<id name="id">
<generator class="identity" />
</id>
<discriminator column="DISC" type="string" />
<property name="nombre" />
<property name="edad" />
<subclass name="hibernate.herencia.modelo.Normal" discriminator-value="nrm">
<property name="ocupacion" />
</subclass>
<subclass name="hibernate.herencia.modelo.Tecnologo" discriminator-value="tec">
<property name="aniosDeEstudios" />
</subclass>
<subclass name="hibernate.herencia.modelo.Programador" discriminator-value="pro">
<property name="lenguajeFavorito" />
<property name="aniosDeExperiencia" />
</subclass>
<subclass name="hibernate.herencia.modelo.Tester" discriminator-value="tes">
<property name="herramientaDeTesteo" />
</subclass>
</class>
</hibernate-mapping>

En el archivo de mapeo anterior tenemos los elementos "<subclass>", que representan cada una de las subclases que extienden de
"Persona", dentro del elemento "<class>" que mapea a esta clase. Adems aqu no es necesario indicar de cul clase extiende cada
una de las subclases, ya que esta informacin se infiere del elemento "<class>" que las contiene.
Esta forma de mapeo me parece ideal si nuestras subclases no tendrn muchos atributos, as no es necesario crear un archivo de mapeo
para cada una de ellas.
Probemos cmo es generada nuestra tabla y como se guardan los mismos en nuestra base de datos. En el mtodo "main" de nuestra
clase "Main" guardemos un elemento de cada uno de los tipos de objetos, y adicionalmente guardemos otro "Programador":

public static void main(String[] args)


{
Normal
normal
= new Normal("normal", 21, "Empleado");
Tecnologo tecnologo
= new Tecnologo("tecnologo", 24, 4);
Programador programador1 = new Programador("primer programador", 25, 4, "java", 4);
Programador programador2 = new Programador("segundo programador", 25, 5, "java", 2);
Tester
tester
= new Tester("tester", 18, 3, "JUnit");
AbstractDAO.almacenaEntidad(normal);
AbstractDAO.almacenaEntidad(tecnologo);
AbstractDAO.almacenaEntidad(programador1);
AbstractDAO.almacenaEntidad(programador2);
AbstractDAO.almacenaEntidad(tester);
}

En el cdigo anterior usamos nuestra clase "AbstractDAO" para almacenar los 5 objetos que creamos. Ahora ejecutemos la aplicacin
y veamos la tabla generada y los datos que se almacenaron en ella.
Vemos qu tablas estn en nuestra base de datos "hibernateherencia" y que, efectivamente, solo tenemos una tabla llamada
"personas". Si vemos cmo est conformada esta tabla nos encontramos con que tiene una columna para cada uno de los atributos de
cada una de las clases dentro de la jerarqua que hemos usado para el ejemplo:

www.javatutoriales.com/2010/08/hibernate-parte-10-herencia.html

10/35

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 10: Herencia

Ahora veamos los datos que contiene:

Como vemos, se han guardado los 5 objetos en esta tabla, justamente como lo estbamos esperando. En la imagen podemos ver los
valores que se han guardado en la columna discriminadora y que los valores de las columnas que no tiene una clase se ha establecido a
"NULL" en todos los casos.
Ahora veamos cmo hacer esto mismo pero usando archivos de mapeo.

TABLA POR JERARQUA DE CLASES USANDO ANOTACIONES


Nuestras clases entidad sern anotadas prcticamente igual que en el segundo tutorial, con unas pequeas diferencias para indicar el tipo
de herencia que queremos usar.
Para indicar que nuestras entidades harn uso de herencia en nuestra base de datos usamos la anotacin "@Inheritance" en la clase
que representa la raz de la jerarqua, en este caso en la clase "Persona". Para indicar cul de las estrategias de herencia queremos
usar usamos su atributo "strategy" de esta forma:

@Entity
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
public abstract class Persona implements Serializable
{
}

Sin embargo cmo el valor por default del atributo "strategy" es "InheritanceType.SINGLE_TABLE" podramos no poner nada
dejndolo as:

@Entity
@Inheritance
public abstract class Persona implements Serializable
{
}

Solo con eso ya estamos indicando que la clase "Persona" es una entidad y que ella y todas las clases que extiendan de ella usarn la
estrategia de herencia de una sola tabla. Sin embargo an podemos indicar algo ms. Recuerdan la columna discriminadora que se usa
en la tabla? Pues tambin podemos indicar cul ser el nombre y el tipo de esta columna. Si no indicamos nada (como arriba) el nombre
de la columna ser "DTYPE" y el tipo ser "String". Si queremos indicar alguna otra cosa podemos hacerlo mediante la anotacin
"@DiscriminatorColumn". Esta anotacin tiene dos atributos importantes: "name" que indica cul ser el nombre de la columna, y
"discriminatorType" que indica de qu tipo ser el discriminador. Este ltimo atributo puede tomar uno de tres valores:
DiscriminatorType.STRING (este es el valor por default)
DiscriminatorType.CHAR
DiscriminatorType.INTEGER
Cambiemos el nombre que Hibernate le da por default a nuestra columna discriminadora para usar "DIS":

www.javatutoriales.com/2010/08/hibernate-parte-10-herencia.html

11/35

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 10: Herencia

@Entity
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name="DIS", discriminatorType=DiscriminatorType.STRING)
public abstract class Persona implements Serializable
{
}

Y el resto de las anotaciones que usamos en "Persona" son las que ya habamos visto en el segundo tutorial. Al final la clase
"Persona" queda as:

@Entity
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(name="DIS", discriminatorType=DiscriminatorType.STRING)
public abstract class Persona implements Serializable
{
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private long id;
private String nombre;
private int edad;
public Persona()
{
}
public Persona(String nombre, int edad)
{
this.nombre = nombre;
this.edad = edad;
}
public int getEdad()
{
return edad;
}
public void setEdad(int edad)
{
this.edad = edad;
}
public long getId()
{
return id;
}
protected void setId(long id)
{
this.id = id;
}
public String getNombre()
{
return nombre;
}
public void setNombre(String nombre)
{
this.nombre = nombre;
}
}

www.javatutoriales.com/2010/08/hibernate-parte-10-herencia.html

12/35

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 10: Herencia

Ahora veremos cmo se hace el mapeo del resto de nuestras clases que, en realidad, es algo bastante simple.
Para hacer que nuestra clase "Normal" quede lista para ser usada en nuestra aplicacin solo es necesario hacer dos cosas. La primera
es indicar, usando la anotacin "@Entity" que se trata de una entidad, de esta forma:

@Entity
public class Normal extends Persona
{
}

Hasta aqu todo sigue siendo lo que ya conocemos. El cambio viene solamente en que hay que indicar, al igual que lo hicimos con los
archivos de mapeo, cul ser el valor que identificar a los registros de esta entidad en la columna discriminadora. Y esto lo hacemos con
la anotacin "@DiscriminatorValue" en cuyo atributo "value" indicamos cul ser el valor que tendr nuestra columna. En el caso
de "Normal" pondremos que el valor para la columna discriminadora que lo representar ser "NM":

@Entity
@DiscriminatorValue(value="NM")
public class Normal extends Persona
{
}

Y listo. El resto de la clase, en este caso, no lleva ninguna anotacin, y al final queda de la siguiente manera:

@Entity
@DiscriminatorValue(value="NM")
public class Normal extends Persona
{
private String ocupacion;
public Normal()
{
}
public Normal(String nombre, int edad, String ocupacion)
{
super(nombre, edad);
this.ocupacion = ocupacion;
}
public String getOcupacion()
{
return ocupacion;
}
public void setOcupacion(String ocupacion)
{
this.ocupacion = ocupacion;
}
}

Para el resto de las clases hacemos exactamente lo mismo, indicamos con "@Entity" que nuestra clase ser una entidad, y usamos
"@DiscriminatorValue" para indicar cul ser el valor de la clase en la columna discriminadora. Para el resto de las clases los
discriminadores quedarn de esta forma:
Clase

Disc

Normal

NM

Tecnologo

TC

Programador

PG

Tester

TS

Y las clases de la siguiente forma:


La clase "Tecnologo" queda as:

www.javatutoriales.com/2010/08/hibernate-parte-10-herencia.html

13/35

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 10: Herencia

@Entity
@DiscriminatorValue(value="TC")
public class Tecnologo extends Persona
{
private int aniosDeEstudios;
public Tecnologo()
{
}
public Tecnologo(String nombre, int edad, int aniosDeEstudios)
{
super(nombre, edad);
this.aniosDeEstudios = aniosDeEstudios;
}
public int getAniosDeEstudios()
{
return aniosDeEstudios;
}
public void setAniosDeEstudios(int aniosDeEstudios)
{
this.aniosDeEstudios = aniosDeEstudios;
}
}

La clase "Programador" queda as:

@Entity
@DiscriminatorValue(value="PG")
public class Programador extends Tecnologo
{
private String lenguajeFavorito;
private int aniosDeExperiencia;
public Programador()
{
}
public Programador(String nombre, int edad, int aniosDeEstudios, String lenguajeFavorito, int
aniosDeExperiencia)
{
super(nombre, edad, aniosDeEstudios);
this.lenguajeFavorito = lenguajeFavorito;
this.aniosDeExperiencia = aniosDeExperiencia;
}
public int getAniosDeExperiencia()
{
return aniosDeExperiencia;
}
public void setAniosDeExperiencia(int aniosDeExperiencia)
{
this.aniosDeExperiencia = aniosDeExperiencia;
}
public String getLenguajeFavorito()
{
return lenguajeFavorito;
}
public void setLenguajeFavorito(String lenguajeFavorito)
{
this.lenguajeFavorito = lenguajeFavorito;
}
}

Y Finalmente la clase "Tester" queda de esta forma:

www.javatutoriales.com/2010/08/hibernate-parte-10-herencia.html

14/35

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 10: Herencia

@Entity
@DiscriminatorValue(value="TS")
public class Tester extends Tecnologo
{
private String herramientaDeTesteo;
public Tester()
{
}
public Tester(String nombre, int edad, int aniosDeEstudios, String herramientaDeTesteo)
{
super(nombre, edad, aniosDeEstudios);
this.herramientaDeTesteo = herramientaDeTesteo;
}
public String getHerramientaDeTesteo()
{
return herramientaDeTesteo;
}
public void setHerramientaDeTesteo(String herramientaDeTesteo)
{
this.herramientaDeTesteo = herramientaDeTesteo;
}
}

No olviden agregar estas clases al archivo de configuracin "hibernate.cfg.xml" de la siguiente forma:

<mapping class="hibernate.herencia.modelo.Persona"/>
<mapping class="hibernate.herencia.modelo.Normal"/>
<mapping class="hibernate.herencia.modelo.Tecnologo"/>
<mapping class="hibernate.herencia.modelo.Programador"/>
<mapping class="hibernate.herencia.modelo.Tester"/>

Probemos que lo anterior funciona usando, nuevamente, el siguiente cdigo en el mtodo "main" de nuestra clase "Main".

public static void main(String[] args)


{
Normal normal = new Normal("normal", 21, "Empleado");
Tecnologo tecnologo = new Tecnologo("tecnologo", 24, 4);
Programador programador1 = new Programador("primer programador", 25, 4, "java", 4);
Programador programador2 = new Programador("segundo programador", 25, 5, "java", 2);
Tester tester = new Tester("tester", 18, 3, "JUnit");
AbstractDAO.almacenaEntidad(normal);
AbstractDAO.almacenaEntidad(tecnologo);
AbstractDAO.almacenaEntidad(programador1);
AbstractDAO.almacenaEntidad(programador2);
AbstractDAO.almacenaEntidad(tester);
}

Al ejecutar la aplicacin podemos ver que se genera una sola tabla en la base de datos llamada "persona" constituida por las siguientes
columnas:

Si vemos qu datos contiene esta tabla podemos observar que se han guardado los datos de la forma que esperbamos y que, al igual
que con los archivos de mapeo, en la columna discriminadora se han guardado los valores indicados y que en las columnas que
representan los atributos de una clase distinta a la del registro se ha colocado el valor "NULL" en todos los casos:

www.javatutoriales.com/2010/08/hibernate-parte-10-herencia.html

15/35

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 10: Herencia

Como podemos ver, con esta estrategia pasamos de nuestra jerarqua de clases a una sola tabla, como se ilustra en la siguiente imagen:

Ahora que ya hemos visto cmo trabajar con la estrategia de una sola tabla, veamos la siguiente de las estrategias de herencia
proporcionadas por hibrnate.

Una Tabla para cada Subclase (joins)


En esta estrategia de herencia se crear una tabla por cada una de las clases que conformen nuestro rbol de herencia. Cada una de
las clases y subclases que declaren atributos persistentes, incluyendo clases abstractas e interfaces, tendr su propia tabla.
La representacin de la relacin de herencia entra estas tablas se hace mediante una llave fornea.
A diferencia de la estrategia de una tabla por jerarqua de clases, aqu cada tabla contiene solamente las columnas que representan los
atributos declarados en la clase, junto con una columna para la llave primaria que es tambin una llave fornea de la super clase. Por lo
tanto nuestra base de datos quedar de la siguiente forma:

Las tablas que representan a las clases padre y las que representan a las clases hijas son unidas por el valor de sus llaves primarias
compartidas. Gracias a esto es posible recuperar de la base de datos las instancias de una subclase haciendo un "join" entre la tabla
de la subclase con la de la superclase.
Esta estrategia tiene la ventaja de que las modificaciones y actualizaciones de una clase no afectan a los datos almacenados de las otras
clase, adems de que nuestro esquema de base de datos est normalizado.
Su desventaja es que la bsqueda de cul clase concreta pertenece una fila debe realizarse en cada una de las tablas de las clases que
componen la jerarqua, que en este caso seran 5. Debido a esto mismo, si debemos escribir nosotros mismos algo de SQL (digamos,
para hacer reportes) la tarea se complica.
Adems de esto el rendimiento puede ser muy malo si tenemos jerarquas complejas de clases.
Veamos cmo implementar esta estrategia en nuestra aplicacin.

UNA TABLA PARA CADA SUBCLASE (JOINS) USANDO ARCHIVOS DE MAPEO


Creamos, en el paquete "mapeos" un nuevo documento XML. Le damos el nombre de "Persona.hbm" (el asistente se encargar de
colocar el ".xml")
Presionamos el botn "Next >" e indicamos que queremos crear un documento XML bien formado (la primera opcin) y presionamos el
botn "Finish".

www.javatutoriales.com/2010/08/hibernate-parte-10-herencia.html

16/35

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 10: Herencia


En esta estrategia la clase base no necesita tener algo especial. Por lo que el mapeo de clase "Persona" queda de forma simple.
Eliminamos el contenido del archivo creado y colocamos el siguiente:

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="hibernate.herencia.modelo.Persona" table="personas">
<id name="id">
<generator class="identity" />
</id>
<property name="nombre" />
<property name="edad" />
</class>
</hibernate-mapping>

Ahora comienza la parte interesante que es crear el mapeo de las subclases. Para indicar que usaremos la estrategia de una tabla por
subclase usamos, en el archivo de mapeo de las subclases, en vez del elemento "<class>", el elemento "<joined-subclass>". En
este elemento indicamos el nombre de la clase que estamos mapeando, usando el atributo "name", junto con la tabla en la que se
guardarn, usando el atributo "table", de la siguiente forma:

<hibernate-mapping>
<joined-subclass name="hibernate.herencia.modelo.Normal" table="normales">
</joined-subclass>
</hibernate-mapping>

Tambin, dentro del elemento "<joined-subclass>" indicamos de cul clase extiende la clase que estamos mapeando, de la
siguiente forma:

<joined-subclass name="hibernate.herencia.modelo.Normal" table="normales" extends="hibernate.heren


cia.modelo.Persona">

Ahora debemos indicar cul de las columnas de la tabla que almacenar los datos de la entidad padre es la que almacena su
identificador, ya que est columna ser usada como llave fornea/primaria de la tabla que se generar para almacenar los datos de la
entidad que estamos mapeando. Para eso hacemos uso del elemento "<key>", y en su atributo "column" indicamos el nombre de la
columna que almacena el identificador de su entidad padre, de la siguiente forma:

<key column="id" />

En este caso la columna que se generar para almacenar el identificador de "Persona" es la mismo nombre que el de la propiedad ("id")
ya que no hemos indicado ninguna otra cosa, pero si, por ejemplo, este se estuviera guardando en una columna llamada "ID_PERSONA"
tendramos que colocar "ID_PERSONA" en el atributo "column" del elemento "<key>".
Esto es lo nico que tenemos que hacer para indicar que queremos usar esta estrategia de herencia. El resto del archivo es el mapeo
normal de la clase, y al final queda de esta forma:

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<joined-subclass name="hibernate.herencia.modelo.Normal" table="normales" extends="hibernate.h
erencia.modelo.Persona">
<key column="id" />
<property name="ocupacion" />
</joined-subclass>
</hibernate-mapping>

www.javatutoriales.com/2010/08/hibernate-parte-10-herencia.html

17/35

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 10: Herencia

El resto de los mapeos se hace exactamente igual, quedando al final de la siguiente forma:
Para la clase "Tecnologo" el mapeo queda de esta forma:

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<joined-subclass name="hibernate.herencia.modelo.Tecnologo" table="tecnologos" extends="hibern
ate.herencia.modelo.Persona">
<key column="id" />
<property name="aniosDeEstudios" />
</joined-subclass>
</hibernate-mapping>

El mapeo para la clase "Programador" queda as:

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<joined-subclass name="hibernate.herencia.modelo.Programador" table="programadores" extends="h
ibernate.herencia.modelo.Tecnologo">
<key column="id" />
<property name="lenguajeFavorito" />
<property name="aniosDeExperiencia" />
</joined-subclass>
</hibernate-mapping>

Finalmente, el mapeo de "Tester" queda de esta forma:

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<joined-subclass name="hibernate.herencia.modelo.Tester" table="testers" extends="hibernate.he
rencia.modelo.Tecnologo">
<key column="id" />
<property name="herramientaDeTesteo" />
</joined-subclass>
</hibernate-mapping>

No olviden poner estos archivos de mapeo en el archivo "hibernate.cfg.xml":

<mapping resource="hibernate/herencia/mapeos/Persona.hbm.xml" />


<mapping resource="hibernate/herencia/mapeos/Normal.hbm.xml" />
<mapping resource="hibernate/herencia/mapeos/Tecnologo.hbm.xml" />
<mapping resource="hibernate/herencia/mapeos/Programador.hbm.xml" />
<mapping resource="hibernate/herencia/mapeos/Tester.hbm.xml" />

Igual que en la estrategia anterior, aqu podemos colocar todos los mapeos en un mismo archivo y as ya no es necesario indicar de cul
clase extienden las clases que estamos mapeando:

www.javatutoriales.com/2010/08/hibernate-parte-10-herencia.html

18/35

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 10: Herencia

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="hibernate.herencia.modelo.Persona" table="personas">
<id name="id">
<generator class="identity" />
</id>
<property name="nombre" />
<property name="edad" />
<joined-subclass name="hibernate.herencia.modelo.Normal" table="normales">
<key column="id" />
<property name="ocupacion" />
</joined-subclass>
<joined-subclass name="hibernate.herencia.modelo.Tecnologo" table="tecnologos">
<key column="id" />
<property name="aniosDeEstudios" />
</joined-subclass>
<joined-subclass name="hibernate.herencia.modelo.Programador" table="programadores">
<key column="id" />
<property name="lenguajeFavorito" />
<property name="aniosDeExperiencia" />
</joined-subclass>
<joined-subclass name="hibernate.herencia.modelo.Tester" table="testers">
<key column="id" />
<property name="herramientaDeTesteo" />
</joined-subclass>
</class>
</hibernate-mapping>

Probemos que nuestra aplicacin funciona correctamente usando el cdigo que tenamos anteriormente en el mtodo "main" de nuestra
clase "Main":

public static void main(String[] args)


{
Normal normal = new Normal("normal", 21, "Empleado");
Tecnologo tecnologo = new Tecnologo("tecnologo", 24, 4);
Programador programador1 = new Programador("primer programador", 25, 4, "java", 4);
Programador programador2 = new Programador("segundo programador", 25, 5, "java", 2);
Tester tester = new Tester("tester", 18, 3, "JUnit");
AbstractDAO.almacenaEntidad(normal);
AbstractDAO.almacenaEntidad(tecnologo);
AbstractDAO.almacenaEntidad(programador1);
AbstractDAO.almacenaEntidad(programador2);
AbstractDAO.almacenaEntidad(tester);
}

Comprobemos qu, en nuestra base de datos, efectivamente se haya creada una sola tabla para cada una de nuestras clases:

Ahora comprobemos los datos que contiene cada una de las tablas:

www.javatutoriales.com/2010/08/hibernate-parte-10-herencia.html

19/35

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 10: Herencia

Como se ve en la imagen anterior, los datos comunes de todas las clases se guardan en la tabla "personas" y los datos particulares de
cada una de las subclases se almacena en su tabla correspondiente.
Veamos cmo hacer esto mismo con anotaciones.

UNA TABLA PARA CADA SUBCLASE (JOINS) USANDO ANOTACIONES


Las anotaciones para esta estrategia de herencia tambin son muy parecidas a las que ya estamos acostumbrados a usar.
En nuestra clase base, la clase "Persona", usamos la anotacin "@Inheritance". Para indicar que queremos usar esta estrategia, lo
indicamos en el atributo "strategy" de esa anotacin con el valor "InheritanceType.JOINED", de la siguiente forma:

@Entity
@Inheritance(strategy=InheritanceType.JOINED)
public abstract class Persona implements Serializable
{
}

Y listo, es todo lo que demos hacer en nuestra clase base. El resto de las anotaciones de la clase "Persona" son las que ya
conocemos, al final queda as:

www.javatutoriales.com/2010/08/hibernate-parte-10-herencia.html

20/35

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 10: Herencia

@Entity
@Inheritance(strategy=InheritanceType.JOINED)
public abstract class Persona implements Serializable
{
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private long id;
private String nombre;
private int edad;
public Persona()
{
}
public Persona(String nombre, int edad)
{
this.nombre = nombre;
this.edad = edad;
}
public int getEdad()
{
return edad;
}
public void setEdad(int edad)
{
this.edad = edad;
}
public long getId()
{
return id;
}
protected void setId(long id)
{
this.id = id;
}
public String getNombre()
{
return nombre;
}
public void setNombre(String nombre)
{
this.nombre = nombre;
}
}

En las subclases no es necesario que hagamos algo especial en esta estrategia de herencia. Por ejemplo, para la clase "Normal" basta
con que la indiquemos de la siguiente forma:

@Entity
public class Normal extends Persona
{
}

Simplemente con indicar que "Normal" es una entidad y que extiende de "Persona" es suficiente en esta estrategia de herencia. El
resto de la clase queda de la siguiente forma:

www.javatutoriales.com/2010/08/hibernate-parte-10-herencia.html

21/35

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 10: Herencia

@Entity
public class Normal extends Persona
{
private String ocupacion;
public Normal()
{
}
public Normal(String nombre, int edad, String ocupacion)
{
super(nombre, edad);
this.ocupacion = ocupacion;
}
public String getOcupacion()
{
return ocupacion;
}
public void setOcupacion(String ocupacion)
{
this.ocupacion = ocupacion;
}
}

El resto de las clases queda exactamente igual, as que no las colocar aqu. Pero no olviden ponerlas en el archivo
"hibernate.cfg.xml" de la siguiente forma:

<mapping class="hibernate.herencia.modelo.Persona"/>
<mapping class="hibernate.herencia.modelo.Normal"/>
<mapping class="hibernate.herencia.modelo.Tecnologo"/>
<mapping class="hibernate.herencia.modelo.Programador"/>
<mapping class="hibernate.herencia.modelo.Tester"/>

Probemos que todo funciona correctamente con el cdigo que hemos estado usando en nuestro mtodo "main":

public static void main(String[] args)


{
Normal normal = new Normal("normal", 21, "Empleado");
Tecnologo tecnologo = new Tecnologo("tecnologo", 24, 4);
Programador programador1 = new Programador("primer programador", 25, 4, "java", 4);
Programador programador2 = new Programador("segundo programador", 25, 5, "java", 2);
Tester tester = new Tester("tester", 18, 3, "JUnit");
AbstractDAO.almacenaEntidad(normal);
AbstractDAO.almacenaEntidad(tecnologo);
AbstractDAO.almacenaEntidad(programador1);
AbstractDAO.almacenaEntidad(programador2);
AbstractDAO.almacenaEntidad(tester);
}

Veamos las tablas generadas en nuestra base de datos:

Y los datos que contiene cada una de ellas:

www.javatutoriales.com/2010/08/hibernate-parte-10-herencia.html

22/35

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 10: Herencia

Comprobamos nuevamente que todo sali como lo planeamos ^_^.


Ahora veamos un poco el SQL generado con esta estrategia. Para esto modifiquemos un poco nuestra aplicacin para recuperar el primer
"Programador" que guardamos. Agreguemos esta lnea al final del mtodo "main":

AbstractDAO.getEntidad(programador1.getId(), Programador.class);

No nos interesa trabajar con la entidad recuperada, solo ver el sql generado por Hibernate para recuperarla:

Si vemos el SQL que resalt en la imagen anterior, veremos que tenemos lo siguiente:

select programado0_.id as id0_0_, programado0_2_.nombre as nombre0_0_, programado0_2_.edad as edad


0_0_, programado0_1_.aniosDeEstudios as aniosDeE2_2_0_, programado0_.lenguajeFavorito as lenguaje2
_3_0_, programado0_.aniosDeExperiencia as aniosDeE3_3_0_ from programadores programado0_ inner joi
n tecnologos programado0_1_ on programado0_.id=programado0_1_.id inner join personas programado0_2
_ on programado0_.id=programado0_2_.id where programado0_.id=?

Lo modificar un poco para hacerlo ms claro:

SELECT
prog.id as id0_0_, pers.nombre as nombre0_0_, pers.edad as edad0_0_, tec.aniosDeEstudios as anio
sDeE2_2_0_, prog.lenguajeFavorito as lenguaje2_3_0_, prog.aniosDeExperiencia as aniosDeE3_3_0_
FROM
programadores prog
INNER JOIN
tecnologos tec on prog.id=tec.id
INNER JOIN
personas pers on prog.id=pers.id
WHERE prog.id=?

Podemos observar que, efectivamente, se crea un join para unir cada una de las tres tablas que forman la jerarqua de "Programador",
que en este caso son "programadores", "tecnologos", y "personas". Sin embargo en este caso nosotros indicamos a cul clase
pertenece la instancia que queremos recuperar (con "Programador.class"). Pero qu ocurrira si no sabemos exactamente a cul de
las subclases de "Persona" pertenece la entidad? En ese caso nuestro cdigo tendra que ser as:

www.javatutoriales.com/2010/08/hibernate-parte-10-herencia.html

23/35

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 10: Herencia

AbstractDAO.getEntidad(programador1.getId(), Persona.class);

Ahora no estamos seguros de a cul clase pertenece el objeto que queremos recuperar (bueno, nosotros sabemos que buscamos un
"Pogramador", pero Hibernate solo sabe que busca una sublcase de "Persona"). Por lo tanto, si ejecutamos la aplicacin de esta
forma, Hibernate genera la siguiente consulta para saber cul clase recuperar:

select persona0_.id as id0_0_, persona0_.nombre as nombre0_0_, persona0_.edad as edad0_0_, persona


0_1_.ocupacion as ocupacion1_0_, persona0_2_.aniosDeEstudios as aniosDeE2_2_0_, persona0_3_.lengua
jeFavorito as lenguaje2_3_0_, persona0_3_.aniosDeExperiencia as aniosDeE3_3_0_, persona0_4_.herram
ientaDeTesteo as herramie2_4_0_, case when persona0_3_.id is not null then 3 when persona0_4_.id i
s not null then 4 when persona0_1_.id is not null then 1 when persona0_2_.id is not null then 2 wh
en persona0_.id is not null then 0 end as clazz_0_ from personas persona0_ left outer join normale
s persona0_1_ on persona0_.id=persona0_1_.id left outer join tecnologos persona0_2_ on persona0_.i
d=persona0_2_.id left outer join programadores persona0_3_ on persona0_.id=persona0_3_.id left out
er join testers persona0_4_ on persona0_.id=persona0_4_.id where persona0_.id=?

Nuevamente lo acomodar para hacerlo un poco ms claro:

SELECT
pers.id as id0_0_, pers.nombre as nombre0_0_, pers.edad as edad0_0_, norm.ocupacion as ocupacion
1_0_, tecs.aniosDeEstudios as aniosDeE2_2_0_, prog.lenguajeFavorito as lenguaje2_3_0_, prog.aniosD
eExperiencia as aniosDeE3_3_0_, tetr.herramientaDeTesteo as herramie2_4_0_,
CASE
WHEN prog.id IS NOT NULL THEN 3
WHEN tetr.id IS NOT NULL THEN 4
WHEN norm.id IS NOT NULL THEN 1
WHEN tecs.id IS NOT NULL THEN 2
WHEN pers.id IS NOT NULL THEN 0
END as clazz_0_
FROM personas pers
LEFT OUTER JOIN
normales norm on pers.id=norm.id
LEFT OUTER JOIN
tecnologos tecs on pers.id=tecs.id
LEFT OUTER JOIN
programadores prog on pers.id=prog.id
LEFT OUTER JOIN
testers tetr on pers.id=tetr.id
WHERE pers.id=?

Ahora la conuslta consulta es "compleja", y entre ms entidades tengamos ms compleja se volver. Es por eso que esta estrategia es
muy lenta si tenemos consulta en los que no sabemos el tipo concreto de la clase que buscamos, solo la clase base. A estas consultas
se les conoce como "Polimrficas".>
Entonces, tenemos que con esta estrategia pasamos de tener un conjunto de clases a tener una tabla por cada una de las clases, como
lo ilustra la siguiente figura:

En esta estrategia no fue necesario usar un discriminador, aunque en caso de que lo quisiramos agregar tambin es posible (aunque

www.javatutoriales.com/2010/08/hibernate-parte-10-herencia.html

24/35

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 10: Herencia


esto no agiliza las consultas polimrficas). Con esto logramos una mezcla entre las dos estrategias anteriores.

Para hacer eso con archivos de mapeo debemos colocar el elemento "<discriminator>" en el archivo de mapeo de la clase base
(indicando el nombre y tipo de la columna discriminadora) y, en los archivos de mapeo de las subclases, debemos usar nuevamente el
elemento "<subclass>" indicando, mediante su atributo "discriminator-value" el valor que tendr la columna discriminadora para
cada una de las subclases. Como hijo del elemento "<subclass>" debemos colocar el elemento "<join>" indicando el nombre de la
tabla que se usar para almacenar los atributos de los objetos de ese tipo, y como hijo de este el elemento "<key>" indicando la
columna de la tabla padre que almacena su identificador. El archivo de mapeo (colocando los mapeos de todo el rbol de herencia de
"Persona" en un solo archivo) quedara de la siguiente forma:

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="hibernate.herencia.modelo.Persona" table="personas">
<id name="id">
<generator class="identity" />
</id>
<discriminator column="DISC" type="string" />
<property name="nombre" />
<property name="edad" />
<subclass name="hibernate.herencia.modelo.Normal" discriminator-value="nrm">
<join table="normales">
<key column="id" />
<property name="ocupacion" />
</join>
</subclass>
<subclass name="hibernate.herencia.modelo.Tecnologo" discriminator-value="tcn">
<join table="tecnologos">
<key column="id" />
<property name="aniosDeEstudios" />
</join>
</subclass>
<subclass name="hibernate.herencia.modelo.Programador" discriminator-value="prm">
<join table="programadores" >
<key column="id" />
<property name="lenguajeFavorito" />
<property name="aniosDeExperiencia" />
</join>
</subclass>
<subclass name="hibernate.herencia.modelo.Tester" discriminator-value="tst">
<join table="testers">
<key column="id" />
<property name="herramientaDeTesteo" />
</join>
</subclass>
</class>
</hibernate-mapping>

Con anotaciones parece que no es posible lograr esto. Pero como dije anteriormente: esto no ayuda en realidad a optimizar las consultas
polimrficas.
Pasemos a ver la ltima de las estrategias de herencia que nos proporciona Hibernate.

Una Tabla por cada Clase Concreta (uniones)


Esta ltima estrategia podra parecer la ms extraa ya que en este caso se generar una tabla por cada una de las entidades noabstractas que tenga nuestra aplicacin (en este caso NO se generar una tabla para "Persona"). Sin embargo cada tabla tendr una
columna para cada uno de los atributos de la clase de la entidad que almacena, propios y heredados. O sea, que la tabla mantendr los
atributos de la clase que mapea, junto con los atributos que hereda de su clase padre.
En este caso las tablas no estn relacionadas de ninguna forma, por lo que terminaremos con un conjunto de tablas independientes una
de otras.
El esquema de la base de datos en esta ocasin quedar de la siguiente forma:

www.javatutoriales.com/2010/08/hibernate-parte-10-herencia.html

25/35

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 10: Herencia

Como vemos, ahora no hay ninguna tabla para "Persona", sin embargo las tablas de "normal" y "tecnologo" tienen las columnas
"edad" y "nombre", que son atributos de "Persona", adems de las columnas para sus propios atributos. De la misma forma
"programador" y "tester" tienen columnas para los atributos de "tecnlogo", adems de columnas para sus atributos propios.
Adems, estas tablas no tienen relacin una con otra de ninguna forma.
Esta estrategia tiene la ventaja de que no es necesario hacer un grupo de joins para obtener todos los datos de una entidad, lo que
nuevamente nos funciona si haremos consultas SQL a mano.
Ahora veamos cmo usar esta estrategia en nuestras aplicaciones.

UNA TABLA POR CLASE CONCRETA USANDO ARCHIVOS DE MAPEO


Creamos, en el paquete "mapeos" un nuevo documento XML. Le damos el nombre de "Persona.hbm" (el asistente se encargar de
colocar el ".xml")
Presionamos el botn "Next >" e indicamos que queremos crear un documento XML bien formado (la primera opcin) y presionamos el
botn "Finish".
En esta estrategia la clase base no necesita cambiar mucho. Por lo que el mapeo de clase "Persona" queda de forma simple.
Eliminamos el contenido del archivo creado y colocamos el siguiente:

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="hibernate.herencia.modelo.Persona">
</class>
</hibernate-mapping>

En este caso en el mapeo de la clase "Persona" (la cual recordemos que es "abstracta) debemos indicar de forma explcita que
estamos mapeando una clase abstracta, con el atributo ""abstract" del elemento ""<class>", de la siguiente forma:

<class name="hibernate.herencia.modelo.Persona" abstract="true">

Tambin si se han dado cuenta, en esta ocasin NO usamos el atributo "table" en este elemento. Estas dos cosas son para que no se
genere una tabla para las tablas abstractas ya que, como podrn imaginar, estas tablas solo estaran ocupando espacio en la base de
datos ya que nunca se usaran.

El siguiente paso es mapear el atributo que se usar como identificador de todas las subclases que extiendan de esta clase en la base
de datos. Solo que ahora no podemos usar el generador "identity" como lo hemos estado haciendo hasta ahora. En realidad no
entiendo el por qu de esta restriccin, pero por el momento tendremos que ajustarnos a esta regla. De hecho los valores que podemos
colocar son los siguientes:
increment
hilo
uuid
guid
assigned
Yo usar "increment" ya que es el que ms se parece a "identity". Si quieren encontrar ms informacin sobre los generadores

www.javatutoriales.com/2010/08/hibernate-parte-10-herencia.html

26/35

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 10: Herencia


pueden hacerlo en esta pgina.
El resto del mapeo de "Persona" no tiene nada de especial, y al final queda de la siguiente forma:

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="hibernate.herencia.modelo.Persona" abstract="true">
<id name="id">
<generator class="assigned" />
</id>
<property name="nombre" />
<property name="edad" />
</class>
</hibernate-mapping>

En el mapeo de las subclases, en esta ocasin en vez del elemento "<class>" usaremos "<union-subclass>". Indicamos en cul
tabla se almacenan los datos de esta subclase usando el atributo "table", y de cul clase extiende usando el atributo "extends". Por
ejemplo en la clase "Normal" el mapeo quedara de la siguiente forma:

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<union-subclass name="hibernate.herencia.modelo.Normal" table="normales" extends="hibernate.he
rencia.modelo.Persona">
<property name="ocupacion" />
</union-subclass>
</hibernate-mapping>

El de "Tecnologo" quedara de esta forma:

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<union-subclass name="hibernate.herencia.modelo.Tecnologo" table="tecnologos" extends="hiberna
te.herencia.modelo.Persona">
<property name="aniosDeEstudios" />
</union-subclass>
</hibernate-mapping>

El mapeo de "Programador" queda as:

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<union-subclass name="hibernate.herencia.modelo.Programador" table="programadores" extends="hi
bernate.herencia.modelo.Tecnologo">
<property name="lenguajeFavorito" />
<property name="aniosDeExperiencia" />
</union-subclass>
</hibernate-mapping>

Y el de la clase "Tester" queda de la siguiente forma:

www.javatutoriales.com/2010/08/hibernate-parte-10-herencia.html

27/35

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 10: Herencia


<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<union-subclass name="hibernate.herencia.modelo.Tester" table="testers" extends="hibernate.her
encia.modelo.Tecnologo">
<property name="herramientaDeTesteo" />
</union-subclass>
</hibernate-mapping>

No olviden colocar los mapeos en el archivo de configuracin "hibernate.cfg.xml" de la siguiente forma:

<mapping resource="hibernate/herencia/mapeos/Persona.hbm.xml" />


<mapping resource="hibernate/herencia/mapeos/Normal.hbm.xml" />
<mapping resource="hibernate/herencia/mapeos/Tecnologo.hbm.xml" />
<mapping resource="hibernate/herencia/mapeos/Programador.hbm.xml" />
<mapping resource="hibernate/herencia/mapeos/Tester.hbm.xml" />

Igual que en los casos anteriores, podemos poner todos estos mapeos en un solo archivo, de la siguiente forma:

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//Hibernate/Hibernate Mapping DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping>
<class name="hibernate.herencia.modelo.Persona" abstract="true">
<id name="id">
<generator class="assigned" />
</id>
<property name="nombre" />
<property name="edad" />
<union-subclass name="hibernate.herencia.modelo.Normal" table="normales">
<property name="ocupacion" />
</union-subclass>
<union-subclass name="hibernate.herencia.modelo.Tecnologo" table="tecnologos">
<property name="aniosDeEstudios" />
</union-subclass>
<union-subclass name="hibernate.herencia.modelo.Programador" table="programadores">
<property name="lenguajeFavorito" />
<property name="aniosDeExperiencia" />
</union-subclass>
<union-subclass name="hibernate.herencia.modelo.Tester" table="testers">
<property name="herramientaDeTesteo" />
</union-subclass>
</class>
</hibernate-mapping>

Probemos que la configuracin ha quedado bien usando nuevamente el siguiente cdigo en nuestro mtodo "main":

www.javatutoriales.com/2010/08/hibernate-parte-10-herencia.html

28/35

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 10: Herencia

public static void main(String[] args)


{
Normal normal
= new Normal("normal", 21, "Empleado");
Tecnologo tecnologo
= new Tecnologo("tecnologo", 24, 4);
Programador programador1 = new Programador("primer programador", 25, 4, "java", 4);
Programador programador2 = new Programador("segundo programador", 25, 5, "java", 2);
Tester tester
= new Tester("tester", 18, 3, "JUnit");
AbstractDAO.almacenaEntidad(normal);
AbstractDAO.almacenaEntidad(tecnologo);
AbstractDAO.almacenaEntidad(programador1);
AbstractDAO.almacenaEntidad(programador2);
AbstractDAO.almacenaEntidad(tester);
}

Al ejecutar nuestra aplicacin podemos ver que se generan las siguientes tablas:

Como vemos, solo se crearon tablas para las entidades no-abstractas de nuestra aplicacin. Ahora veamos los datos que contiene cada
una de estas tablas:

Nuevamente todo ha salido como esperabamos ^-^. Ahora veamos cmo usar esta estrategia usando anotaciones.

UNA TABLA POR CLASE CONCRETA USANDO ANOTACIONES


En esta estrategia nuevamente hacemos uso de la anotacin "@Inheritance" en la clase base (en este caso "Persona") para indicar
el mecanismo de herencia que queremos usar. En este caso colocaremos en su atributo "strategy" el valor
"InheritanceType.TABLE_PER_CLASS", de la siguiente forma:

@Entity
@Inheritance(strategy=InheritanceType.TABLE_PER_CLASS)
public abstract class Persona implements Serializable
{
}

Lo que sigue es indicar cul de los atributos de la clase servir como identificador. Igual que ocurre en el caso de usar archivos de mapeo,
en esta ocasin no podemos usar el valor "GenerationType.IDENTITY" como la estrategia de generacin del identificador. De hecho
en esta ocasin el nico valor que podemos elegir es:
GenerationType.TABLE
Este tipo de generacin lo que hace es crear una tabla especial para generar los identificadores (una especie de secuencia) por lo que en
nuestra base de datos terminaremos con una tabla de ms.
Fuera de esta pequea diferencia el resto del mapeo de nuestra clase no tiene ninguna otra particularidad. El mapeo completo de la clase
"Persona" se muestra a continuacin:

www.javatutoriales.com/2010/08/hibernate-parte-10-herencia.html

29/35

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 10: Herencia

@Entity
@Inheritance(strategy=InheritanceType.TABLE_PER_CLASS)
public abstract class Persona implements Serializable
{
@Id
@GeneratedValue(strategy=GenerationType.TABLE)
private long id;
private String nombre;
private int edad;
public Persona()
{
}
public Persona(String nombre, int edad)
{
this.nombre = nombre;
this.edad = edad;
}
public int getEdad()
{
return edad;
}
public void setEdad(int edad)
{
this.edad = edad;
}
public long getId()
{
return id;
}
protected void setId(long id)
{
this.id = id;
}
public String getNombre()
{
return nombre;
}
public void setNombre(String nombre)
{
this.nombre = nombre;
}
}

El mapeo de las subclases no tiene ninguna cosa extraa, por lo que solo colocar el mapeo de "Normal", que queda de la siguiente
forma:

@Entity
public class Normal extends Persona
{
private String ocupacion;
public Normal()
{
}
public Normal(String nombre, int edad, String ocupacion)
{
super(nombre, edad);
this.ocupacion = ocupacion;
}
public String getOcupacion()
{
return ocupacion;
}
public void setOcupacion(String ocupacion)
{
this.ocupacion = ocupacion;
}
}

www.javatutoriales.com/2010/08/hibernate-parte-10-herencia.html

30/35

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 10: Herencia

El mapeo de las dems clases es exactamente igual que el de "Normal". No olviden colocar estas clases en el archivo de configuracin
"hibernate.cfg.xml":

<mapping class="hibernate.herencia.modelo.Persona"/>
<mapping class="hibernate.herencia.modelo.Normal"/>
<mapping class="hibernate.herencia.modelo.Tecnologo"/>
<mapping class="hibernate.herencia.modelo.Programador"/>
<mapping class="hibernate.herencia.modelo.Tester"/>

Ahora, probemos que nuestra aplicacin funciona usando nuevamente el siguiente cdigo en nuestro mtodo "main":

public static void main(String[] args)


{
Normal normal
= new Normal("normal", 21, "Empleado");
Tecnologo tecnologo
= new Tecnologo("tecnologo", 24, 4);
Programador programador1 = new Programador("primer programador", 25, 4, "java", 4);
Programador programador2 = new Programador("segundo programador", 25, 5, "java", 2);
Tester tester
= new Tester("tester", 18, 3, "JUnit");
AbstractDAO.almacenaEntidad(normal);
AbstractDAO.almacenaEntidad(tecnologo);
AbstractDAO.almacenaEntidad(programador1);
AbstractDAO.almacenaEntidad(programador2);
AbstractDAO.almacenaEntidad(tester);
}

Al ejecutar nuestra aplicacin podemos ver que se generan las siguientes tablas:

En la imagen anterior podemos ver que se gener, adems de las tablas esperadas, una tabla llamada "hibernate_sequences". Esta
tabla es la que usa para generara los identificadores de cada una de las subclases de "Persona" que guardemos en la base de datos.
Ahora veamos los datos almacenados en cada uno de nuestras tablas:

Podemos ver que, nuevamente, los datos se han almacenado correctamente y que todo ha salido como lo planeamos ^_^.
Veamos, solo por curiosidad, nuevamente el SQL generado por Hibernate en las consultas polimrficas. Si intentamos recuperar una
instancia de la clase "Programador" usando la siguiente lnea al final del cdigo anterior:

AbstractDAO.getEntidad(programador1.getId(), Programador.class);

Hibernate genera el siguiente SQL:

www.javatutoriales.com/2010/08/hibernate-parte-10-herencia.html

31/35

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 10: Herencia

select programado0_.id as id0_0_, programado0_.edad as edad0_0_, programado0_.nombre as nombre0_0_


, programado0_.aniosDeEstudios as aniosDeE1_2_0_, programado0_.aniosDeExperiencia as aniosDeE1_3_0
_, programado0_.lenguajeFavorito as lenguaje2_3_0_ from Programador programado0_ where programado0
_.id=?

Que acomodado queda de la siguiente forma:

SELECT
prog.id as id0_0_, prog.edad as edad0_0_, prog.nombre as nombre0_0_, prog.aniosDeEstudios as ani
osDeE1_2_0_, prog.aniosDeExperiencia as aniosDeE1_3_0_, prog.lenguajeFavorito as lenguaje2_3_0_
FROM
Programador prog
WHERE prog.id=?

Como podemos ver no hay ningn problema, pedimos un Programadory Hibernate lo busca en la tabla "programador". Pero qu
ocurre si no sabemos a cul clase pertenece nuestra entidad? En ese caso tendramos que usar la siguiente lnea:

AbstractDAO.getEntidad(programador1.getId(), Persona.class);

Con lo que Hibernate generar la siguiente consulta:

select persona0_.id as id0_0_, persona0_.edad as edad0_0_, persona0_.nombre as nombre0_0_, persona


0_.ocupacion as ocupacion1_0_, persona0_.aniosDeEstudios as aniosDeE1_2_0_, persona0_.aniosDeExper
iencia as aniosDeE1_3_0_, persona0_.lenguajeFavorito as lenguaje2_3_0_, persona0_.herramientaDeTes
teo as herramie1_4_0_, persona0_.clazz_ as clazz_0_ from ( select id, edad, nombre, null as ocupac
ion, aniosDeEstudios, aniosDeExperiencia, lenguajeFavorito, null as herramientaDeTesteo, 3 as claz
z_ from Programador union select id, edad, nombre, null as ocupacion, aniosDeEstudios, null as ani
osDeExperiencia, null as lenguajeFavorito, herramientaDeTesteo, 4 as clazz_ from Tester union sele
ct id, edad, nombre, ocupacion, null as aniosDeEstudios, null as aniosDeExperiencia, null as lengu
ajeFavorito, null as herramientaDeTesteo, 1 as clazz_ from Normal union select id, edad, nombre, n
ull as ocupacion, aniosDeEstudios, null as aniosDeExperiencia, null as lenguajeFavorito, null as h
erramientaDeTesteo, 2 as clazz_ from Tecnologo ) persona0_ where persona0_.id=?

Que un poco acomodada se ve as:

www.javatutoriales.com/2010/08/hibernate-parte-10-herencia.html

32/35

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 10: Herencia

SELECT
pers.id as id0_0_, pers.edad as edad0_0_, pers.nombre as nombre0_0_, pers.ocupacion as ocupacion
1_0_, pers.aniosDeEstudios as aniosDeE1_2_0_, pers.aniosDeExperiencia as aniosDeE1_3_0_, pers.leng
uajeFavorito as lenguaje2_3_0_, pers.herramientaDeTesteo as herramie1_4_0_, pers.clazz_ as clazz_0
_

FROM (
SELECT id, edad, nombre, null as ocupacion, aniosDeEstudios, aniosDeExperiencia, lenguajeFavorit
o, null as herramientaDeTesteo, 3 as clazz_
FROM Programador
UNION
SELEC id, edad, nombre, null as ocupacion, aniosDeEstudios, null as aniosDeExperiencia, null as
lenguajeFavorito, herramientaDeTesteo, 4 as clazz_
FROM Tester
UNION
SELECT id, edad, nombre, ocupacion, null as aniosDeEstudios, null as aniosDeExperiencia, null as
lenguajeFavorito, null as herramientaDeTesteo, 1 as clazz_
FROM Normal
UNION
SELECT id, edad, nombre, null as ocupacion, aniosDeEstudios, null as aniosDeExperiencia, null as
lenguajeFavorito, null as herramientaDeTesteo, 2 as clazz_
FROM Tecnologo ) pers
WHERE pers.id=?

Como podemos ver, Hibernate tiene que buscar, nuevamente, a qu clase pertenece el objeto en todas las tablas para la jerarqua de
clases. Esto, como se podrn imaginar, har nuestras consultas muy lentas en caso de que dicha jerarqua tenga muchas clases.
Hemos podido ver cmo usar las tres estrategias de herencia que Hibernate nos proporciona y las ventajas y desventajas de algunas de
ellas. Aunque no es necesario que usemos solo una estrategia en nuestras aplicaciones, podemos mezclarlas en la forma que ms nos
convenga para sacarles el mayor provecho.
Para terminar este tutorial les dejo algunos consejos de cmo elegir una estrategia de herencia para sus aplicaciones.

ELIGIENDO UNA ESTRATEGIA DE HERENCIA

Si no requerimos asociaciones o consultas polimrficas, lo mejor ser elegir "una tabla por clase concreta"; en otras
palabras, si nunca o rara vez haremos una consulta buscando con la clase base (como "Persona"), entonces esta estrategia
es ideal, ya que solo buscaremos en una tabla de nuestra base de datos.
Si requerimos asociaciones o consultas polimrficas y nuestras subclases declaran pocos atributos (esto puede ser debido a
que la diferencia principal entre las subclases sea el comportamiento), entonces lo mejor ser elegir "una tabla para la
jerarqua de clases".
Finalmente, si requerimos asociaciones polimrficas y nuestras subclases declaran muchos atributos distintos entonces la
mejor estrategia ser "una tabla por subclase". O, dependiendo de de la profundidad de la jerarqua de herencia y el posible
costo de los joins contra las uniones, podramos elegir "una tabla por clase concreta".
Por default podemos elegir "una tabla por jerarqua de clases" para problemas simples, y en casos ms complejos elegir alguna de las
otras dos estrategias, o considerar modificar nuestro modelo de datos ^-^!
Pues bien, esto es todo para este post. En la siguiente y ltima entrega hablar sobre cmo trabajar con Interceptores y Eventos.
Saludos.
Descarga los archivos de este tutorial desde aqu:
Hibernate Herencia Tabla por Jerarquia de Clases con Archivos de Mapeo
Hibernate Herencia Tabla por Jerarquia de Clases con Anotaciones
Hibernate Herencia Tabla por Subclase con Archivos de Mapeo
Hibernate Herencia Tabla por Subclase con Anotaciones
Hibernate Herencia Tabla por Clase Concreta con Archivos de Mapeo
Hibernate Herencia Tabla por Clase Concreta con Anotaciones

Entradas Relacionadas:
Parte 1: Persistiendo Objetos Simples usando Mapeos en XML
Parte 2: Persistiendo Objetos Simples usando Anotaciones (Metadatos)
Parte 3: Relaciones / Uno a uno
Parte 4: Relaciones / Uno a muchos
Parte 5: Relaciones / Muchos a uno
Parte 6: Relaciones / Muchos a Muchos

www.javatutoriales.com/2010/08/hibernate-parte-10-herencia.html

33/35

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 11: Interceptores y Eventos


Compartir

Ms

Siguiente blog

Tutoriales de Programacion Java


Blog dedicado a temas de programacin actuales usando el lenguaje de programacin Java y las ltimas versiones de sus APIs y Herramientas.
Pgina principal

Pgina de Concursos

Tutoriales UPAO 2010

Presentaciones Capacitacin

LUNES, 23 DE AGOSTO DE 2010

Hibernate - Parte 11: Interceptores y Eventos


Algunas veces podemos tener situaciones que demanden la realizacin de algunas operaciones antes o despus de nuestra lgica
funcional (precondiciones y postcondiciones). O tal vez simplemente queremos intervenir antes o despus de qu alguna de nuestras
operaciones de persistencia (alta, baja, actualizacin, lectura, etc.) sea realizada. Ya sea para, por ejemplo, modificar algn valor de
nuestra entidad (como encriptar algn dato antes de ser guardado) o para leer algn valor.
Tambin algunas veces es necesario recibir alguna notificacin de algn suceso que est ocurriendo en nuestro motor de persistencia,
como el estar recuperando o eliminando algn objeto. Esto puede ser til para propsitos de auditoras, o para obtener estadsticas sobre
las operaciones de persistencia en nuestras aplicaciones.
Hibernate proporciona dos mecanismos para lograr estos dos objetivos: listeners y eventos.
En este tutorial aprenderemos cmo recibir notificaciones cada vez que Hibernate realice alguna operacin de persistencia a travs de
estos dos mecanismos.

1. Interceptores
Los interceptores nos proporcionan llamadas, a nivel sesin o a nivel aplicacin, permitiendo a la aplicacin inspeccionar y/o
manipular propiedades de un objeto persistente antes de ser guardado, actualizado, eliminado, o cargado dentro de nuestro contexto
persistente.
Pueden ser utilizados para monitorear los eventos ocurridos o para sobreescribir la funcionalidad de un mdulo. El ejemplo clsico es la
auditora del sistema, para realizar un log de eventos que indiquen los cambios que realizan sobre nuestras entidades.
En nuestro ejemplo realizaremos un mini-sistema de auditora, en el que queremos que, cada vez que un Usuariosea almacenado o
eliminado del sistema, se muestre un mensaje en la consola. Por lo tanto comenzaremos nuestro ejemplo creando un nuevo proyecto.

DONACIONES

JAVA TUTORIALES EN FACEBOOK

Java Tutoriales
Me gusta

Java Tutoriales

Amigo programador,
ests todo el da pica
cdigo, escucha esta
recomendaciones sl
hechas para ti..... q
esto?... Gracias Jorg
Rubira....

No olviden poner la
sentencia where al ha
un borraro en la base
datos..

http://www.youtube.c
watch?v=i_cVJgIz_Cs
A 7896 personas les gusta

Creamos un proyecto en NetBeans (men "File -> New Project... -> Java -> Java Application"). Le damos un nombre
y una ubicacin al proyecto y nos aseguramos de que las opciones "Create Main Class" y "Set as Main Project" estn
habilitadas. Presionamos el botn "Finish" y veremos aparecer en el editor nuestra clase "Main".
Agregamos la biblioteca de "Hibernate", que creamos en el primer tutorial de la serie. Hacemos clic derecho en el nodo "Libraries"
del proyecto. En el men contextual que se abre seleccionamos la opcin "Add Library...":

Plug-in social de Facebook

En la ventana que se abre seleccionamos la biblioteca "Hibernate":

www.javatutoriales.com/2010/08/hibernate-parte-11-interceptores-y.html

1/20

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 11: Interceptores y Eventos

Curso Online
de jquery
www.teleformacio
Crea pginas web
dinmicas Descuento
para desempleados
25%

Extend JMS to
.NET

Presionamos el botn "Add Library" para que la biblioteca se agregue a nuestro proyecto. Como vamos a usar anotaciones, adems
debemos agregar la biblioteca "HibernateAnotaciones" que creamos en el segundo tutorial. Aprovechamos tambin para agregar el
conector de MySQL. Debemos tener los siguientes archivos en nuestro proyecto:

Visual JSF
Flow Designer
Curso
Programacin
Evo
Performance
Tuning
SEGUIDORES

Participar en este sitio


Google Friend Connect

Miembros (173) Ms

Ahora creamos tres paquetes, uno con el nombre "modelo", que contendr las clases entidades, otro con el nombre "dao" que
contendr nuestras clases para operaciones de persistencia, y el ltimo con el nombre "interceptores" que contendr el interceptor
que crearemos para nuestro ejemplo. Hacemos clic derecho en el nodo del paquete que se cre al generar el proyecto. En el men
contextual que se abre seleccionamos la opcin "New -> Java Package..." y creamos los paquetes.

Ya eres miembro? Iniciar sesin

ARCHIVO DEL BLOG

2012 (2)
2011 (11)
2010 (10)
diciembre (1)
octubre (3)
septiembre (2)
agosto (2)

Hibernate - Parte 11: Intercept


Eventos

Hibernate - Parte 10: Herencia


julio (1)
mayo (1)

Ahora creamos el archivo de mapeo "hibernate.cfg.xml" en el paquete raz de nuestra aplicacin. Este archivo ser muy parecido al
del primer tutorial:

www.javatutoriales.com/2010/08/hibernate-parte-11-interceptores-y.html

2009 (22)

2/20

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 11: Interceptores y Eventos

<?xml version="1.0" encoding="UTF-8"?>


<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<!-- parametros para la conexion a la base de datos -->
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="connection.url">jdbc:mysql://localhost/hibernateinterceptores</property>
<property name="connection.username">usuario</property>
<property name="connection.password">password</property>
<!-- Configuracion del pool interno -->
<property name="connection.pool_size">1</property>
<!-- Dialecto de la base de datos -->
<property name="dialect">org.hibernate.dialect.MySQL5Dialect</property>
<!-- Otras propiedades importantes -->
<property name="show_sql">false</property>
<property name="hbm2ddl.auto">create-drop</property>
<!-- Clases o Archivos de mapeo -->
</session-factory>
</hibernate-configuration>

Aprovechamos para agregar, en el paquete "dao" la clase "HibernateUtil" que creamos en el segundo tutorial. Y la clase
"AbstractDAO" que creamos en el tutorial 9 (parmetros).
Para terminar crearemos una sola clase entidad llamada "Usuario", en el paquete "modelo", que tendr solo un par de atributos
adems del identificador y ser anotada con las mismas anotaciones que vimos en el segundo tutorial. La clase queda de la siguiente
forma:

DATOS PERSONALES

Alex

Programador Java con algunos


experiencia en mltiples poyec
mltiples APIs y herramientas d
compartir experiencias con el
programadores.
Ver todo mi perfil

www.javatutoriales.com/2010/08/hibernate-parte-11-interceptores-y.html

3/20

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 11: Interceptores y Eventos

@Entity
public class Usuario implements Serializable
{
@Id
@GeneratedValue(strategy=GenerationType.IDENTITY)
private long id;
private String nombre;
private String username;
private String password;
public Usuario()
{
}
public Usuario(String nombre, String username, String password)
{
this.nombre = nombre;
this.username = username;
this.password = password;
}
public long getId()
{
return id;
}
private void setId(long id)
{
this.id = id;
}
public String getNombre()
{
return nombre;
}
public void setNombre(String nombre)
{
this.nombre = nombre;
}
public String getPassword()
{
return password;
}
public void setPassword(String password)
{
this.password = password;
}
public String getUsername()
{
return username;
}
public void setUsername(String username)
{
this.username = username;
}
}

No olviden agregar esta clase en el archivo de configuracin "hibernate.cfg.xml".

<mapping class="hibernate.interceptores.modelo.Usuario" />

Para este ejercicio usaremos una base de datos llamada "hibernateinterceptores".


Ahora comencemos a ver cmo implementar nuestro interceptor.
La forma ms "directa" de crear un interceptor es implementar la interface "org.hibernate.Interceptor" la cual tiene nada ms
y nada menos que 18 mtodos. La siguiente tabla muestra una breve descripcin de los 13 mtodos ms importantes de esta interface:
afterTransactionBegin Este mtodo es llamado inmediatamente despus de que una transaccin es iniciada.

www.javatutoriales.com/2010/08/hibernate-parte-11-interceptores-y.html

4/20

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 11: Interceptores y Eventos


afterTransactionCompletion Llamado al terminar una transaccin.
beforeTransactionCompletion Llamado antes de que se realice un commitde la transaccin (solo de commit, no de
rollback).
findDirty Llamado en el momento de llamar a "flush()".
onCollectionRecreate Llamado antes de que una coleccin se creada o recreada.
onCollectionRemove Llamado antes de que una coleccin sea eliminada.
onCollectionUpdate Llamado antes de que una coleccin sea actualizada.
onDelete Llamado antes de que una instancia sea eliminada
onLoad Llamado antes de que una entidad sea inicializada (o sea antes de establecer los valores de sus atributos).
onPrepareStatement Llamado cuando se est preparando la cadena con el SQL generado.
onSave Llamado antes de que una entidad sea almacenada.
postFlush Llamado despus del flushque sincroniza los datos con la base de datos.
preFlush Llamado antes de un flush.
Como podemos ver, esta interface tiene mtodos para prcticamente cualquier cosa que se nos pueda ofrecer (aparentemente). Sin
embargo, como sabemos, si queremos implementar una interface entonces debemos proporcionar la implementacin de cada uno de los
mtodos que tiene la interface (y con 18 mtodos esto no es una tarea nada fcil). Afortunadamente los creadores de Hibernate nos
ofrecen una manera de no tener que implementar, por nosotros mismos, cada uno de estos mtodos, a travs de la clase
"org.hibernate.EmptyInterceptor", la cual funciona como adapter de la interface "org.hibernate.Interceptor". Esta clase
contiene implementaciones vacas de los 18 mtodos de la interface "org.hibernate.Interceptor", por lo que solo deberemos
sobreescribir los mtodos que nos interesen.
Ser a travs de esta ltima clase que realizaremos nuestro ejemplo.
Creamos, en nuestro paquete "interceptores", una clase llamada "InterceptorAuditoria". Que se encargar de realizar los
procesos de auditora de los que hablamos. Esta clase debe extender de "EmptyInterceptor", de la siguiente forma:

public class InterceptorAuditoria extends EmptyInterceptor


{
}

Repasemos los dos requerimientos que nuestra clase resolver:


1. Cada vez que un Usuariosea almacenado se debe mostrar un mensaje en consola.
2. Cada vez que un Usuariosea eliminado se debe mostrar un mensaje en consola.
Si revisamos la lista de mtodos de la interface "Interceptor" vemos que tiene 2 que podran servirnos: "onSave" para el
requerimiento nmero 1, y "onDelete" para el requerimiento nmero 2. Por lo que sobreescribimos estos dos mtodo en la clase
"InterceptorAuditoria".

public class InterceptorAuditoria extends EmptyInterceptor


{
@Override
public boolean onSave(Object entity, Serializable id, Object[] state, String[] propertyNames,
Type[] types)
{
}
@Override
public void onDelete(Object entity, Serializable id, Object[] state, String[] propertyNames, T
ype[] types)
{
}
}

Veamos primero cmo trabaja el mtodo "onSave" y cmo lo usaremos para nuestros propsitos de auditora.

boolean onSave(Object entity,


Serializable id,
Object[] state,
String[] propertyNames,
Type[] types)
throws CallbackException

Como dice en la lista: "onSave" es llamado antes de que un objeto sea guardado. Lo primero que podemos ver en la firma del mtodo
nos indica que este regresa un booleano. Este valor indica si nosotros hemos modificado este objeto de alguna forma, como por

www.javatutoriales.com/2010/08/hibernate-parte-11-interceptores-y.html

5/20

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 11: Interceptores y Eventos


ejemplo modificando alguno de los valores del mismo. Como para nuestros propsitos esto no es necesario regresaremos "false":

@Override
public boolean onSave(Object entity, Serializable id, Object[] state, String[] propertyNames, Type
[] types)
{
return false;
}

Dentro de la lista de parmetros que recibe este mtodo podemos ver que solamente nos interesa uno, de hecho el primero: "entity"
que es la entidad que ser almacenada en nuestra base de datos. Para poder saber si estamos guardando un "Usuario" o algn otro
tipo de entidad debemos usar el operador "instanceof". Despus haremos un cast al tipo "Usuario" para poder obtener de este su
"nombre" y su "username" de la siguiente forma:

if(entity instanceof Usuario)


{
Usuario usuario = (Usuario)entity;
System.out.println("Se ha almacenado al Usuario " + usuario.getNombre() + ", \"" + usuario.get
Username() + "\"");
}

Y listo, con este pequeo fragmento de cdigo hemos cumplido con el primer requerimiento de nuestro sistema de auditora. Nuestro
mtodo "onSave" queda de la siguiente forma:

public boolean onSave(Object entity, Serializable id, Object[] state, String[] propertyNames, Type
[] types)
{
if(entity instanceof Usuario)
{
Usuario usuario = (Usuario)entity;
System.out.println("Se ha almacenado al Usuario " + usuario.getNombre() + ", \"" + usuario
.getUsername() + "\"");
}
return false;
}

Ahora veamos nuestro segundo requerimiento: "Cada vez que un Usuariosea eliminado se debe mostrar un mensaje en consola". Para
el cual dijimos que usaremos el mtodo "onDelete":

void onDelete(Object entity,


Serializable id,
Object[] state,
String[] propertyNames,
Type[] types)
throws CallbackException

Recordemos que, segn la lista, "onDelete" es llamado antes de que la entidad sea eliminada. Podemos ver en la firma del mtodo que,
a diferencia de "onSave", "onDelete" no regresa nada. Esto es debido a que como la entidad va a ser eliminada, no tiene sentido
modificar los atributos del objeto.
Dentro de los parmetros que recibe el mtodo, ahora hay 2 que nos interesan: "entity", que es la entidad que se va a eliminar, e "id",
que es el identificador de dicha entidad en la base de datos.
Nuevamente, dentro del mtodo "onDelete" usaremos el operador "instanceof" para determinar si estamos eliminando un
"Usuario". Despus haremos un cast al tipo "Usuario" para poder obtener de este su "nombre" y usaremos el argumento "id" para
mostrar el identificador de esta entidad (el cual tambin podramos obtener invocando al mtodo "getId()" de nuestro Usuario):

if(entity instanceof Usuario)


{
Usuario usuario = (Usuario)entity;
System.out.println("Se eliminar al Usuario " + usuario.getNombre() + ", id=" + id);
}

www.javatutoriales.com/2010/08/hibernate-parte-11-interceptores-y.html

6/20

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 11: Interceptores y Eventos

Y listo, esto es suficiente para cumplir con nuestro segundo requerimiento. El mtodo "onDelete" queda de la siguiente forma:

public void onDelete(Object entity, Serializable id, Object[] state, String[] propertyNames, Type[
] types)
{
if(entity instanceof Usuario)
{
Usuario usuario = (Usuario)entity;
System.out.println("Se eliminar al Usuario " + usuario.getNombre() + ", id=" + id);
}
}

Y nuestra clase "InterceptorAuditoria" as:

public class InterceptorAuditoria extends EmptyInterceptor


{
@Override
public boolean onSave(Object entity, Serializable id, Object[] state, String[] propertyNames,
Type[] types)
{
if(entity instanceof Usuario)
{
Usuario usuario = (Usuario)entity;
System.out.println("Se ha almacenado al Usuario " + usuario.getNombre() + ", \"" + usu
ario.getUsername() + "\"");
}
return false;
}
@Override
public void onDelete(Object entity, Serializable id, Object[] state, String[] propertyNames, T
ype[] types)
{
if(entity instanceof Usuario)
{
Usuario usuario = (Usuario)entity;
System.out.println("Se eliminar al Usuario " + usuario.getNombre() + ", id=" + id);
}
}
}

Ya teniendo listo nuestro interceptor, lo siguiente que debemos hacer es indicarle a Hibernate que este interceptor existe para que pueda
utilizarlo. Este es el momento indicado para decir que Hibernate maneja dos tipos de Interceptores:
Interceptores de Session(Session-scoped)
Interceptores de SessionFactory(SessionFactory-scoped)
Los interceptores de session son especificados cuando se abre una sesin, usando el mtodo "openSession" de
"SessionFactory" (que en nuestra clase "AbstracDAO" ocurre en el mtodo "iniciaOperacion"), y funcionan nicamente para la
sesin que se est abriendo.
Los interceptores de SessionFactory se registran con el objeto "org.hibernate.cfg.Configuration" que usamos para
construir la "SessionFactory", usando el mtodo "buildSessionFactory" (que en nuestra clase "HibernateUtil" ocurre en el
constructor esttico). Estos interceptores son usados en todas las sesiones que se abran en nuestra aplicacin (a menos que
especifiquemos interceptores para una sesin especfica usando los interceptores de session).
Como en este caso nuestro interceptor solo el til si estamos trabajando con entidades "Usuario", usaremos interceptores de
session. Por lo que modificaremos un poco nuestra clase "AbstracDAO" para que pueda recibir un interceptor cada vez que vayamos a
almacenar una entidad.
Lo primero que haremos es agregar un nuevo mtodo "iniciaOperacion" que reciba como parmetro nuestro interceptor. He optado
por hacer esto ya que es la opcin que requiere menos cambios del cdigo que ya tenemos. As que nuestro nuevo mtodo
"iniciaOperacion" queda de la siguiente forma:

protected void iniciaOperacion(Interceptor interceptor)


{
sesion = HibernateUtil.getSessionFactory().openSession(interceptor);
sesion.getTransaction().begin();
}

www.javatutoriales.com/2010/08/hibernate-parte-11-interceptores-y.html

7/20

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 11: Interceptores y Eventos


Este nuevo mtodo "iniciaOperacion" lo usaremos en el mtodo "almacenaEntidad" de la misma clase "AbstractDAO", de la
siguiente forma:

dummy.iniciaOperacion(new InterceptorAuditoria());

Esto nos resuelve parte referente al primer requerimiento, pero si revisan la clase "AbstractDAO" vern que no existe ningn mtodo
para eliminar entidades, por lo que crearemos uno muy similar a "almacenaEntidad", pero que haga uso del mtodo "delete" en vez
de "saveOrUpdate". Este mtodo se llamar "eliminaEntidad", y queda de esta forma:

public static void eliminaEntidad(Object entidad) throws HibernateException


{
AbstractDAO dummy = new AbstractDAO(){};
try
{
dummy.iniciaOperacion(new InterceptorAuditoria());
dummy.getSession().delete(entidad);
dummy.getSession().flush();
}
catch(HibernateException he)
{
dummy.manejaExcepcion(he);
}
finally
{
dummy.terminaOperacion();
}
}

Ahora que ya tenemos los dos mtodos listos para usarlos, solo nos falta usarlos en nuestra clase "Main" en nuestro mtodo "main".
Crearemos 5 Usuarios y despus eliminaremos a 2 de ellos, para ver que, efectivamente, tengamos la salida esperada en la consola.
Coloquemos el siguiente cdigo en nuestro mtodo "main":

public static void main(String[] args)


{
Usuario usuario1 = new Usuario("usuario 1", "username usuario 1", "password usuario 1");
Usuario usuario2 = new Usuario("usuario 2", "username usuario 2", "password usuario 2");
Usuario usuario3 = new Usuario("usuario 3", "username usuario 3", "password usuario 3");
Usuario usuario4 = new Usuario("usuario 4", "username usuario 4", "password usuario 4");
Usuario usuario5 = new Usuario("usuario 5", "username usuario 5", "password usuario 5");
AbstractDAO.almacenaEntidad(usuario1);
AbstractDAO.almacenaEntidad(usuario2);
AbstractDAO.almacenaEntidad(usuario3);
AbstractDAO.almacenaEntidad(usuario4);
AbstractDAO.almacenaEntidad(usuario5);
AbstractDAO.eliminaEntidad(usuario2);
AbstractDAO.eliminaEntidad(usuario5);
}

El cdigo es muy simple: creamos 5 Usuarios que posteriormente guardamos en nuestra base de datos usando el mtodo
"almacenaEntidad" de la clase "UsuarioDAO", y posteriormente eliminamos a los Usuarios 2 y 5 usando el mtodo
"eliminaEntidad" de la clase "UsuarioDAO".
Al ejecutar el cdigo anterior genera la siguiente salida en nuestra consola:

www.javatutoriales.com/2010/08/hibernate-parte-11-interceptores-y.html

8/20

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 11: Interceptores y Eventos

Como podemos ver hemos obtenido los 7 mensajes esperados en consola. Por lo que nuestro ejemplo ha funcionado correctamente ^_^.
Ahora veremos cmo funciona y cmo trabajar con el sistema de eventos de Hibernate.

2. Eventos
Si queremos que nuestra aplicacin reaccione a ciertos eventos de nuestra capa de persistencia, podemos usar la arquitectura de eventos
de Hibernate. El sistema de eventos puede ser usado para complementar, o reemplazar, el uso de interceptores.
Todos los mtodos de la interface "Session" estn relacionados con un evento del cual podemos recibir una notificacin. Cuando
invocamos algn mtodo como "save", "load", "delete", etc. Hibernate lanza un evento y podemos realizar alguna accin en ese
momento. Por cada tipo de evento existe una interface "xxEventListener" que tendremos que implementar para recibir notificaciones
para ese evento. Estas interfaces reciben un parmetro del tipo del evento que la lanzo. Por ejemplo, si esperamos una notificacin de un
evento "saveOrUpdate", tendremos que implementar una interface "org.hibernate.event.SaveOrUpdateEventListener" en
cuyo mtodo de escucha recibe un objeto de tipo "org.hibernate.event.SaveOrUpdateEvent".
El paquete "org.hibernate.event" contiene las siguientes interfaces que nos permiten recibir notificaciones de eventos:
AutoFlushEventListener
DeleteEventListener
DirtyCheckEventListener
EvictEventListener
FlushEntityEventListener
FlushEventListener
InitializeCollectionEventListener
LoadEventListener
LockEventListener
MergeEventListener
PersistEventListener
PostCollectionRecreateEventListener
PostCollectionRemoveEventListener
PostCollectionUpdateEventListener
PostDeleteEventListener
PostInsertEventListener
PostLoadEventListener
PostUpdateEventListener
PreCollectionRecreateEventListener
PreCollectionRemoveEventListener
PreCollectionUpdateEventListener
PreDeleteEventListener
PreInsertEventListener
PreLoadEventListener
PreUpdateEventListener
RefreshEventListener
ReplicateEventListener
SaveOrUpdateEventListener
Para este ejemplo crearemos un sistema que reciba notificaciones despus de que una entidad "Usuario" sea cargada de la base de
datos, antes y despus de eliminarla y antes de actualizarla, y muestre en consola el mensaje correspondiente al eventos que se ha
recibido.
Crearemos un nuevo proyecto en NetBeans siguiendo los mismos pasos que usamos para el proyecto que usa los interceptores. Las
nicas diferencias son que ahora crearemos un paquete llamados "eventos" en lugar de "interceptores" y que usaremos una base
de datos llamada "hibernateeventos".
Usaremos la misma clase "Usuario" del ejemplo anterior, as como las clases "HibernateUtil" del segundo tutorial, y
"AbstractDAO" del noveno tutorial.
Hagamos nuevamente una lista con los requerimientos de nuestra aplicacin, en lo que a eventos se refiere.

www.javatutoriales.com/2010/08/hibernate-parte-11-interceptores-y.html

9/20

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 11: Interceptores y Eventos


1. Antes de que un Usuariosea cargado debemos mostrar un mensaje en consola.
2. Antes de eliminar un Usuariodebemos mostrar un mensaje en consola.
3. Despus de eliminar un Usuariodebemos mostrar un mensaje en consola.
4. Antes de actualizar un Usuariodebemos mostrar un mensaje en consola.
Si echamos un vistazo a la lista listeners de eventos que nos proporciona Hibernate podemos ver que tenemos 4 interfaces que nos sirven
perfectamente para cada uno de los requerimientos (vaya coincidencia ^_^!).
Comencemos viendo cmo cubrir el primer requerimiento. Si revisamos la lista de listeners disponibles vemos que hay uno llamado
"PostLoadEventListener" el cual, como su nombre lo indica, es llamado despus de que la entidad es cargada en el contexto
persistente de nuestra aplicacin. Como la entidad ya se encuentra cargada, es posible acceder a sus atributos para consultarlos o
modificarlos.
Creamos una nueva clase, en el paquete "eventos", llamada "CargaUsuarioListener", la cual implementar la interface
"PostLoadEventListener":

public class CargaUsuarioListener implements PostLoadEventListener


{
}
La interface "PostLoadEventListener" tiene un solo mtodo llamado "onPostLoad", el cual recibe un solo argumento de tipo
"org.hibernate.event.PostLoadEvent", de la siguiente forma:

public void onPostLoad(PostLoadEvent postLoadEvent);

La clase "PostLoadEvent" tiene dos mtodos que nos sern de mucha utilidad: "getEntity()", que regresa un "Object" que es la
entidad que se est recuperando, y "getId()", y regesa el identificador de dicha entidad. Primero usaremos "getEntity()" para
recuperar la entidad cargada, de la siguiente forma:

Object entidad = postLoadEvent.getEntity();

Despus revisamos, usando el operador "instanceof", si la entidad es de tipo "Usuario". De ser el caso, hacemos un cast al tipo
"Usuario" para poder obtener su "username". Una vez hecho esto, usamos el mtodo "getId()" para obtener el identificador de la
entidad. De la siguiente forma:

if (entidad instanceof Usuario)


{
Usuario usuario = (Usuario) entidad;
System.out.println("Se ha cargado el usuario " + usuario.getUsername() + ", id=\"" + postLoadE
vent.getId() + "\"");
}

Finalmente la clase "CargaUsuarioListener" queda de la siguiente forma:

public class CargaUsuarioListener implements PostLoadEventListener


{
public void onPostLoad(PostLoadEvent postLoadEvent)
{
Object entidad = postLoadEvent.getEntity();
if (entidad instanceof Usuario)
{
Usuario usuario = (Usuario) entidad;
System.out.println("Se ha cargado el usuario " + usuario.getUsername() + ", id=\"" + p
ostLoadEvent.getId() + "\"");
}
}
}

www.javatutoriales.com/2010/08/hibernate-parte-11-interceptores-y.html

10/20

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 11: Interceptores y Eventos


Veamos ahora el segundo requerimiento: "Antes de eliminar un Usuario debemos mostrar un mensaje en consola". Nuevamente si
revisamos la lista de listeners vemos que existe una interface llamada "PreDeleteEventListener" que, como su nombre indica, es
llamado antes de que una entidad sea eliminada de la base de datos.
Creamos una nueva clase llamada "PreEliminaUsuarioListener" que implementar la interface "PreDeleteEventListener". De
la siguiente forma:

public class PreEliminaUsuarioListener implements PreDeleteEventListener


{
}

La interface "PreDeleteEventListener" tiene un solo mtodo llamado "onPreDelete", que regresa un booleano que indica la
operacin
de
eliminacin
debe
ser
cancelada.
Tambin
recibe
un
nico
argumento
de
tipo
"org.hibernate.event.PreDeleteEvent". La firma del mtodo es la siguiente:

public boolean onPreDelete(PreDeleteEvent preDeleteEvent);

Lo primero que haremos es regresar un valor de "false", ya que NO queremos que la operacin de eliminacin sea cancelada.

public boolean onPreDelete(PreDeleteEvent preDeleteEvent)


{
return false;
}

La clase "PreDeleteEvent" tiene prcticamente los mismos mtodos que "PostLoadEvent" (al menos los que nos interesan). Por lo
nuevamente usaremos el mtodo "getEntity()" para obtener la entidad que estamos a punto de eliminar, y despus revisamos,
usando el operador "instanceof", si la entidad es de tipo "Usuario". De ser el caso, hacemos un cast al tipo "Usuario" para poder
obtener su "username". Una vez hecho esto, usamos el mtodo "getId()" para obtener el identificador de la entidad. Por lo que el
mtodo queda de la siguiente forma:

public boolean onPreDelete(PreDeleteEvent preDeleteEvent)


{
Object entidad = preDeleteEvent.getEntity();
if (entidad instanceof Usuario)
{
Usuario usuario = (Usuario) entidad;
System.out.println("Se eliminar al usuario " + usuario.getUsername() + ", id=\"" + preDel
eteEvent.getId() + "\"");
}
return false;
}

Prosigamos con el tercer requerimiento: "Despus de eliminar un Usuario debemos mostrar un mensaje en consola". Para este
requerimiento nuevamente haremos uso de una de las interfaces de la lista: "PostDeleteEventListener", as que crearemos una
nueva clase llamada "PostEliminaUsuarioListener", en el paquete "eventos", que implemente esta interface, de la siguiente
forma:

public class PostEliminaUsuarioListener implements PostDeleteEventListener


{
}

Esta
interface
tiene
un
solo
mtodo:
"onPostDelete",
"org.hibernate.event.PostDeleteEvent", de la siguiente forma:

que

recibe

un

parmetro

de

tipo

public void onPostDelete(PostDeleteEvent pde);

www.javatutoriales.com/2010/08/hibernate-parte-11-interceptores-y.html

11/20

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 11: Interceptores y Eventos

Al igual que en los casos anteriores, "PostDeleteEvent" tiene dos mtodos que nos interesan "getEntity()", y "getId()". Como
creo que la idea de cmo implementaremos nuestros eventos ya est entendida, solo colocar el cdigo de la clase
"PostEliminaUsuarioListener" que se encarga del requerimiento 3 y "ActualizaUsuarioListener" que se encarga del
requerimiento 4.
La clase "PostEliminaUsuarioListener" queda de la siguiente forma:

public class PostEliminaUsuarioListener implements PostDeleteEventListener


{
public void onPostDelete(PostDeleteEvent postDeleteEvent)
{
Object entidad = postDeleteEvent.getEntity();
if (entidad instanceof Usuario)
{
Usuario usuario = (Usuario) entidad;
System.out.println("Se ha eliminado al Usuario " + usuario.getUsername() + ", id=\"" +
postDeleteEvent.getId() + "\"");
}
}
}

Y la clase "ActualizaUsuarioListener" queda as:

public class ActualizaUsuarioListener implements PreUpdateEventListener


{
public boolean onPreUpdate(PreUpdateEvent preUploadEvent)
{
Object entidad = preUploadEvent.getEntity();
if(entidad instanceof Usuario)
{
Usuario usuario = (Usuario)entidad;
System.out.println("Se va a actualizar al usuario " + usuario.getUsername() + ", id=\"
" + preUploadEvent.getId() + "\"");
}
return false;
}
}

Ahora debemos decirle a Hibernate que queremos que estas clases reciban notificaciones para los eventos indicados. Para esto existen
dos formas: la primera y que me parece ms sencilla es colocando los listeners en el archivo de configuracin "hibernate.cfg.xml"
en la configuracin del "session-factory", y la segunda es en cdigo, al momento de crear el objeto
"org.hibernate.cfg.Configuration" o "org.hibernate.cfg.AnnotationConfiguration" (que nosotros hacemos en la
clase "HibernateUtil" en nuestro bloque de inicializacin esttico). Veremos cmo hacerlo de las dos formas, aunque en los archivos
del tutorial dejar la versin que hace uso del archivo de configuracin.

2.1. CONFIGURACIN DE LISTENERS DE EVENTOS EN EL ARCHIVO DE CONFIGURACIN


En la primera de las formas debemos colocar, al final del archivo "hibernate.cfg.xml", un elemento "<event>", en cuyo atributo
"type" indicamos el tipo de evento que est esperando recibir el listener que indicaremos posteriormente en el sub-elemento "
<listener>", en cuyo atributo "class" indicaremos la clase que responder al evento. Por ejemplo, para indicar que la clase
"hibernate.eventos.eventos.CargaUsuarioListener" debe responder al evento de que una entidad haya sido cargada lo
hacemos de la siguiente forma:

<event type="post-load">
<listener class="hibernate.eventos.eventos.CargaUsuarioListener" />
</event>

Los tipos de eventos, como deben ser marcados en el atributo "type" del elemento "<event>" son:
*Nota: Algunos de los listenes pueden tom ar m s de un valor, en la tabla los he separado usando una com a, pero en su archivo de configuracin
solo deben colocar uno de los dos.

Clase Listener

www.javatutoriales.com/2010/08/hibernate-parte-11-interceptores-y.html

Valor de typo

12/20

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 11: Interceptores y Eventos


AutoFlushEventListener

auto-flush

DeleteEventListener

delete

DirtyCheckEventListener

dirty-check

EvictEventListener

evict

FlushEntityEventListener

flush-entity

FlushEventListener

Flush

InitializeCollectionEventListener

load-collection

LoadEventListener

load

LockEventListener

Lock

MergeEventListener

merge

PersistEventListener

create, create-onflush

PostCollectionRecreateEventListener

post-collection-recreate

PostCollectionRemoveEventListener

post-collection-remove

PostCollectionUpdateEventListener

post-collection-update

PostDeleteEventListener

post-delete, post-commit-delete

PostInsertEventListener

post-insert, post-commit-insert

PostLoadEventListener

post-load

PostUpdateEventListener

post-update, post-commit-update

PreCollectionRecreateEventListener

pre-collection-recreate

PreCollectionRemoveEventListener

pre-collection-remove

PreCollectionUpdateEventListener

pre-collection-update

PreDeleteEventListener

pre-delete

PreInsertEventListener

pre-insert

PreLoadEventListener

pre-load

PreUpdateEventListener

pre-update

RefreshEventListener

refresh

ReplicateEventListener

replicate

SaveOrUpdateEventListener

save-update, save, update

Por lo tanto, los listeners declarados es nuestro archivo de configuracin quedan de la siguiente forma:

<event type="post-load">
<listener class="hibernate.eventos.eventos.CargaUsuarioListener" />
</event>
<event type="pre-delete">
<listener class="hibernate.eventos.eventos.PreEliminaUsuarioListener" />
</event>
<event type="post-delete">
<listener class="hibernate.eventos.eventos.PostEliminaUsuarioListener" />
</event>
<event type="pre-update">
<listener class="hibernate.eventos.eventos.ActualizaUsuarioListener" />
</event>

Y el archivo completo de configuracin quedara de esta forma:

www.javatutoriales.com/2010/08/hibernate-parte-11-interceptores-y.html

13/20

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 11: Interceptores y Eventos

<?xml version="1.0" encoding="UTF-8"?>


<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<!-- parametros para la conexion a la base de datos -->
<property name="connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="connection.url">jdbc:mysql://localhost/hibernateeventos</property>
<property name="connection.username">usuario</property>
<property name="connection.password">password</property>
<!-- Configuracion del pool interno -->
<property name="connection.pool_size">1</property>
<!-- Dialecto de la base de datos -->
<property name="dialect">org.hibernate.dialect.MySQL5Dialect</property>
<!-- Otras propiedades importantes -->
<property name="show_sql">false</property>
<property name="hbm2ddl.auto">create-drop</property>
<!-- Clases o Archivos de mapeo -->
<mapping class="hibernate.eventos.modelo.Usuario" />
<event type="post-load">
<listener class="hibernate.eventos.eventos.CargaUsuarioListener" />
</event>
<event type="pre-delete">
<listener class="hibernate.eventos.eventos.PreEliminaUsuarioListener" />
</event>
<event type="post-delete">
<listener class="hibernate.eventos.eventos.PostEliminaUsuarioListener" />
</event>
<event type="pre-update">
<listener class="hibernate.eventos.eventos.ActualizaUsuarioListener" />
</event>
</session-factory>
</hibernate-configuration>

Veamos que nuestra aplicacin funciona correctamente colocando el siguiente cdigo en el mtodo "main" de nuestra clase "Main":

public static void main(String[] args)


{
Usuario usuario1 = new Usuario("usuario 1", "username usuario1", "password usuario1");
Usuario usuario2 = new Usuario("usuario 2", "username usuario2", "password usuario2");
Usuario usuario3 = new Usuario("usuario 3", "username usuario3", "password usuario3");
Usuario usuario4 = new Usuario("usuario 4", "username usuario4", "password usuario4");
//

Almacenamos las 4 entidades Usuario


AbstractDAO.almacenaEntidad(usuario1);
AbstractDAO.almacenaEntidad(usuario2);
AbstractDAO.almacenaEntidad(usuario3);
AbstractDAO.almacenaEntidad(usuario4);

//

Recuperamos 2 Usuarios
AbstractDAO.getEntidad(usuario2.getId(), Usuario.class);
AbstractDAO.getEntidad(usuario3.getId(), Usuario.class);

//

Actualizamos 3 Usuarios
usuario1.setNombre("Nuevo nombre del Usuario1");
usuario2.setNombre("Nuevo nombre del Usuario2");
usuario3.setNombre("Nuevo nombre del Usuario3");
AbstractDAO.almacenaEntidad(usuario1);
AbstractDAO.almacenaEntidad(usuario2);
AbstractDAO.almacenaEntidad(usuario3);

//

Eliminamos 2 Usuarios
AbstractDAO.eliminaEntidad(usuario1);
AbstractDAO.eliminaEntidad(usuario4);

www.javatutoriales.com/2010/08/hibernate-parte-11-interceptores-y.html

14/20

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 11: Interceptores y Eventos


Nuevamente el cdigo es muy sencillo y autoexplicativo. Simplemente creamos 4 objetos "Usuario" que posteriormente almacenamos
en la base de datos. Luego recuperamos 2 de estos Usuarios, haciendo uso de su identificador, actualizamos 3, y eliminamos 2, con lo
que esperamos tener en consola 9 mensajes (2 de recuperacin, 3 de actualizacin, 2 de antes de eliminar, y 2 de despus de eliminar).
Ejecutemos nuestra aplicacin para ver la salida:

Como podemos ver, tenemos los 9 mensajes en consola que esperbamos, por lo que nuestros listeners de eventos han funcionado
correctamente.
Ahora veamos cmo hacer lo mismo en cdigo, directo en nuestra clase "HibernateUtil".

2.2. CONFIGURACIN DE LISTENERS DE EVENTOS EN CDIGO


Si
recordamos, "HibernateUtil"
tiene un
inicializador esttico
en
donde se
crea un
objeto de
tipo
"org.hibernate.cfg.Configuration", si usamos archivos de mapeo, o "org.hibernate.cfg.AnnotationConfiguration",
si usamos anotaciones. Actualmente creamos este objeto e inmediatamente, mediante encadenamiento de mtodos, creamos el
"SessionFactory" correspondiente:

new AnnotationConfiguration().configure().buildSessionFactory();

Como ahora necesitamos una referencia a este objeto para registrar nuestros listeners tendremos que modificar la lnea anterior para
hacer lo mismo, pero en dos pasos, de esta forma:

Configuration cfg = new AnnotationConfiguration();


sessionFactory = cfg.configure().buildSessionFactory();

As ya tenemos una referencia a nuestro objeto "Configuration" para poder registrar los listeners de eventos que necesitamos. El
objeto "org.hibernate.cfg.Configuration" tiene un mtodo llamado "getEventListeners()", que regresa un objeto de tipo
"org.hibernate.event.EventListeners", el cual mantendr la lista de listeners de nuestra aplicacin. Este objeto tiene una serie
de mtodos setters, uno para cada tipo de listeners, los cuales reciben un arreglo con los listeners de eventos que queremos registrar.
Por ejemplo, para registrar el listener "CargaUsuarioListener", que recordemos que es de tipo "PostLoadEventListener", lo
hacemos de la siguiente forma:

Configuration cfg = new AnnotationConfiguration();


EventListeners eventListeners = cfg.getEventListeners();
eventListeners.setPostLoadEventListeners(new PostLoadEventListener[]{new CargaUsuarioListener()});

Donde creamos un arreglo annimo de tipo "PostLoadEventListener" cuyo nico elemento es un objeto de tipo
"CargaUsuarioListener". Su tuviramos otro listener de tipo "PostLoadEventListener" simplemente lo agregaramos dentro del
mismo arreglo.
Podemos observar que este arreglo annimo lo pasamos como parmetro al mtodo "setPostLoadEventListeners" que es que
usamos para registrar los listeners de tipo "PostLoadEventListener". Hacemos lo mismo con el resto de nuestros listeners de la
siguiente forma:

www.javatutoriales.com/2010/08/hibernate-parte-11-interceptores-y.html

15/20

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 11: Interceptores y Eventos

eventListeners.setPreDeleteEventListeners (new PreDeleteEventListener[] {new PreEliminaUsuarioList


ener()});
eventListeners.setPostDeleteEventListeners(new PostDeleteEventListener[]{new PostEliminaUsuarioLis
tener()});
eventListeners.setPreUpdateEventListeners (new PreUpdateEventListener[] {new ActualizaUsuarioListe
ner()});

Con lo que la nueva clase "HibernateUtil" queda de la siguiente forma:

public class HibernateUtil


{
private static final SessionFactory sessionFactory;
static
{
try
{
Configuration cfg = new AnnotationConfiguration();
EventListeners eventListeners = cfg.getEventListeners();
eventListeners.setPostLoadEventListeners (new PostLoadEventListener[] {new CargaUsua
rioListener()});
eventListeners.setPreDeleteEventListeners (new PreDeleteEventListener[] {new PreElimin
aUsuarioListener()});
eventListeners.setPostDeleteEventListeners(new PostDeleteEventListener[]{new PostElimi
naUsuarioListener()});
eventListeners.setPreUpdateEventListeners (new PreUpdateEventListener[] {new Actualiza
UsuarioListener()});
sessionFactory = cfg.configure().buildSessionFactory();
}
catch (HibernateException he)
{
System.err.println("Ocurri un error en la inicializacin de la SessionFactory: " + he
);
throw new ExceptionInInitializerError(he);
}
}
public static SessionFactory getSessionFactory()
{
return sessionFactory;
}
}

Y listo. Ahora probemos que funciona colocando el siguiente cdigo en el mtodo "main" de nuestra clase "Main":

www.javatutoriales.com/2010/08/hibernate-parte-11-interceptores-y.html

16/20

10/11/13

Tutoriales de Programacion Java: Hibernate - Parte 11: Interceptores y Eventos

public static void main(String[] args)


{
Usuario usuario1 = new Usuario("usuario 1", "username usuario1", "password usuario1");
Usuario usuario2 = new Usuario("usuario 2", "username usuario2", "password usuario2");
Usuario usuario3 = new Usuario("usuario 3", "username usuario3", "password usuario3");
Usuario usuario4 = new Usuario("usuario 4", "username usuario4", "password usuario4");
//

Almacenamos las 4 entidades Usuario


AbstractDAO.almacenaEntidad(usuario1);
AbstractDAO.almacenaEntidad(usuario2);
AbstractDAO.almacenaEntidad(usuario3);
AbstractDAO.almacenaEntidad(usuario4);

//

Recuperamos 2 Usuarios
AbstractDAO.getEntidad(usuario2.getId(), Usuario.class);
AbstractDAO.getEntidad(usuario3.getId(), Usuario.class);

//

Actualizamos 3 Usuarios
usuario1.setNombre("Nuevo nombre del Usuario1");
usuario2.setNombre("Nuevo nombre del Usuario2");
usuario3.setNombre("Nuevo nombre del Usuario3");
AbstractDAO.almacenaEntidad(usuario1);
AbstractDAO.almacenaEntidad(usuario2);
AbstractDAO.almacenaEntidad(usuario3);

//

Eliminamos 2 Usuarios
AbstractDAO.eliminaEntidad(usuario1);
AbstractDAO.eliminaEntidad(usuario4);

Que es el mismo que ya haba explicado. Solo recordemos que esperamos obtener en la consola 9 mensajes: 2 de recuperacin, 3 de
actualizacin, 2 de antes de eliminar, y 2 de despus de eliminar. Cuando ejecutamos nuestra aplicacin obtenemos la siguiente salida:

Como podemos ver, obtuvimos los 9 mensajes esperados. Por lo que nuestro ejemplo ha funcionado correctamente.
Pues bien, este fue el ltimo tutorial oficial de la serie de Hibernate, los cuales espero sirvan para conocer los conceptos bsicos de esta
herramienta ORM que es bastante til.
Cualquier duda, comentario, o sugerencia no duden en dejarlo en la seccin correspondiente.
Saludos.
Descarga los archivos de este tutorial desde aqu:
Interceptores con Hibernate
Eventos con Hibernate

Entradas Relacionadas:
Parte 1: Persistiendo Objetos Simples usando Mapeos en XML
Parte 2: Persistiendo Objetos Simples usando Anotaciones (Metadatos)
Parte 3: Relaciones / Uno a uno
Parte 4: Relaciones / Uno a muchos
Parte 5: Relaciones / Muchos a uno
Parte 6: Relaciones / Muchos a Muchos
Parte 7: HQL Primera Parte
Parte 8: HQL Segunda Parte
Parte 9: Parmetros en HQL
Parte 10: Herencia
Publicado por Alex en 21:15
Reacciones:

divertido (2)

interesante (1)

increible (1)

www.javatutoriales.com/2010/08/hibernate-parte-11-interceptores-y.html

no me gusta (0)

17/20

Hibernate Annotations
Reference Guide
Version: 3.1 beta 9

Table of Contents
Preface ............................................................................................................................................ iv
1. Setting up an annotations project ................................................................................................ 1
1.1. Requirements ..................................................................................................................... 1
1.2. Configuration ..................................................................................................................... 1
2. Entity Beans ................................................................................................................................ 3
2.1. Intro .................................................................................................................................. 3
2.2. Mapping with EJB3 Annotations ......................................................................................... 3
2.2.1. Declaring an entity bean .......................................................................................... 3
2.2.1.1. Defining the table ......................................................................................... 3
2.2.1.2. Versioning for optimistic locking ................................................................... 4
2.2.2. Mapping simple properties ....................................................................................... 4
2.2.2.1. Declaring basic property mappings ................................................................ 4
2.2.2.2. Declaring column attributes ........................................................................... 5
2.2.2.3. Embedded objects (aka components) .............................................................. 6
2.2.2.4. Non-annotated property defaults .................................................................... 8
2.2.. Mapping identifier properties ..................................................................................... 8
2.2.4. Mapping inheritance .............................................................................................. 11
2.2.4.1. Table per class ............................................................................................ 11
2.2.4.2. Single table per class hierarchy .................................................................... 11
2.2.4.3. Joined subclasses ........................................................................................ 12
2.2.4.4. Inherit properties from superclasses ............................................................. 12
2.2.5. Mapping entity bean associations/relationships ........................................................ 14
2.2.5.1. One-to-one ................................................................................................. 14
2.2.5.2. Many-to-one ............................................................................................... 15
2.2.5.3. Collections ................................................................................................. 15
2.2.5.4. Transitive persistence with cascading ........................................................... 21
2.2.5.5. Association fetching ................................................................................... 21
2.2.6. Mapping composite primary and foreign keys ......................................................... 21
2.2.7. Mapping secondary tables ...................................................................................... 23
2.3. Mapping Queries .............................................................................................................. 23
2.3.1. Mapping EJBQL/HQL queries ............................................................................... 23
2.3.2. Mapping native queries .......................................................................................... 24
2.4. Hibernate Annotation Extensions ...................................................................................... 27
2.4.1. Entity ................................................................................................................... 28
2.4.2. Identifier ............................................................................................................... 29
2.4.3. Property ................................................................................................................ 29
2.4.3.1. Access type ................................................................................................ 29
2.4.3.2. Formula ..................................................................................................... 31
2.4.3.3. Type .......................................................................................................... 31
2.4.3.4. Index ......................................................................................................... 32
2.4.4. Inheritance ............................................................................................................ 32
2.4.5. Single Association related annotations .................................................................... 32
2.4.6. Collection related annotations ................................................................................ 32
2.4.6.1. Parameter annotations ................................................................................. 32
2.4.6.2. Extra collection types .................................................................................. 33
2.4.7. Cache ................................................................................................................... 35
2.4.8. Filters ................................................................................................................... 35
2.4.9. Queries ................................................................................................................. 36
Hibernate 3.1 beta 9

ii

Hibernate Annotations
3. Hibernate Validator .................................................................................................................. 37
3.1. Constraints ...................................................................................................................... 37
3.1.1. What is a constraint? .............................................................................................. 37
3.1.2. Built in constraints ................................................................................................. 37
3.1.3. Error messages ...................................................................................................... 38
3.1.4. Writing your own constraints ................................................................................. 39
3.1.5. Annotating your domain model .............................................................................. 40
3.2. Using the Validator framework ......................................................................................... 41
3.2.1. Database schema-level validation ........................................................................... 41
3.2.2. Hibernate event-based validation ............................................................................ 42
3.2.3. Application-level validation ................................................................................... 42
3.2.4. Validation informations ......................................................................................... 42
4. Hibernate Lucene Integration ................................................................................................... 44
4.1. Using Lucene to index your entities ................................................................................... 44
4.1.1. Annotating your domain model .............................................................................. 44
4.1.2. Enabling automatic indexing .................................................................................. 44

Hibernate 3.1 beta 9

iii

Preface
Hibernate, like all other object/relational mapping tools, requires metadata that governs the transformation of
data from one representation to the other (and vice versa). In Hibernate 2.x, mapping metadata is most of the
time declared in XML text files. Another option is XDoclet, utilizing Javadoc source code annotations and a
preprocessor at compile time. The same kind of annotation support is now available in the standard JDK, although more powerful and better supported by tools. IntelliJ IDEA, and Eclipse for example, support autocompletion and syntax highlighting of JDK 5.0 annotations. Annotations are compiled into the bytecode and
read at runtime (in Hibernate's case on startup) using reflection, so no external XML files are needed.
The EJB3 specification recognizes the interest and the success of the transparent object/relational mapping
paradigm. The EJB3 specification standardizes the basic APIs and the metadata needed for any object/relational
persistence mechanism. Hibernate EntityManager implements the programming interfaces and lifecycle rules
as defined by the EJB3 persistence specification. Together with Hibernate Annotations, this wrapper implements a complete (and standalone) EJB3 persistence solution on top of the mature Hibernate core. You may use
a combination of all three together, annotations without EJB3 programming interfaces and lifecycle, or even
pure native Hibernate, depending on the business and technical needs of your project. You can at all times fall
back to Hibernate native APIs, or if required, even to native JDBC and SQL.
Please note that this documentation is based on a preview release of the Hibernate Annotations that follows the
public final draft of EJB 3.0/JSR-220 persistence annotations. This work is already very close to the final concepts in the new specification. Our goal is to provide a complete set of ORM annotations, including EJB3
standard annotations as well as Hibernate3 extensions for cases not covered by the specification. Eventually
you will be able to create all possible mappings with annotations. See the JIRA road mapsection for more information.
The EJB3 Public final draft has change some annotations, please refer to http://www.hibernate.org/371.html as
a migration guide between Hibernate Annotations 3.1beta7 and 3.1beta8.

Hibernate 3.1 beta 9

iv

Chapter 1. Setting up an annotations project


1.1. Requirements

Download and unpack the Hibernate Annotations distribution from the Hibernate website.

This preview release requires Hibernate 3.2.0.CR2 and above. Do not use this release of Hibernate Annotations with an older version of Hibernate 3.x!

This release is known to work on Hibernate core 3.2.0.CR2

Make sure you have JDK 5.0 installed. You can of course continue using XDoclet and get some of the benefits of annotation-based metadata with older JDK versions. Note that this document only describes JDK
5.0 annotations and you have to refer to the XDoclet documentation for more information.

1.2. Configuration
First, set up your classpath (after you have created a new project in your favorite IDE):

Copy all Hibernate3 core and required 3rd party library files (see lib/README.txt in Hibernate).

Copy hibernate-annotations.jar and lib/ejb3-persistence.jar from the Hibernate Annotations distribution to your classpath as well.

To use the Chapter 4, Hibernate Lucene Integration, add the lucene jar file.

We also recommend a small wrapper class to startup Hibernate in a static initializer block, known as HibernateUtil. You might have seen this class in various forms in other areas of the Hibernate documentation. For
Annotation support you have to enhance this helper class as follows:
package hello;
import
import
import
import

org.hibernate.*;
org.hibernate.cfg.*;
test.*;
test.animals.Dog;

public class HibernateUtil {


private static final SessionFactory sessionFactory;
static {
try {
sessionFactory = new AnnotationConfiguration().buildSessionFactory();
} catch (Throwable ex) {
// Log exception!
throw new ExceptionInInitializerError(ex);
}
}
public static Session getSession()
throws HibernateException {
return sessionFactory.openSession();
}
}

Hibernate 3.1 beta 9

Setting up an annotations project

Interesting here is the use of AnnotationConfiguration. The packages and annotated classes are declared in
your regular XML configuration file (usually hibernate.cfg.xml). Here is the equivalent of the above declaration:
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<mapping package="test.animals"/>
<mapping class="test.Flight"/>
<mapping class="test.Sky"/>
<mapping class="test.Person"/>
<mapping class="test.animals.Dog"/>
</session-factory>
</hibernate-configuration>

Note that you can mix the hbm.xml use and the new annotation one.
Alternatively, you can define the annotated classes and packages using the programmatic API
sessionFactory = new AnnotationConfiguration()
.addPackage("test.animals") //the fully qualified package name
.addAnnotatedClass(Flight.class)
.addAnnotatedClass(Sky.class)
.addAnnotatedClass(Person.class)
.addAnnotatedClass(Dog.class)
.buildSessionFactory();

You can also use the Hibernate Entity Manager which has it's own configuration mechanism. Please refer to
this project documentation for more details.
There is no other difference in the way you use Hibernate APIs with annotations, except for this startup routine
change or in the configuration file. You can use your favorite configuration method for other properties ( hibernate.properties, hibernate.cfg.xml, programmatic APIs, etc). You can even mix annotated persistent
classes and classic hbm.cfg.xml declarations with the same SessionFactory. You can however not declare a
class several times (whether annotated or through hbm.xml). You cannot mix configuration strategies (hbm vs
annotations) in a mapped entity hierarchy either.
To ease the migration process from hbm files to annotations, the configuration mechanism detects the mapping
duplication between annotations and hbm files. HBM files are then prioritized over annotated metadata on a
class to class basis. You can change the priority using hibernate.mapping.precedence property. The default is
hbm, class, changing it to class, hbm will prioritize the annotated classes over hbm files when a conflict occurs.

Hibernate 3.1 beta 9

Chapter 2. Entity Beans


2.1. Intro
This section covers EJB 3.0 entity bean annotations and Hibernate-specific extensions.

2.2. Mapping with EJB3 Annotations


EJB3 entity beans are plain POJOs. Actually they represent the exact same concept as the Hibernate persistent
entities. Their mappings are defined through JDK 5.0 annotations (an XML descriptor syntax for overriding
will be defined in the EJB3 specification, but it's not finalized so far). Annotations can be split in two categories, the logical mapping annotations (allowing you to describe the object model, the class associations, etc.) and
the physical mapping annotations (describing the physical schema, tables, columns, indexes, etc). We will mix
annotations from both categories in the following code examples.
EJB3 annotations are in the javax.persistence.* package. Most JDK 5 compliant IDE (like Eclipse, IntelliJ
IDEA and Netbeans) can autocomplete annotation interfaces and attributes for you (even without a specific
"EJB3" module, since EJB3 annotations are plain JDK 5 annotations).
For more and runnable concrete examples read the JBoss EJB 3.0 tutorial or review the Hibernate Annotations
test suite. Most of the unit tests have been designed to represent a concrete example and be a inspiration source.

2.2.1. Declaring an entity bean


Every bound persistent POJO class is an entity bean and is declared using the @Entity annotation (at the class
level):

@Entity
public class Flight implements Serializable {
Long id;
@Id
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
}

declares the class as an entity bean (i.e. a persistent POJO class), @Id declares the identifier property of
this entity bean. The other mapping declarations are implicit. This configuration by exception concept is central
to the new EJB3 specification and a major improvement. The class Flight is mapped to the Flight table, using
the column id as its primary key column.
@Entity

Depending on whether you annotate fields or methods, the access type used by Hibernate will be field or
property. The EJB3 spec requires that you declare annotations on the element type that will be accessed, i.e.
the getter method if you use property access, the field if you use field access. Mixing EJB3 annotations in
both fields and methods should be avoided. Hibernate will guess the access type from the position of @Id or
@EmbeddedId.
Defining the table

Hibernate 3.1 beta 9

Entity Beans

is set at the class level; it allows you to define the table, catalog, and schema names for your entity bean
mapping. If no @Table is defined the default values are used: the unqualified class name of the entity.
@Table

@Entity
@Table(name="tbl_sky")
public class Sky implements Serializable {
...

The @Table element also contains a schema and a catalog attributes, if they need to be defined. You can also
define unique constraints to the table using the @UniqueConstraint annotation in conjunction with @Table (for
a unique constraint bound to a single column, refer to @Column).
@Table(name="tbl_sky",
uniqueConstraints = {@UniqueConstraint(columnNames={"month", "day"})}
)

A unique constraint is applied to the tuple month, day. Note that the columnNames array refers to the logical
column names.
The logical column name is defined by the Hibernate NamingStrategy implementation. The default EJB3 naming strategy use the physical column name as the logical column name. Note that this may be different than the
property name (if the column name is explicit). Unless you override the NamingStrategy, you shouldn't worry
about that.
Versioning for optimistic locking
You can add optimistic locking capability to an entity bean using the @Version annotation:

@Entity
public class Flight implements Serializable {
...
@Version
@Column(name="OPTLOCK")
public Integer getVersion() { ... }
}

The version property will be mapped to the OPTLOCK column, and the entity manager will use it to detect conflicting updates (preventing lost updates you might otherwise see with the last-commit-wins strategy).
The version column may be a numeric (the recommended solution) or a timestamp as per the EJB3 spec. Hibernate support any kind of type provided that you define and implement the appropriate UserVersionType.

2.2.2. Mapping simple properties


Declaring basic property mappings
Every non static non transient property (field or method) of an entity bean is considered persistent, unless you
annotate it as @Transient. Not having an annotation for your property is equivalent to the appropriate @Basic
annotation. The @Basic annotation allows you to declare the fetching strategy for a property:
public transient int counter; //transient property
private String firstname; //persistent property
@Transient
String getLengthInMeter() { ... } //transient property

Hibernate 3.1 beta 9

Entity Beans

String getName() {... } // persistent property


@Basic
int getLength() { ... } // persistent property
@Basic(fetch = FetchType.LAZY)
String getDetailedComment() { ... } // persistent property
@Temporal(TemporalType.TIME)
java.util.Date getDepartureTime() { ... } // persistent property
@Enumerated(STRING)
Starred getNote() { ... } //enum persisted as String in database
counter,

a transient field, and lengthInMeter, a method annotated as @Transient, and will be ignored by the
entity manager. name, length, and firstname properties are mapped persistent and eagerly fetched (the default
for simple properties). The detailedComment property value will be lazily fetched from the database once a
lazy property of the entity is accessed for the first time. Usually you don't need to lazy simple properties (not to
be confused with lazy association fetching).

Note
To enable property level lazy fetching, your classes have to be instrumented: bytecode is added to the
original one to enable such feature, please refer to the Hibernate reference documentation. If your
classes are not instrumented, property level lazy loading is silently ignored.
The recommended alternative is to use the projection capability of EJB-QL or Criteria queries.
EJB3 support property mapping of all basic types supported by Hibernate (all basic Java types , their respective
wrappers and serializable classes). Hibernate Annotations support out of the box Enum type mapping either into a ordinal column (saving the enum ordinal) or a string based column (saving the enum string representation):
the persistence representation, defaulted to ordinal, can be overriden through the @Enumerated annotation as
shown in the note property example.
In core Java APIs, the temporal precision is not defined. When dealing with temporal data you might want to
describe the expected precision in database. Temporal data can have DATE, TIME, or TIMESTAMP precision (ie the
actual date, only the time, or both). Use the @Temporal annotation to fine tune that.
indicates that the property should be persisted in a Blob or a Clob depending on the property type:
java.sql.Clob, Character[], char[] and java.lang.String will be persisted in a Clob. java.sql.Blob,
Byte[], byte[] and serializable type will be persisted in a Blob.
@Lob

@Lob
public String getFullText() {
return fullText;
}
@Lob
public byte[] getFullCode() {
return fullCode;
}

If the property type implements java.io.Serializable and is not a basic type, and if the property is not annotated with @Lob, then the Hibernate serializable type is used.
Declaring column attributes
Hibernate 3.1 beta 9

Entity Beans

The column(s) used for a property mapping can be defined using the @Column annotation. Use it to override default values (see the EJB3 specification for more information on the defaults). You can use this annotation at
the property level for properties that are:

not annotated at all

annotated with @Basic

annotated with @Version

annotated with @Lob

annotated with @Temporal

annotated with @org.hibernate.annotations.CollectionOfElements (for Hibernate only)

@Entity
public class Flight implements Serializable {
...
@Column(updatable = false, name = "flight_name", nullable = false, length=50)
public String getName() { ... }

The name property is mapped to the flight_name column, which is not nullable, has a length of 50 and is not
updatable (making the property immutable).
This annotation can be applied to regular properties as well as @Id or @Version properties.
@Column(
name="columnName";
boolean unique() default false;
boolean nullable() default true;
boolean insertable() default true;
boolean updatable() default true;
String columnDefinition() default "";
String table() default "";
int length() default 255;
int precision() default 0; // decimal precision
int scale() default 0; // decimal scale

(optional): the column name (default to the property name)


(optional): set a unique constraint on this column or not (default false)
nullable (optional): set the column as nullable (default false).
insertable (optional): whether or not the column will be part of the insert statement (default true)
updatable (optional): whether or not the column will be part of the update statement (default true)
columnDefinition (optional): override the sql DDL fragment for this particular column (non portable)
table (optional): define the targeted table (default primary table)
length (optional): column length (default 255)
precision (optional): column decimal precision (default 0)
scale (optional): column decimal scale if useful (default 0)

(1)

name

(2)

unique

(3)
(4)
(5)
(6)
(7)
(8)
(8)
(10)

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

Embedded objects (aka components)


It is possible to declare an embedded component inside an entity and even override its column mapping. Component classes have to be annotated at the class level with the @Embeddable annotation. It is possible to override
the column mapping of an embedded object for a particular entity using the @Embedded and

Hibernate 3.1 beta 9

Entity Beans
@AttributeOverride

annotation in the associated property:

@Entity
public class Person implements Serializable {
// Persistent component using defaults
Address homeAddress;
@Embedded
@AttributeOverrides( {
@AttributeOverride(name="iso2", column = @Column(name="bornIso2") ),
@AttributeOverride(name="name", column = @Column(name="bornCountryName") )
} )
Country bornIn;
...
}

@Embeddable
public class Address implements Serializable {
String city;
Country nationality; //no overriding here
}

@Embeddable
public class Country implements Serializable {
private String iso2;
@Column(name="countryName") private String name;
public String getIso2() { return iso2; }
public void setIso2(String iso2) { this.iso2 = iso2; }

public String getName() { return name; }


public void setName(String name) { this.name = name; }
...
}

A embeddable object inherit the access type of its owning entity (note that you can override that using the Hibernate specific @AccessType annotations (see Hibernate Annotation Extensions).
The Person entity bean has two component properties, homeAddress and bornIn. homeAddress property has not
been annotated, but Hibernate will guess that it is a persistent component by looking for the @Embeddable annotation in the Address class. We also override the mapping of a column name (to bornCountryName) with the
@Embedded and @AttributeOverride annotations for each mapped attribute of Country. As you can see, Country is also a nested component of Address, again using auto-detection by Hibernate and EJB3 defaults. Overriding columns of embedded objects of embedded objects is currently not supported in the EJB3 spec, however,
Hibernate Annotations supports it through dotted expressions.

@Embedded
@AttributeOverrides( {
@AttributeOverride(name="city", column = @Column(name="fld_city") )
@AttributeOverride(name="nationality.iso2", column = @Column(name="nat_Iso2") ),
@AttributeOverride(name="nationality.name", column = @Column(name="nat_CountryName") )
//nationality columns in homeAddress are overridden
} )
Address homeAddress;

Hibernate Annotations supports one more feature that is not explicitly supported by the EJB3 specification.

Hibernate 3.1 beta 9

Entity Beans
You can annotate a embedded object with the @MappedSuperclass annotation to make the superclass properties
persistent (see @MappedSuperclass for more informations).
While not supported by the EJB3 specification, Hibernate Annotations allows you to use association annotations in an embeddable object (ie @*ToOne nor @*ToMany). To override the association columns you can use
@AssociationOverride.
If you want to have the same embeddable object type twice in the same entity, the column name defaulting will
not work: at least one of the columns will have to be explicit. Hibernate goes beyond the EJB3 spec and allows
you to enhance the defaulting mechanism through the NamingStrategy. DefaultComponentSafeNamingStrategy is a small improvement over the default EJB3NamingStrategy that allows embedded objects to be defaulted even if used twice in the same entity.
Non-annotated property defaults
If a property is not annotated, the following rules apply:

If the property is of a single type, it is mapped as @Basic

Otherwise, if the type of the property is annotated as @Embeddable, it is mapped as @Embedded

Otherwise, if the type of the property is Serializable, it is mapped as @Basic in a column holding the object
in its serialized version

Otherwise, if the type of the property is java.sql.Clob or java.sql.Blob, it is mapped as @Lob with the appropriate LobType

2.2.. Mapping identifier properties


The @Id annotation lets you define which property is the identifier of your entity bean. This property can be set
by the application itself or be generated by Hibernate (preferred). You can define the identifier generation
strategy thanks to the @GeneratedValue annotation:

AUTO - either identity column, sequence or table depending on the underlying DB

TABLE - table holding the id

IDENTITY - identity column

SEQUENCE - sequence

Hibernate provides more id generators than the basic EJB3 ones. Check Hibernate Annotation Extensions for
more informations.
The following example shows a sequence generator using the SEQ_STORE configuration (see below)

@Id @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="SEQ_STORE")


public Integer getId() { ... }

The next example uses the identity generator:

@Id @GeneratedValue(strategy=GenerationType.IDENTITY)

Hibernate 3.1 beta 9

Entity Beans

public Long getId() { ... }

The AUTO generator is the preferred type for portable applications (across several DB vendors). The identifier
generation configuration can be shared for several @Id mappings with the generator attribute. There are several
configurations available through @SequenceGenerator and @TableGenerator. The scope of a generator can be
the application or the class. Class-defined generators are not visible outside the class and can override application level generators. Application level generators are defined at package level (see package-info.java):

@javax.persistence.TableGenerator(
name="EMP_GEN",
table="GENERATOR_TABLE",
pkColumnName = "key",
valueColumnName = "hi"
pkColumnValue="EMP",
allocationSize=20
)
@javax.persistence.SequenceGenerator(
name="SEQ_GEN",
sequenceName="my_sequence"
)
package org.hibernate.test.metadata;

If package-info.java in the org.hibernate.test.metadata package is used to initialize the EJB configuration, EMP_GEN and SEQ_GEN are application level generators. EMP_GEN defines a table based id generator using
the hilo algorithm with a max_lo of 20. The hi value is kept in a table "GENERATOR_TABLE". The information is
kept in a row where pkColumnName "key" is equals to pkColumnValue "EMP" and column valueColumnName "hi"
contains the the next high value used.
defines a sequence generator using a sequence named my_sequence. Note that this version of Hibernate Annotations does not handle initialValue and allocationSize parameters in the sequence generator.
SEQ_GEN

The next example shows the definition of a sequence generator in a class scope:

@Entity
@javax.persistence.SequenceGenerator(
name="SEQ_STORE",
sequenceName="my_sequence"
)
public class Store implements Serializable {
private Long id;
@Id @GeneratedValue(strategy=GenerationType.SEQUENCE, generator="SEQ_STORE")
public Long getId() { return id; }
}

This class will use a sequence named my_sequence and the SEQ_STORE generator is not visible in other
classes. Note that you can check the Hibernate Annotations tests in the org.hibernate.test.metadata.id package
for more examples.
You can define a composite primary key through several syntaxes:

annotate the component property as @Id and make the component class @Embeddable

annotate the component property as @EmbeddedId

Hibernate 3.1 beta 9

Entity Beans

annotate the class as @IdClass and annotate each property of the entity involved in the primary key with
@Id

While quite common to the EJB2 developer, @IdClass is likely new for Hibernate users. The composite
primary key class corresponds to multiple fields or properties of the entity class, and the names of primary key
fields or properties in the primary key class and those of the entity class must match and their types must be the
same. Let's look at an example:
@Entity
@IdClass(FootballerPk.class)
public class Footballer {
//part of the id key
@Id public String getFirstname() {
return firstname;
}
public void setFirstname(String firstname) {
this.firstname = firstname;
}
//part of the id key
@Id public String getLastname() {
return lastname;
}
public void setLastname(String lastname) {
this.lastname = lastname;
}
public String getClub() {
return club;
}
public void setClub(String club) {
this.club = club;
}
//appropriate equals() and hashCode() implementation
}
@Embeddable
public class FootballerPk implements Serializable {
//same name and type as in Footballer
public String getFirstname() {
return firstname;
}
public void setFirstname(String firstname) {
this.firstname = firstname;
}
//same name and type as in Footballer
public String getLastname() {
return lastname;
}
public void setLastname(String lastname) {
this.lastname = lastname;
}
//appropriate equals() and hashCode() implementation
}

As you may have seen, @IdClass points to the corresponding primary key class.
While not supported by the EJB3 specification, Hibernate allows you to define associations inside a composite

Hibernate 3.1 beta 9

10

Entity Beans

identifier. Simply use the regular annotations for that


@Entity
@AssociationOverride( name="id.channel", joinColumns = @JoinColumn(name="chan_id") )
public class TvMagazin {
@EmbeddedId public TvMagazinPk id;
@Temporal(TemporalType.TIME) Date time;
}
@Embeddable
public class TvMagazinPk implements Serializable {
@ManyToOne
public Channel channel;
public String name;
@ManyToOne
public Presenter presenter;
}

2.2.4. Mapping inheritance


EJB3 supports the three types of inheritance:

Table per Class Strategy: the <union-class> element in Hibernate

Single Table per Class Hierarchy Strategy: the <subclass> element in Hibernate

Joined Subclass Strategy: the <joined-subclass> element in Hibernate

The chosen strategy is declared at the class level of the top level entity in the hierarchy using the @Inheritance
annotation.

Note
Annotating interfaces is currently not supported.
Table per class
This strategy has many drawbacks (esp. with polymorphic queries and associations) explained in the EJB3
spec, the Hibernate reference documentation, Hibernate in Action, and many other places. Hibernate work
around most of them implementing this strategy using SQL UNION queries. It is commonly used for the top level
of an inheritance hierarchy:

@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public class Flight implements Serializable {

This strategy support one to many associations provided that they are bidirectional. This strategy does not support the IDENTITY generator strategy: the id has to be shared across several tables. Consequently, when using
this strategy, you should not use AUTO nor IDENTITY.
Single table per class hierarchy
All properties of all super- and subclasses are mapped into the same table, instances are distinguished by a special discriminator column:

Hibernate 3.1 beta 9

11

Entity Beans

@Entity
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
@DiscriminatorColumn(
name="planetype",
discriminatorType=DiscriminatorType.STRING
)
@DiscriminatorValue("Plane")
public class Plane { ... }
@Entity
@DiscriminatorValue("A320")
public class A320 extends Plane { ... }

is the superclass, it defines the inheritance strategy InheritanceType.SINGLE_TABLE. It also defines the
discriminator column through the @DiscriminatorColumn annotation, a discriminator column can also define
the discriminator type. Finally, the @DiscriminatorValue annotation defines the value used to differentiate a
class in the hierarchy. All of these attributes have sensible default values. The default name of the discriminator
column is DTYPE. The default discriminator value is the entity name (as defined in @Entity.name) for DiscriminatorType.STRING. A320 is a subclass; you only have to define discriminator value if you don't want to use
the default value. The strategy and the discriminator type are implicit.
Plane

@Inheritance

and @DiscriminatorColumn should only be defined at the top of the entity hierarchy.

Joined subclasses
The @PrimaryKeyJoinColumn and @PrimaryKeyJoinColumns annotations define the primary key(s) of the
joined subclass table:

@Entity
@Inheritance(strategy=InheritanceType.JOINED)
public class Boat implements Serializable { ... }
@Entity
public class Ferry extends Boat { ... }
@Entity
@PrimaryKeyJoinColumn(name="BOAT_ID")
public class AmericaCupClass extends Boat { ... }

All of the above entities use the JOINED strategy, the Ferry table is joined with the Boat table using the same
primary key names. The AmericaCupClass table is joined with Boat using the join condition Boat.id = AmericaCupClass.BOAT_ID.
Inherit properties from superclasses
This is sometimes useful to share common properties through a technical or a business superclass without including it as a regular mapped entity (ie no specific table for this entity). For that purpose you can map them as
@MappedSuperclass.
@MappedSuperclass
public class BaseEntity {
@Basic
@Temporal(TemporalType.TIMESTAMP)
public Date getLastUpdate() { ... }
public String getLastUpdater() { ... }
...
}

Hibernate 3.1 beta 9

12

Entity Beans

@Entity class Order extends BaseEntity {


@Id public Integer getId() { ... }
...
}

In database, this hierarchy will be represented as an Order table having the id, lastUpdate and lastUpdater
columns. The embedded superclass property mappings are copied into their entity subclasses. Remember that
the embeddable superclass is not the root of the hierarchy though.

Note
Properties from superclasses not mapped as @MappedSuperclass are ignored.

Note
The access type (field or methods), is inherited from the root entity, unless you use the Hibernate annotation @AccessType

Note
The same notion can be applied to @Embeddable objects to persist properties from their superclasses.
You also need to use @MappedSuperclass to do that (this should not be considered as a standard EJB3
feature though)

Note
It is allowed to mark a class as @MappedSuperclass in the middle of the mapped inheritance hierarchy.

Note
Any class in the hierarchy non annotated with @MappedSuperclass nor @Entity will be ignored.
You can override columns defined in entity superclasses at the root entity level using the @AttributeOverride
annotation.
@MappedSuperclass
public class FlyingObject implements Serializable {
public int getAltitude() {
return altitude;
}
@Transient
public int getMetricAltitude() {
return metricAltitude;
}
@ManyToOne
public PropulsionType getPropulsion() {
return metricAltitude;
}
...
}
@Entity
@AttributeOverride( name="altitude", column = @Column(name="fld_altitude") )
@AssociationOverride( name="propulsion", joinColumns = @JoinColumn(name="fld_propulsion_fk") )
public class Plane extends FlyingObject {
...
}

Hibernate 3.1 beta 9

13

Entity Beans

The altitude property will be persisted in an fld_altitude column of table Plane and the propulsion association will be materialized in a fld_propulsion_fk foreign key column.
You

can

define

@AttributeOverride(s)

and @AssociationOverride(s)
@MappedSuperclass classes and properties pointing to an @Embeddable object.

on

@Entity

classes,

2.2.5. Mapping entity bean associations/relationships


One-to-one
You can associate entity beans through a one-to-one relationship using @OneToOne. There are two cases for oneto-one associations: either the associated entities share the same primary keys values or a foreign key is held by
one of the entities (note that this FK column in the database should be constrained unique to simulate oneto-one multiplicity).
First, we map a real one-to-one association using shared primary keys:

@Entity
public class Body {
@Id
public Long getId() { return id; }
@OneToOne(cascade = CascadeType.ALL)
@PrimaryKeyJoinColumn
public Heart getHeart() {
return heart;
}
...
}

@Entity
public class Heart {
@Id
public Long getId() { ...}
}

The one to one is marked as true by using the @PrimaryKeyJoinColumn annotation.


In the following example, the associated entities are linked through a foreign key column:

@Entity
public class Customer implements Serializable {
@OneToOne(cascade = CascadeType.ALL)
@JoinColumn(name="passport_fk")
public Passport getPassport() {
...
}
@Entity
public class Passport implements Serializable {
@OneToOne(mappedBy = "passport")
public Customer getOwner() {
...
}

Hibernate 3.1 beta 9

14

Entity Beans

A Customer is linked to a Passport, with a foreign key column named passport_fk in the Customer table. The
join column is declared with the @JoinColumn annotation which looks like the @Column annotation. It has one
more parameters named referencedColumnName. This parameter declares the column in the targeted entity that
will be used to the join. Note that when using referencedColumnName to a non primary key column, the associated
class has to be Serializable. Also note that the referencedColumnName to a non primary key column has to be
mapped to a property having a single column (other cases might not work).
The association may be bidirectional. In a bidirectional relationship, one of the sides (and only one) has to be
the owner: the owner is responsible for the association column(s) update. To declare a side as not responsible
for the relationship, the attribute mappedBy is used. mappedBy refers to the property name of the association on
the owner side. In our case, this is passport. As you can see, you don't have to (must not) declare the join
column since it has already been declared on the owners side.
If no @JoinColumn is declared on the owner side, the defaults apply. A join column(s) will be created in the
owner table and its name will be the concatenation of the name of the relationship in the owner side, _
(underscore), and the name of the primary key column(s) in the owned side. In this example passport_id because the property name is passport and the column id of Passport is id.
Many-to-one
Many-to-one associations are declared at the property level with the annotation @ManyToOne:

@Entity()
public class Flight implements Serializable {
@ManyToOne( cascade = {CascadeType.PERSIST, CascadeType.MERGE} )
@JoinColumn(name="COMP_ID")
public Company getCompany() {
return company;
}
...
}

The @JoinColumn attribute is optional, the default value(s) is like in one to one, the concatenation of the name
of the relationship in the owner side, _ (underscore), and the name of the primary key column in the owned
side. In this example company_id because the property name is company and the column id of Company is id.
has a parameter named targetEntity which describes the target entity name. You usually don't
need this parameter since the default value (the type of the property that stores the association) is good in almost all cases. However this is useful when you want to use interfaces as the return type instead of the regular
entity.
@ManyToOne

@Entity()
public class Flight implements Serializable {
@ManyToOne( cascade = {CascadeType.PERSIST, CascadeType.MERGE}, targetEntity=CompanyImpl.class )
@JoinColumn(name="COMP_ID")
public Company getCompany() {
return company;
}
...
}
public interface Company {
...

Collections
Hibernate 3.1 beta 9

15

Entity Beans

Overview
You can map Collection, List (ie ordered lists, not indexed lists), Map and Set. The EJB3 specification describes how to map an ordered list (ie a list ordered at load time) using @javax.persistence.OrderBy annotation: this annotation takes into parameter a list of comma separated (target entity) properties to order the collection by (eg firstname asc, age desc), if the string is empty, the collection will be ordered by id. @OrderBy
currently works only on collections having no association table. For true indexed collections, please refer to the
Hibernate Annotation Extensions. EJB3 allows you to map Maps using as a key one of the target entity property using @MapKey(name="myProperty") (myProperty is a property name in the target entity). When using
@MapKey (without property name), the target entity primary key is used. The map key uses the same column as
the property pointed out: there is no additional column defined to hold the map key, and it does make sense
since the map key actually represent a target ptoperty. Be aware that once loaded, the key is no longer kept in
sync with the property, in other words, if you change the property value, the key will not change automatically
in your Java model (Map support the way Hibernate 3 does is currently not supported in this release). Many
people confuse <map> capabilities and @MapKey ones. These are two different features. @MapKey still has some
limitations, please check the forum or the JIRA tracking system for more informations.
Hibernate has several notions of collections.

Table 2.1. Collections semantics


Semantic

java representation

annotations

Bag semantic

java.util.List, java.util.Collection

@org.hibernate.annotations.Collec
tionOfElements, @OneToMany,
@ManyToMany

List semantic

java.util.List

@org.hibernate.annotations.Collec
tionOfElements, @OneToMany,
@ManyToMany + @OrderBy,
@org.hibernate.annotations.Index
Column

Set semantic

java.util.Set

@org.hibernate.annotations.Collec
tionOfElements, @OneToMany,
@ManyToMany

Map semantic

java.util.Map

@org.hibernate.annotations.Collec
tionOfElements, @OneToMany,
@ManyToMany + @MapKey

So specifically, java.util.List collections wo @OrderBy nor @org.hibernate.annotations.IndexColumn are going to be considered as bags.
Collection of primitive, core type or embedded objects is not supported by the EJB3 specification. Hibernate
Annotations allows them however (see Hibernate Annotation Extensions).
@Entity public class City {
@OneToMany(mappedBy="city")
@OrderBy("streetName")
public List<Street> getStreets() {
return streets;
}
...
}

Hibernate 3.1 beta 9

16

Entity Beans
@Entity public class Street {
public String getStreetName() {
return streetName;
}
@ManyToOne
public City getCity() {
return city;
}
...
}

@Entity
public class Software {
@OneToMany(mappedBy="software")
@MapKey(name="codeName")
public Map<String, Version> getVersions() {
return versions;
}
...
}
@Entity
@Table(name="tbl_version")
public class Version {
public String getCodeName() {...}
@ManyToOne
public Software getSoftware() { ... }
...
}

So City has a collection of Streets that are ordered by streetName (of Street) when the collection is loaded.
Software has a map of Versions which key is the Version codeName.
Unless the collection is a generic, you will have to define targetEntity. This is a annotation attribute that take
the target entity class as a value.

One-to-many
One-to-many associations are declared at the property level with the annotation @OneToMany. One to many associations may be bidirectional.
Bidirectional
Since many to one are (almost) always the owner side of a bidirectional relationship in the EJB3 spec, the one
to many association is annotated by @OneToMany( mappedBy=... )
@Entity
public class Troop {
@OneToMany(mappedBy="troop")
public Set<Soldier> getSoldiers() {
...
}
@Entity
public class Soldier {
@ManyToOne
@JoinColumn(name="troop_fk")
public Troop getTroop() {
...
}

Troop

has a bidirectional one to many relationship with Soldier through the troop property. You don't have to

Hibernate 3.1 beta 9

17

Entity Beans
(must not) define any physical mapping in the mappedBy side.
To map a bidirectional one to many, with the one-to-many side as the owning side, you have to remove the
mappedBy element and set the many to one @JoinColumn as insertable and updatable to false. This solution is
obviously not optimized from the number of needed statements.
@Entity
public class Troop {
@OneToMany
@JoinColumn(name="troop_fk") //we need to duplicate the physical information
public Set<Soldier> getSoldiers() {
...
}
@Entity
public class Soldier {
@ManyToOne
@JoinColumn(name="troop_fk", insertable=false, updatable=false)
public Troop getTroop() {
...
}

Unidirectional
A unidirectional one to many using a foreign key column in the owned entity is not that common and not really
recommended. We strongly advise you to use a join table for this kind of association (as explained in the next
section). This kind of association is described through a @JoinColumn

@Entity
public class Customer implements Serializable {
@OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER)
@JoinColumn(name="CUST_ID")
public Set<Ticket> getTickets() {
...
}
@Entity
public class Ticket implements Serializable {
... //no bidir
}

Customer

describes a unidirectional relationship with Ticket using the join column CUST_ID.

Unidirectional with join table


A unidirectional one to many with join table is much preferred. This association is described through an
@JoinTable.

@Entity
public class Trainer {
@OneToMany
@JoinTable(
name="TrainedMonkeys",
joinColumns = { @JoinColumn( name="trainer_id") },
inverseJoinColumns = @JoinColumn( name="monkey_id")
)
public Set<Monkey> getTrainedMonkeys() {
...
}
@Entity
public class Monkey {
... //no bidir

Hibernate 3.1 beta 9

18

Entity Beans

describes a unidirectional relationship with Monkey using the join table TrainedMonkeys, with a foreign key trainer_id to Trainer (joinColumns) and a foreign key monkey_id to Monkey
(inversejoinColumns).
Trainer

Defaults
Without describing any physical mapping, a unidirectional one to many with join table is used. The table name
is the concatenation of the owner table name, _, and the other side table name. The foreign key name(s) referencing the owner table is the concatenation of the owner table, _, and the owner primary key column(s) name.
The foreign key name(s) referencing the other side is the concatenation of the owner property name, _, and the
other side primary key column(s) name. A unique constraint is added to the foreign key referencing the other
side table to reflect the one to many.

@Entity
public class Trainer {
@OneToMany
public Set<Tiger> getTrainedTigers() {
...
}
@Entity
public class Tiger {
... //no bidir
}

describes a unidirectional relationship with Tiger using the join table Trainer_Tiger, with a foreign
key trainer_id to Trainer (table name, _, trainer id) and a foreign key trainedTigers_id to Monkey (property
name, _, Tiger primary column).
Trainer

Many-to-many
Definition
A many-to-many association is defined logically using the @ManyToMany annotation. You also have to describe
the association table and the join conditions using the @JoinTable annotation. If the association is bidirectional,
one side has to be the owner and one side has to be the inverse end (ie. it will be ignored when updating the relationship values in the association table):

@Entity
public class Employer implements Serializable {
@ManyToMany(
targetEntity=org.hibernate.test.metadata.manytomany.Employee.class,
cascade={CascadeType.PERSIST, CascadeType.MERGE}
)
@JoinTable(
name="EMPLOYER_EMPLOYEE",
joinColumns={@JoinColumn(name="EMPER_ID")},
inverseJoinColumns={@JoinColumn(name="EMPEE_ID")}
)
public Collection getEmployees() {
return employees;
}
...
}

Hibernate 3.1 beta 9

19

Entity Beans

@Entity
public class Employee implements Serializable {
@ManyToMany(
cascade={CascadeType.PERSIST, CascadeType.MERGE},
mappedBy="employees"
targetEntity=Employer.class
)
public Collection getEmployers() {
return employers;
}
}

We've already shown the many declarations and the detailed attributes for associations. We'll go deeper in the
@JoinTable description, it defines a name, an array of join columns (an array in annotation is defined using { A,
B, C }), and an array of inverse join columns. The latter ones are the columns of the association table which
refer to the Employee primary key (the "other side").
As seen previously, the other side don't have to (must not) describe the physical mapping: a simple mappedBy
argument containing the owner side property name bind the two.
Default values
As any other annotations, most values are guessed in a many to many relationship. Without describing any
physical mapping in a unidirectional many to many the following rules applied. The table name is the concatenation of the owner table name, _ and the other side table name. The foreign key name(s) referencing the owner
table is the concatenation of the owner table name, _ and the owner primary key column(s). The foreign key
name(s) referencing the other side is the concatenation of the owner property name, _, and the other side
primary key column(s). These are the same rules used for a unidirectional one to many relationship.

@Entity
public class Store {
@ManyToMany(cascade = CascadeType.PERSIST)
public Set<City> getImplantedIn() {
...
}
}
@Entity
public class City {
... //no bidirectional relationship
}

A Store_Table is used as the join table. The Store_id column is a foreign key to the Store table. The implantedIn_id column is a foreign key to the City table.
Without describing any physical mapping in a bidirectional many to many the following rules applied. The table name is the concatenation of the owner table name, _ and the other side table name. The foreign key
name(s) referencing the owner table is the concatenation of the other side property name, _, and the owner
primary key column(s). The foreign key name(s) referencing the other side is the concatenation of the owner
property name, _, and the other side primary key column(s). These are the same rules used for a unidirectional
one to many relationship.

@Entity
public class Store {
@ManyToMany(cascade = {CascadeType.PERSIST, CascadeType.MERGE})
public Set<Customer> getCustomers() {

Hibernate 3.1 beta 9

20

Entity Beans

...
}
}
@Entity
public class Customer {
@ManyToMany(mappedBy="customers")
public Set<Store> getStores() {
...
}
}

A Store_Customer is used as the join table. The stores_id column is a foreign key to the Store table. The
customers_id column is a foreign key to the City table.
Transitive persistence with cascading
You probably have noticed the cascade attribute taking an array of CascadeType as a value. The cascade
concept in EJB3 is very is similar to the transitive persistence and cascading of operations in Hibernate, but
with slightly different semantics and cascading types:

CascadeType.PERSIST: cascades the persist (create) operation to associated entities persist() is called or if
the entity is managed

CascadeType.MERGE: cascades the merge operation to associated entities if merge() is called or if the entity is managed

CascadeType.REMOVE: cascades the remove operation to associated entities if delete() is called

CascadeType.REFRESH: cascades the refresh operation to associated entities if refresh() is called

CascadeType.ALL: all of the above

Please refer to the chapter 6.3 of the EJB3 specification for more information on cascading and create/merge
semantics.
Association fetching
You have the ability to either eagerly or lazily fetch associated entities. The fetch parameter can be set to
FetchType.LAZY or FetchType.EAGER. EAGER will try to use an outer join select to retrieve the associated object, while LAZY is the default and will only trigger a select when the associated object is accessed for the first
time. EJBQL also has a fetch keyword that allows you to override laziness when doing a particular query. This
is very useful to improve performance and is decided on a use case to use case basis.

2.2.6. Mapping composite primary and foreign keys


Composite primary keys use a embedded class as the primary key representation, so you'd use the @Id and
@Embeddable annotations. Alternatively, you can use the @EmbeddedId annotation. Note that the dependent class
has to be serializable and implements equals()/hashCode(). You can also use @IdClass as described in Mapping identifier properties.

@Entity
public class RegionalArticle implements Serializable {
@Id

Hibernate 3.1 beta 9

21

Entity Beans

public RegionalArticlePk getPk() { ... }


}
@Embeddable
public class RegionalArticlePk implements Serializable { ... }

or alternatively

@Entity
public class RegionalArticle implements Serializable {
@EmbeddedId
public RegionalArticlePk getPk() { ... }
}
public class RegionalArticlePk implements Serializable { ... }

inherit the access type of its owning entity unless the Hibernate specific annotation @AccessType
is used. Composite foreign keys (if not using the default sensitive values) are defined on associations using the
@JoinColumns element, which is basically an array of @JoinColumn. It is considered a good practice to express
referencedColumnNames explicitly. Otherwise, Hibernate will suppose that you use the same order of columns
as in the primary key declaration.
@Embeddable

@Entity
public class Parent implements Serializable {
@Id
public ParentPk id;
public int age;
@OneToMany(cascade=CascadeType.ALL)
@JoinColumns ({
@JoinColumn(name="parentCivility", referencedColumnName = "isMale"),
@JoinColumn(name="parentLastName", referencedColumnName = "lastName"),
@JoinColumn(name="parentFirstName", referencedColumnName = "firstName")
})
public Set<Child> children; //unidirectional
...
}

@Entity
public class Child implements Serializable {
@Id @GeneratedValue
public Integer id;
@ManyToOne
@JoinColumns ({
@JoinColumn(name="parentCivility", referencedColumnName = "isMale"),
@JoinColumn(name="parentLastName", referencedColumnName = "lastName"),
@JoinColumn(name="parentFirstName", referencedColumnName = "firstName")
})
public Parent parent; //unidirectional
}

@Embeddable
public class ParentPk implements Serializable {
String firstName;
String lastName;
...

Hibernate 3.1 beta 9

22

Entity Beans

Note the explicit usage of the referencedColumnName.

2.2.7. Mapping secondary tables


You can map a single entity bean to several tables using the @SecondaryTable or @SecondaryTables class level
annotations. To express that a column is in a particular table, use the table parameter of @Column or
@JoinColumn.

@Entity
@Table(name="MainCat")
@SecondaryTables({
@SecondaryTable(name="Cat1", pkJoinColumns={
@PrimaryKeyJoinColumn(name="cat_id", referencedColumnName="id")
),
@SecondaryTable(name="Cat2", uniqueConstraints={@UniqueConstraint(columnNames={"storyPart2"})})
})
public class Cat implements Serializable {
private
private
private
private

Integer id;
String name;
String storyPart1;
String storyPart2;

@Id @GeneratedValue
public Integer getId() {
return id;
}
public String getName() {
return name;
}
@Column(table="Cat1")
public String getStoryPart1() {
return storyPart1;
}
@Column(table="Cat2")
public String getStoryPart2() {
return storyPart2;
}

In this example, name will be in MainCat. storyPart1 will be in Cat1 and storyPart2 will be in Cat2. Cat1
will be joined to MainCat using the cat_id as a foreign key, and Cat2 using id (ie the same column name, the
MainCat id column has). Plus a unique constraint on storyPart2 has been set.
Check out the JBoss EJB 3 tutorial or the Hibernate Annotations unit test suite for more examples.

2.3. Mapping Queries


2.3.1. Mapping EJBQL/HQL queries
You can map EJBQL/HQL queries using annotations. @NamedQuery and @NamedQueries can be defined at the
class or at the package level. However their definitions are global to the session factory/entity manager factory
scope. A named query is defined by its name and the actual query string.
Hibernate 3.1 beta 9

23

Entity Beans

javax.persistence.NamedQueries(
@javax.persistence.NamedQuery(name="plane.getAll", query="select p from Plane p")
)
package org.hibernate.test.annotations.query;
...
@Entity
@NamedQuery(name="night.moreRecentThan", query="select n from Night n where n.date >= :date")
public class Night {
...
}
public class MyDao {
doStuff() {
Query q = s.getNamedQuery("night.moreRecentThan");
q.setDate( "date", aMonthAgo );
List results = q.list();
...
}
...
}

You can also provide some hints to a query through an array of QueryHint through a hints attribute.
The availabe Hibernate hints are

Table 2.2. Query hints


hint

description

org.hibernate.cacheable

Whether the query should interact with the second


level cache (defualt to false)

org.hibernate.cacheRegion

Cache region name (default used otherwise)

org.hibernate.timeout

Query timeout

org.hibernate.fetchSize

resultset fetch size

org.hibernate.flushMode

Flush mode used for this query

org.hibernate.cacheMode

Cache mode used for this query

org.hibernate.readOnly

Entities loaded by this query should be in read only


mode or not (default to false)

org.hibernate.comment

Query comment added to the generated SQL

2.3.2. Mapping native queries


You can also map a native query (ie a plain SQL query). To achieve that, you need to describe the SQL resultset structure using @SqlResultSetMapping (or @SqlResultSetMappings if you plan to define several resulset
mappings). Like @NamedQuery, a @SqlResultSetMapping can be defined at both package level or class level.
However its scope is global to the application. As we will see, a resultSetMapping parameter is defined the
@NamedNativeQuery, it represents the name of a defined @SqlResultSetMapping. The resultset mapping declares the entities retrieved by this native query. Each field of the entity is bound to an SQL alias (or column
Hibernate 3.1 beta 9

24

Entity Beans
name). All fields of the entity including the ones of subclasses and the foreign key columns of related entities
have to be present in the SQL query. Field definitions are optional provided that they map to the same column
name as the one declared on the class property.

@NamedNativeQuery(name="night&area", query="select night.id nid, night.night_duration, "


+ " night.night_date, area.id aid, night.area_id, area.name "
+ "from Night night, Area area where night.area_id = area.id", resultSetMapping="joinMapping")
@SqlResultSetMapping(name="joinMapping", entities={
@EntityResult(entityClass=org.hibernate.test.annotations.query.Night.class, fields = {
@FieldResult(name="id", column="nid"),
@FieldResult(name="duration", column="night_duration"),
@FieldResult(name="date", column="night_date"),
@FieldResult(name="area", column="area_id"),
discriminatorColumn="disc"
}),
@EntityResult(entityClass=org.hibernate.test.annotations.query.Area.class, fields = {
@FieldResult(name="id", column="aid"),
@FieldResult(name="name", column="name")
})
}
)

In the above example, the night&area named query use the joinMapping result set mapping. This mapping returns 2 entities, Night and Area, each property is declared and associated to a column name, actually the
column name retrieved by the query. Let's now see an implicit declaration of the property / column.

@Entity
@SqlResultSetMapping(name="implicit", entities=@EntityResult(entityClass=org.hibernate.test.annotation
@NamedNativeQuery(name="implicitSample", query="select * from SpaceShip", resultSetMapping="implicit")
public class SpaceShip {
private String name;
private String model;
private double speed;
@Id
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Column(name="model_txt")
public String getModel() {
return model;
}
public void setModel(String model) {
this.model = model;
}
public double getSpeed() {
return speed;
}
public void setSpeed(double speed) {
this.speed = speed;
}
}

In this example, we only describe the entity member of the result set mapping. The property / column mappings
is done using the entity mapping values. In this case the model property is bound to the model_txt column. If
the association to a related entity involve a composite primary key, a @FieldResult element should be used for
each foreign key column. The @FieldResult name is composed of the property name for the relationship, fol-

Hibernate 3.1 beta 9

25

Entity Beans
lowed by a dot ("."), followed by the name or the field or property of the primary key.
@Entity
@SqlResultSetMapping(name="compositekey",
entities=@EntityResult(entityClass=org.hibernate.test.annotations.query.SpaceShip.class,
fields = {
@FieldResult(name="name", column = "name"),
@FieldResult(name="model", column = "model"),
@FieldResult(name="speed", column = "speed"),
@FieldResult(name="captain.firstname", column = "firstn"),
@FieldResult(name="captain.lastname", column = "lastn"),
@FieldResult(name="dimensions.length", column = "length"),
@FieldResult(name="dimensions.width", column = "width")
}),
columns = { @ColumnResult(name = "surface"),
@ColumnResult(name = "volume") } )

@NamedNativeQuery(name="compositekey",
query="select name, model, speed, lname as lastn, fname as firstn, length, width, length * width a
resultSetMapping="compositekey")
} )
public class SpaceShip {
private String name;
private String model;
private double speed;
private Captain captain;
private Dimensions dimensions;
@Id
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@ManyToOne(fetch= FetchType.LAZY)
@JoinColumns( {
@JoinColumn(name="fname", referencedColumnName = "firstname"),
@JoinColumn(name="lname", referencedColumnName = "lastname")
} )
public Captain getCaptain() {
return captain;
}
public void setCaptain(Captain captain) {
this.captain = captain;
}
public String getModel() {
return model;
}
public void setModel(String model) {
this.model = model;
}
public double getSpeed() {
return speed;
}
public void setSpeed(double speed) {
this.speed = speed;
}
public Dimensions getDimensions() {
return dimensions;
}
public void setDimensions(Dimensions dimensions) {
this.dimensions = dimensions;

Hibernate 3.1 beta 9

26

Entity Beans
}
}
@Entity
@IdClass(Identity.class)
public class Captain implements Serializable {
private String firstname;
private String lastname;
@Id
public String getFirstname() {
return firstname;
}
public void setFirstname(String firstname) {
this.firstname = firstname;
}
@Id
public String getLastname() {
return lastname;
}
public void setLastname(String lastname) {
this.lastname = lastname;
}
}

Note
If you look at the dimension property, you'll see that Hibernate supports the dotted notation for embedded objects (you can even have nested embedded objects). EJB3 implementations do not have to support this feature, we do :-)
If you retrieve a single entity and if you use the default mapping, you can use the resultClass attribute instead
of resultSetMapping:
@NamedNativeQuery(name="implicitSample", query="select * from SpaceShip",
resultClass=SpaceShip.class)
public class SpaceShip {

In some of your native queries, you'll have to return scalar values, for example when building report queries.
You can map them in the @SqlResultsetMapping through @ColumnResult. You actually can even mix, entities
and scalar returns in the same native query (this is probably not that common though).

@SqlResultSetMapping(name="scalar", columns=@ColumnResult(name="dimension"))
@NamedNativeQuery(name="scalar", query="select length*width as dimension from SpaceShip", resultSetMap

An other query hint specific to native queries has been introduced: org.hibernate.callable which can be true
or false depending on whether the query is a stored procedure or not.

2.4. Hibernate Annotation Extensions


Hibernate 3.1 offers a variety of additional annotations that you can mix/match with your EJB 3 entities. They
have been designed as a natural extension of EJB3 annotations.
To empower the EJB3 capabilities, hibernate provides specific annotations that match hibernate features. The
org.hibernate.annotations package contains all these annotations extensions.

Hibernate 3.1 beta 9

27

Entity Beans

2.4.1. Entity
You can fine tune some of the actions done by Hibernate on entities beyond what the EJB3 spec offers.
@org.hibernate.annotations.Entity

adds additional metadata that may be needed beyond what is defined in

the standard @Entity

mutable: whether this entity is mutable or not

dynamicInsert: allow dynamic SQL for inserts

dynamicUpdate: allow dynamic SQL for updates

selectBeforeUpdate: Specifies that Hibernate should never perform an SQL UPDATE unless it is certain
that an object is actually modified.

polymorphism: whether the entity polymorphism is of PolymorphismType.IMPLICIT (default) or PolymorphismType.EXPLICIT

persister: allow the overriding of the default persister implementation

optimisticLock: optimistic locking strategy (OptimisticLockType.VERSION, OptimisticLockType.NONE,


OptimisticLockType.DIRTY or OptimisticLockType.ALL)

Note
@javax.persistence.Entity is still mandatory, @org.hibernate.annotations.Entity is not a replacement.
Here are some additional Hibernate annotation extensions
allows you to define the batch size when fetching instances of this
entity ( eg. @BatchSize(size=4) ). When loading a given entity, Hibernate will then load all the uninitialized
entities of the same type in the persistence context up to the batch size.
@org.hibernate.annotations.BatchSize

defines the laziness attributes of the entity. lazy (default to true) define
whether the class is lazy or not. proxyClassName is the interface used to generate the proxy (default is the class
itself).
@org.hibernate.annotations.Proxy

@org.hibernate.annotations.Where

defines an optional SQL WHERE clause used when instances of this

class is retrieved.
@org.hibernate.annotations.Check

defines an optional check constraints defined in the DDL statetement.

@OnDelete(action=OnDeleteAction.CASCADE)

on joined subclasses: use a SQL cascade delete on deletion in-

stead of the regular Hibernate mechanism.


@Table(appliesTo="tableName",

indexes

@Index(name="index1",

columnNames={"column1",

creates the defined indexes on the columns of table tableName. This can be applied on the
primary table or any secondary table. The @Tables annotation allows your to apply indexes on different tables.
This annotation is expected where @javax.persistence.Table or @javax.persistence.SecondaryTable(s)
occurs.
"column2"} ) } )

Note

Hibernate 3.1 beta 9

28

Entity Beans

is
a
complement,
not
a
replacement
to
@javax.persistence.Table. Especially, if you want to change the default name of a table, you must
use @javax.persistence.Table, not @org.hibernate.annotations.Table.
@org.hibernate.annotations.Table

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

@Entity
@Inheritance(
strategy=InheritanceType.JOINED
)
public class Vegetable { ... }
@Entity
@OnDelete(action=OnDeleteAction.CASCADE)
public class Carrot extends Vegetable { ... }

2.4.2. Identifier
@org.hibernate.annotations.GenericGenerator

allows you to define an Hibernate specific id generator.

@Id @GeneratedValue(generator="system-uuid")
@GenericGenerator(name="system-uuid", strategy = "uuid")
public String getId() {
@Id @GeneratedValue(generator="hibseq")
@GenericGenerator(name="hibseq", strategy = "seqhilo",
parameters = {
@Parameter(name="max_lo", value = "5"),
@Parameter(name="sequence", value="heybabyhey")
}
)
public Integer getId() {

is the short name of an Hibernate3 generator strategy or the fully qualified class name of an IdentifierGenerator implementation. You can add some parameters through the parameters attribute
strategy

2.4.3. Property
Access type
The access type is guessed from the position of @Id or @EmbeddedId in the entity hierarchy. Sub-entities, embedded objects and mapped superclass inherit the access type from the root entity.
In Hibernate, you can override the access type to:

use a custom access type strategy

fine tune the access type at the class level or at the property level

Hibernate 3.1 beta 9

29

Entity Beans

An @AccessType annotation has been introduced to support this behavior. You can define the access type on

an entity

a superclass

an embeddable object

a property

The access type is overriden for the annotated element, if overriden on a class, all the properties of the given
class inherit the access type. For root entities, the access type is considered to be the default one for the whole
hierarchy (overridable at class or property level).
If the access type is marked as "property", the getters are scanned for annotations, if the access type is marked
as "field", the fields are scanned for annotations. Otherwise the elements marked with @Id or @embeddedId
are scanned.
You can override an access type for a property, but the element to annotate will not be influenced: for example
an entity having access type field, can annotate a field with @AccessType("property"), the access type will
then be property for this attribute, the the annotations still have to be carried on the field.
If a superclass or an embeddable object is not annotated, the root entity access type is used (even if an access
type has been define on an intermediate superclass or embeddable object). The russian doll principle does not
apply.
@Entity
public class Person implements Serializable {
@Id @GeneratedValue //access type field
Integer id;
@Embedded
@AttributeOverrides({
@AttributeOverride(name = "iso2", column = @Column(name = "bornIso2")),
@AttributeOverride(name = "name", column = @Column(name = "bornCountryName"))
})
Country bornIn;
}
@Embeddable
@AccessType("property") //override access type for all properties in Country
public class Country implements Serializable {
private String iso2;
private String name;
public String getIso2() {
return iso2;
}
public void setIso2(String iso2) {
this.iso2 = iso2;
}
@Column(name = "countryName")
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}

Hibernate 3.1 beta 9

30

Entity Beans

Formula
Sometimes, you want the Database to do some computation for you rather than in the JVM, you might also create some kind of virtual column. You can use a SQL fragment (aka formula) instead of mapping a property into
a column. This kind of property is read only (its value is calculated by your formula fragment).
@Formula("obj_length * obj_height * obj_width")
public long getObjectVolume()

The SQL fragment can be as complex as you want avec even include subselects.
Type
overrides the default hibernate type used: this is generally not necessary
since the type is correctly inferred by Hibernate. Please refer to the Hibernate reference guide for more informations on the Hibernate types.
@org.hibernate.annotations.Type

and @org.hibernate.annotations.TypeDefs allows you to declare


type definitions. These annotations are placed at the class or package level. Note that these definitions will be
global for the session factory (even at the class level) and that type definition has to be defined before any usage.
@org.hibernate.annotations.TypeDef

@TypeDefs(
{
@TypeDef(
name="caster",
typeClass = CasterStringType.class,
parameters = {
@Parameter(name="cast", value="lower")
}
)
}
)
package org.hibernate.test.annotations.entity;
...
public class Forest {
@Type(type="caster")
public String getSmallText() {
...
}

When using composite user type, you will have to express column definitions. The @Columns has been introduced for that purpose.
@Type(type="org.hibernate.test.annotations.entity.MonetaryAmountUserType")
@Columns(columns = {
@Column(name="r_amount"),
@Column(name="r_currency")
})
public MonetaryAmount getAmount() {
return amount;
}

public class MonetaryAmount implements Serializable {


private BigDecimal amount;
private Currency currency;
...
}

Hibernate 3.1 beta 9

31

Entity Beans

Index
You can define an index on a particular column using the @Index annotation on a one column property, the
columnNames attribute will then be ignored
@Column(secondaryTable="Cat1")
@Index(name="story1index")
public String getStoryPart1() {
return storyPart1;
}

2.4.4. Inheritance
SINGLE_TABLE is a very powerful strategy but sometimes, and especially for legacy systems, you cannot add
an additional discriminator column. For that purpose Hibernate has introduced the notion of discriminator formula: @DiscriminatorFormula is a replacement of @DiscriminatorColumn and use a SQL fragment as a formula for discriminator resolution (no need to have a dedicated column).
@Entity
@DiscriminatorForumla("case when forest_type is null then 0 else forest_type end")
public class Forest { ... }

2.4.5. Single Association related annotations


By default, when Hibernate cannot resolve the association because the expected associated element is not in
database (wrong id on the association column), an exception is raised by Hibernate. This might be inconvenient
for lecacy and badly maintained schemas. You can ask Hibernate to ignore such elements instead of raising an
exception using the @NotFound annotation. This annotation can be used on a @OneToOne (with FK), @ManyToOne,
@OneToMany or @ManyToMany association.
@Entity
public class Child {
...
@ManyToOne
@NotFound(action=NotFoundAction.IGNORE)
public Parent getParent() { ... }
...
}

Sometimes you want to delegate to your database the deletion of cascade when a given entity is deleted.
@Entity
public class Child {
...
@ManyToOne
@OnDelete(action=OnDeleteAction.CASCADE)
public Parent getParent() { ... }
...
}

In this case Hibernate generates a cascade delete constraint at the database level.

2.4.6. Collection related annotations


Parameter annotations

Hibernate 3.1 beta 9

32

Entity Beans

It is possible to set

the batch size for collections using @BatchSize

the where clause, using @Where

the check clause, using @Check

the SQL order by clause, using @OrderBy

the delete cascade strategy through @OnDelete(action=OnDeleteAction.CASCADE)

You can also declare a sort comparator. Use the @Sort annotation. Expressing the comparator type you want
between unsorted, natural or custom comparator. If you want to use your own comparator implementation,
you'll also have to express the implementation class using the comparator attribute.
@OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER)
@JoinColumn(name="CUST_ID")
@Sort(type = SortType.COMPARATOR, comparator = TicketComparator.class)
@Where(clause="1=1")
@OnDelete(action=OnDeleteAction.CASCADE)
public SortedSet<Ticket> getTickets() {
return tickets;
}

Please refer to the previous descriptions of these annotations for more informations.
Extra collection types
Beyond EJB3, Hibernate Annotations supports true List and Array. Map your collection the same way as usual
and add the @IndexColumn. This annotation allows you to describe the column that will hold the index. You
can also declare the index value in DB that represent the first element (aka as base index). The usual value is 0
or 1.
@OneToMany(cascade = CascadeType.ALL)
@IndexColumn(name = "drawer_position", base=1)
public List<Drawer> getDrawers() {
return drawers;
}

Note
If you forgot to set @IndexColumn, the bag semantic is applied
Hibernate Annotations also supports collections of core types (Integer, String, Enums, ...), collections of embeddable objects and even arrays of primitive types. This is known as collection of elements.
A collection of elements as to be annotated as @CollectionOfElements (as a replacement of @OneToMany) To
define the collection table, the @JoinTable annotation is used on the association property, joinColumns defines
the join columns between the entity primary table and the collection table (inverseJoincolumn is useless and
should be left empty). For collection of core types or array of primitive types, you can override the element
column definition using a @Column on the association property. You can also override the columns of a collection of embeddable object using @AttributeOverride.
@Entity
public class Boy {
private Integer id;
private Set<String> nickNames = new HashSet<String>();

Hibernate 3.1 beta 9

33

Entity Beans

private int[] favoriteNumbers;


private Set<Toy> favoriteToys = new HashSet<Toy>();
private Set<Character> characters = new HashSet<Character>();
@Id @GeneratedValue
public Integer getId() {
return id;
}
@CollectionOfElements
public Set<String> getNickNames() {
return nickNames;
}
@CollectionOfElements
@JoinTable(
table=@Table(name="BoyFavoriteNumbers"),
joinColumns = @JoinColumn(name="BoyId")
)
@Column(name="favoriteNumber", nullable=false)
@IndexColumn(name="nbr_index")
public int[] getFavoriteNumbers() {
return favoriteNumbers;
}
@CollectionOfElements
@AttributeOverride( name="serial", column=@Column(name="serial_nbr") )
public Set<Toy> getFavoriteToys() {
return favoriteToys;
}
@CollectionOfElements
public Set<Character> getCharacters() {
return characters;
}
...
}
public enum Character {
GENTLE,
NORMAL,
AGGRESSIVE,
ATTENTIVE,
VIOLENT,
CRAFTY
}
@Embeddable
public class Toy {
public String name;
public String serial;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSerial() {
return serial;
}
public void setSerial(String serial) {
this.serial = serial;
}
public boolean equals(Object o) {
if ( this == o ) return true;
if ( o == null || getClass() != o.getClass() ) return false;

Hibernate 3.1 beta 9

34

Entity Beans

final Toy toy = (Toy) o;


if ( !name.equals( toy.name ) ) return false;
if ( !serial.equals( toy.serial ) ) return false;
return true;
}
public int hashCode() {
int result;
result = name.hashCode();
result = 29 * result + serial.hashCode();
return result;
}
}

Note
Previous versions of Hibernate Annotations used the @OneToMany to mark a collection of elements. Due
to semantic inconsistencies, we've introduced the annotation @CollectionOfElements. Marking collections of elements the old way still work but is considered deprecated and is going to be unsupported in
future releases

2.4.7. Cache
In order to optimize your database accesses, you can activave the so called second level cache of Hibernate.
This cache is configurable on a per entity and per collection basis.
defines the caching strategy and region of a given second level cache.
This annotation can be applied on the root entity (not the sub entities), and on the collections.
@org.hibernate.annotations.Cache

@Entity
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public class Forest { ... }

@OneToMany(cascade=CascadeType.ALL, fetch=FetchType.EAGER)
@JoinColumn(name="CUST_ID")
@Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE)
public SortedSet<Ticket> getTickets() {
return tickets;
}

@Cache(
CacheConcurrencyStrategy usage();
String region() default "";
String include() default "all";
)

(1)

(2)
(3)

(1)
(2)
(3)

usage: the given cache concurrency strategy (NONE, READ_ONLY, NONSTRICT_READ_WRITE,


READ_WRITE, TRANSACTIONAL)
region (optional): the cache region (default to the fqcn of the class or the fq role name of the collection)
include (optional): all to include all properties, non-lazy to only include non lazy properties (default all).

2.4.8. Filters
Hibernate has the notion of data filter that can be applied at runtime on a given session. Those filters has to be
defined first.
Hibernate 3.1 beta 9

35

Entity Beans

or @FilterDefs define filter definition(s) used by filter(s) using the


same name. A filter definition has a name() and an array of parameters(). A @ParamDef has a name and a type.
You can also define a defaultCondition() parameter for a given @filterDef to set the default condition to use
when none are defined in the @Filter. A @FilterDef(s) can be defined at the class or package level.
@org.hibernate.annotations.FilterDef

We now need to define the SQL filter clause applied to either the entity load or the collection load. @Filter is
used and placed either on the entity or the collection element

@Entity
@FilterDef(name="minLength", parameters={ @ParamDef( name="minLength", type="integer" ) } )
@Filters( {
@Filter(name="betweenLength", condition=":minLength <= length and :maxLength >= length"),
@Filter(name="minLength", condition=":minLength <= length")
} )
public class Forest { ... }

2.4.9. Queries
Since Hibernate has more features on named queries than the one defined in the EJB3 specification,
@org.hibernate.annotations.NamedQuery,
@org.hibernate.annotations.NamedQueries,
@org.hibernate.annotations.NamedNativeQuery and @org.hibernate.annotations.NamedNativeQueries
have been introduced. They add some attributes to the standard version and can be used as a replacement:

flushMode: define the query flush mode (Always, Auto, Commit or Never)

cacheable: whether the query should be cached or not

cacheRegion: cache region used if the query is cached

fetchSize: JDBC statement fetch size for this query

timeout: query time out

callable: for native queries only, to be set to true for stored procedures

comment: if comments are activated, the comment seen when the query is sent to the database.

cacheMode: Cache interaction mode (get, ignore, normal, put or refresh)

readOnly: whether or not the elements retrievent from the query are in read only mode.

Note, that the EJB3 public final draft has introduced the notion of @QueryHint, which is probably a better way
to define those hints.

Hibernate 3.1 beta 9

36

Chapter 3. Hibernate Validator


Annotations are a very convenient and elegant way to specify invariant constraints for a domain model. You
can, for example, express that a property should never be null, that the account balance should be strictly positive, etc. These domain model constraints are declared in the bean itself by annotating its properties. A validator
can then read them and check for constraint violations. The validation mechanism can be executed in different
layers in your application without having to duplicate any of these rules (presentation layer, data access layer).
Hibernate Validator has been designed for that purpose.
Hibernate Validator works at two levels. First, it is able to check in-memory instances of a class for constraint
violations. Second, it can apply the constraints to the Hibernate metamodel and incorporate them into the generated database schema.
Each constraint annotation is associated to a validator implementation responsible for checking the constraint
on the entity instance. A validator can also (optionally) apply the constraint to the Hibernate metamodel, allowing Hibernate to generate DDL that expresses the constraint. With the appropriate event listener, you can execute the checking operation on inserts and updates done by Hibernate. Hibernate Validator is not limited to use
with Hibernate. You can easily use it anywhere in your application.
When checking instances at runtime, Hibernate Validator returns information about constraint violations in an
array of InvalidValues. Among other information, the InvalidValue contains an error description message
that can embed the parameter values bundle with the annotation (eg. length limit), and message strings that may
be externalized to a ResourceBundle.

3.1. Constraints
3.1.1. What is a constraint?
A constraint is represented by an annotation. A constraint usually has some attributes used to parameterize the
constraints limits. The constraint apply to the annotated element.

3.1.2. Built in constraints


Hibernate Validator comes with some built-in constraints, which covers most basic data checks. As we'll see
later, you're not limited to them, you can in a minute write your own constraints.
Table 3.1. Built-in constraints
Annotation
@Length(min=, max=)

Apply on

Runtime checking

Hibernate Metadata impact

property (String)

check if the string length Column length will be set


match the range
to max

@Max(value=)

property (numeric or check if the value is less Add a check constraint on


string representation of a than or equals to max
the column
numeric)

@Min(value=)

property (numeric or check if the value is more Add a check constraint on


string representation of a than or equals to min
the column
numeric)

Hibernate 3.1 beta 9

37

Hibernate Validator
Annotation

Apply on

Runtime checking

@NotNull

property

check if the value is not Column(s) are not null


null

@Past
@Future

Hibernate Metadata impact

property (date or calen- check if the date is in the Add a check constraint on
dar)
past
the column
property (date or calen- check if the date is in the none
dar)
future

@Pattern(regex="regexp" property (string)


, flag=)

check if the property none


match the regular expression given a match flag
(see
java.util.regex.Patte
rn

@Range(min=, max=)

@Size(min=, max=)

property (numeric or check if the value is Add a check constraint on


string representation of a between min and max the column
numeric)
(included)
property (array, collec- check if the element size none
tion, map)
is between min and max
(included)

@AssertFalse

property

check that the method none


evaluates to false (useful
for constraints expressed
in code rather than annotations)

@AssertTrue

property

check that the method none


evaluates to true (useful
for constraints expressed
in code rather than annotations)

@Valid

property (object)

perform validation re- none


cursively on the associated object. If the object
is a Collection or an array, the elements are validated recursively. If the
object is a Map, the value
elements are validated recursively.

@Email

property (String)

check whether the string none


is conform to the email
address specification

3.1.3. Error messages

Hibernate 3.1 beta 9

38

Hibernate Validator

Hibernate Validator comes with a default set of error messages translated in a few languages (if yours is not
part of it, please sent us a patch). You can override those messages by creating a ValidatorMessages.properties
or
(ValidatorMessages_loc.properties)
out
of
org.hibernate.validator.resources.DefaultValidatorMessages.properties and change the appropriate
keys. You can even add your own additional set of messages while writing your validator annotations.
Alternatively you can provide a ResourceBundle while checking programmatically the validation rules on a
bean.

3.1.4. Writing your own constraints


Extending the set of built-in constraints is extremely easy. Any constraint consists of two pieces: the constraint
descriptor (the annotation) and the constraint validator (the implementation class). Here is a simple userdefined descriptor:
@ValidatorClass(CapitalizedValidator.class)
@Target(METHOD)
@Retention(RUNTIME)
@Documented
public @interface Capitalized {
CapitalizeType type() default Capitalize.FIRST;
String message() default "has incorrect capitalization";
}

is a parameter describing how the property should to be capitalized. This is a user parameter fully dependant on the annotation business.
type

is the default string used to describe the constraint violation and is mandatory. You can hard code the
string or you can externalize part/all of it through the Java ResourceBundle mechanism. Parameters values are
going to be injected inside the message when the {parameter} string is found (in our example Capitalization
is not {type} would generate Capitalization is not FIRST), externalizing the whole string in ValidatorMessages.properties is considered good practice. See Error messages.
message

@ValidatorClass(CapitalizedValidator.class)
@Target(METHOD)
@Retention(RUNTIME)
@Documented
public @interface Capitalized {
CapitalizeType type() default Capitalize.FIRST;
String message() default "{validator.capitalized}";
}
...
#in ValidatorMessages.properties
validator.capitalized=Capitalization

is not {type}

As you can see the {} notation is recursive.


To link a descriptor to its validator implementation, we use the @ValidatorClass meta-annotation. The validator class parameter must name a class which implements Validator<ConstraintAnnotation>.
We now have to implement the validator (ie. the rule checking implementation). A validation implementation
can check the value of the a property (by implementing PropertyConstraint) and/or can modify the hibernate
mapping metadata to express the constraint at the database level (by implementing PersistentClassConstraint).
public class CapitalizedValidator
implements Validator<Capitalized>, PropertyConstraint {

Hibernate 3.1 beta 9

39

Hibernate Validator

private CapitalizeType type;


//part of the Validator<Annotation> contract,
//allows to get and use the annotation values
public void initialize(Capitalized parameters) {
type = parameters.type();
}
//part of the property constraint contract
public boolean isValid(Object value) {
if (value==null) return true;
if ( !(value instanceof String) ) return false;
String string = (String) value;
if (type == CapitalizeType.ALL) {
return string.equals( string.toUpperCase() );
}
else {
String first = string.substring(0,1);
return first.equals( first.toUpperCase();
}
}
}

The isValid() method should return false if the constraint has been violated. For more examples, refer to the
built-in validator implementations.
We only have seen property level validation, but you can write a Bean level validation annotation. Instead of
receiving the return instance of a property, the bean itself will be passed to the validator. To activate the validation checking, just annotated the bean itself instead. A small sample can be found in the unit test suite.

3.1.5. Annotating your domain model


Since you are already familiar with annotations now, the syntax should be very familiar.
public class Address {
private String line1;
private String line2;
private String zip;
private String state;
private String country;
private long id;
// a not null string of 20 characters maximum
@Length(max=20)
@NotNull
public String getCountry() {
return country;
}
// a non null string
@NotNull
public String getLine1() {
return line1;
}
//no constraint
public String getLine2() {
return line2;
}
// a not null string of 3 characters maximum
@Length(max=3) @NotNull
public String getState() {
return state;
}

Hibernate 3.1 beta 9

40

Hibernate Validator

// a not null numeric string of 5 characters maximum


// if the string is longer, the message will
//be searched in the resource bundle at key 'long'
@Length(max=5, message="{long}")
@Pattern(regex="[0-9]+")
@NotNull
public String getZip() {
return zip;
}
// should always be true
@AssertTrue
public boolean isValid() {
return true;
}
// a numeric between 1 and 2000
@Id @Min(1)
@Range(max=2000)
public long getId() {
return id;
}
}

While the example only shows public property validation, you can also annotate fields of any kind of visibility.
@MyBeanConstraint(max=45)
public class Dog {
@AssertTrue private boolean isMale;
@NotNull protected String getName() { ... };
...
}

You can also annotate interfaces. Hibernate Validator will check all superclasses and interfaces extended or implemented by a given bean to read the appropriate validator annotations.
public interface Named {
@NotNull String getName();
...
}
public class Dog implements Named {
@AssertTrue private boolean isMale;
public String getName() { ... };
}

The name property will be checked for nullity when the Dog bean is validated.

3.2. Using the Validator framework


Hibernate Validator is intended to be used to implement multi-layered data validation, where we express constraints in one place (the annotated domain model) and apply them at various different layers of the application.

3.2.1. Database schema-level validation


Out of the box, Hibernate Annotations will translate the constraints you have defined for your entities into mapping metadata. For example, if a property of your entity is annotated @NotNull, its columns will be declared as
not null in the DDL schema generated by Hibernate.
Hibernate 3.1 beta 9

41

Hibernate Validator

3.2.2. Hibernate event-based validation


Hibernate Validator has two built-in Hibernate event listeners. Whenever a PreInsertEvent or PreUpdateEvent occurs, the listeners will verify all constraints of the entity instance and throw an exception if any
constraint is violated. Basically, objects will be checked before any inserts and before any updates made by Hibernate. This is the most convenient and the easiest way to activate the validation process. On constraint violation, the event will raise a runtime InvalidStateException which contains an array of InvalidValues describing each failure.
<hibernate-configuration>
...
<event type="pre-update">
<listener
class="org.hibernate.validator.event.ValidatePreUpdateEventListener"/>
</event>
<event type="pre-insert">
<listener
class="org.hibernate.validator.event.ValidatePreInsertEventListener"/>
</event>
</hibernate-configuration>

Note
When using Hibernate Entity Manager, the Validation framework is activated out of the box. If the
beans are not annotated with validation annotations, there is no performance cost.

3.2.3. Application-level validation


Hibernate Validator can be applied anywhere in your application code.

ClassValidator personValidator = new ClassValidator( Person.class );


ClassValidator addressValidator = new ClassValidator( Address.class, ResourceBundle.getBundle("message
InvalidValue[] validationMessages = addressValidator.getInvalidValues(address);

The first two lines prepare the Hibernate Validator for class checking. The first one relies upon the error messages embedded in Hibernate Validator (see Error messages), the second one uses a resource bundle for these
messages. It is considered a good practice to execute these lines once and cache the validator instances.
The third line actually validates the Address instance and returns an array of InvalidValues. Your application
logic will then be able to react to the failure.
You can also check a particular property instead of the whole bean. This might be useful for property per property user interaction

ClassValidator addressValidator = new ClassValidator( Address.class, ResourceBundle.getBundle("message


//only get city property invalid values
InvalidValue[] validationMessages = addressValidator.getInvalidValues(address, "city");
//only get potential city property invalid values
InvalidValue[] validationMessages = addressValidator.getPotentialInvalidValues("city", "Paris")

3.2.4. Validation informations


As a validation information carrier, hibernate provide an array of InvalidValue. Each InvalidValue has a
Hibernate 3.1 beta 9

42

Hibernate Validator
buch of methods describing the individual issues.
getBeanClass()

retrieves the failing bean type

getBean()retrieves
getValue()

the failing instance (if any ie not when using getPotentianInvalidValues())

retrieves the failing value

getMessage()

retrieves the proper internationalized error message

retrieves the root bean instance generating the issue (useful in conjunction with @Valid), is null
if getPotentianInvalidValues() is used.
getRootBean()

getPropertyPath()

Hibernate 3.1 beta 9

retrieves the dotted path of the failing property starting from the root bean

43

Chapter 4. Hibernate Lucene Integration


Lucene is a high-performance Java search engine library available from the Apache Software Foundation. Hibernate Annotations includes a package of annotations that allows you to mark any domain model object as indexable and have Hibernate maintain a Lucene index of any instances persisted via Hibernate.

4.1. Using Lucene to index your entities


4.1.1. Annotating your domain model
First, we must declare a persistent class as @Indexed:
@Entity
@Indexed(index="indexes/essays")
public class Essay {
...
}

The index attribute tells Hibernate where the Lucene index is located (a directory on your file system). If you
wish to define a base directory for all lucene indexes, you can use the hibernate.lucene.index_dir property
in your configuration file.
Lucene indexes contain four kinds of fields: keyword fields, text fields, unstored fields and unindexed fields.
Hibernate Annotations provides annotations to mark a property of an entity as one of the first three kinds of indexed fields.
@Entity
@Indexed(index="indexes/essays")
public class Essay {
...
@Id
@Keyword(id=true)
public Long getId() { return id; }
@Text(name="Abstract")
public String getSummary() { return summary; }
@Lob
@Unstored
public String getText() { return text; }
}

These annotations define an index with three fields: Id, Abstract and Text.
Note: you must specify @Keyword(id=true) on the identifier property of your entity class.
The analyzer class used to index the elements is configurable through the hibernate.lucene.analyzer property. If none defined, org.apache.lucene.analysis.standard.StandardAnalyzer is used as the default.

4.1.2. Enabling automatic indexing


Finally, we enable the LuceneEventListener for the three Hibernate events that occur after changes are committed to the database.

Hibernate 3.1 beta 9

44

Hibernate Lucene Integration

<hibernate-configuration>
...
<event type="post-commit-update"
<listener
class="org.hibernate.lucene.event.LuceneEventListener"/>
</event>
<event type="post-commit-insert"
<listener
class="org.hibernate.lucene.event.LuceneEventListener"/>
</event>
<event type="post-commit-delete"
<listener
class="org.hibernate.lucene.event.LuceneEventListener"/>
</event>
</hibernate-configuration>

Hibernate 3.1 beta 9

45

Das könnte Ihnen auch gefallen