Beruflich Dokumente
Kultur Dokumente
Tutoriales de Programacion Java: HIbernate - Parte 1: Persistiendo Objetos Simples usando Mapeos en XML
Compartir
14
Ms
Siguiente blog
Pgina de Concursos
Presentaciones Capacitacin
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
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.
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
hibernate3.jar
Miembros (173) Ms
2012 (2)
2011 (11)
2010 (10)
2009 (22)
septiembre (2)
agosto (2)
julio (1)
junio (3)
mayo (2)
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...":
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:
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
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>
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:
<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:
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.
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);
}
}
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".
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:
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:
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
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":
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-1-persistiendo-objetos.html
12/29
10/11/13
Tutoriales de Programacion Java: HIbernate - Parte 1: Persistiendo Objetos Simples usando Mapeos en XML
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:
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):
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;
}
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:
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)
79 comentarios:
Annimo 13 de mayo de 2009 05:17
ok programador java , como siempre excelente tutorial ya lo estoy implementando . . .
Responder
Alex
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
Pgina de Concursos
Presentaciones Capacitacin
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
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:
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
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
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:
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)
DATOS PERSONALES
Alex
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;
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:
<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:
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)
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.
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);
}
}
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)
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".
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:
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:
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:
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":
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)
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:
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):
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:
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":
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)
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
Ms
Siguiente blog
Pgina de Concursos
Presentaciones Capacitacin
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
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
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/2009/06/hibernate-parte-3-relaciones-uno-uno.html
1/24
10/11/13
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
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
2012 (2)
2011 (11)
2010 (10)
2009 (22)
septiembre (2)
agosto (2)
julio (1)
junio (3)
Acepto Donaciones
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
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.
DATOS PERSONALES
Alex
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.
www.javatutoriales.com/2009/06/hibernate-parte-3-relaciones-uno-uno.html
3/24
10/11/13
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
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.
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
<?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:
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
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":
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":
<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
<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:
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
@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
@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;
www.javatutoriales.com/2009/06/hibernate-parte-3-relaciones-uno-uno.html
10/24
10/11/13
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
Como podemos ver tambin este ejemplo funciona ^-^. Ahora veremos cmo crear relaciones uno a uno pero en esta ocasin
bidireccionales.
www.javatutoriales.com/2009/06/hibernate-parte-3-relaciones-uno-uno.html
12/24
10/11/13
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
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:
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
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
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:
/*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();
www.javatutoriales.com/2009/06/hibernate-parte-3-relaciones-uno-uno.html
16/24
10/11/13
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:
pais.setPresidente(presidente);
Como podemos ver, una vez ms ^-^, todo ha salido bien, por lo que podemos pasar a la ltima parte de este tutorial:
www.javatutoriales.com/2009/06/hibernate-parte-3-relaciones-uno-uno.html
17/24
10/11/13
@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
@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":
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
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
Ms
Siguiente blog
Pgina de Concursos
Presentaciones Capacitacin
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
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
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
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
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)
2009 (22)
septiembre (2)
agosto (2)
julio (1)
junio (3)
Acepto Donaciones
abril (5)
marzo (2)
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.
www.javatutoriales.com/2009/06/hibernate-parte-4-relaciones-uno-muchos.html
2/27
10/11/13
Programador
Java?
InfoJobs.net/Ofert
Ms de mil ofertas de
empleo Java
interesantes
Descbrelas!
Extend JMS to
.NET
Cursos Gratis
INEM
Kick Eclipse to
the Cloud
Bien, ahora comencemos con los ejemplos:
Curso
Programacin
DATOS PERSONALES
Alex
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
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:
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
<?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
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:
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:
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):
www.javatutoriales.com/2009/06/hibernate-parte-4-relaciones-uno-muchos.html
6/27
10/11/13
<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
/*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.
www.javatutoriales.com/2009/06/hibernate-parte-4-relaciones-uno-muchos.html
8/27
10/11/13
@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;
}
}
www.javatutoriales.com/2009/06/hibernate-parte-4-relaciones-uno-muchos.html
9/27
10/11/13
@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>();
www.javatutoriales.com/2009/06/hibernate-parte-4-relaciones-uno-muchos.html
10/27
10/11/13
@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<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);
}
}
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:
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
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.
www.javatutoriales.com/2009/06/hibernate-parte-4-relaciones-uno-muchos.html
12/27
10/11/13
www.javatutoriales.com/2009/06/hibernate-parte-4-relaciones-uno-muchos.html
13/27
10/11/13
<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:
<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
Ahora comprobemos que en la base de datos solo quedan los datos de la persona2, junto con sus libroscorrespondientes:
www.javatutoriales.com/2009/06/hibernate-parte-4-relaciones-uno-muchos.html
15/27
10/11/13
@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:
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
@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
/*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:
www.javatutoriales.com/2009/06/hibernate-parte-4-relaciones-uno-muchos.html
18/27
10/11/13
Ms
Siguiente blog
Pgina de Concursos
Presentaciones Capacitacin
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
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
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
SEGUIDORES
Miembros (173) Ms
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)
2009 (22)
septiembre (2)
agosto (2)
julio (1)
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.
www.javatutoriales.com/2009/08/hibernate-parte-5-relaciones-muchos-uno_02.html
2/11
10/11/13
DATOS PERSONALES
Alex
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
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:
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
<?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:
www.javatutoriales.com/2009/08/hibernate-parte-5-relaciones-muchos-uno_02.html
5/11
10/11/13
<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:
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:
www.javatutoriales.com/2009/08/hibernate-parte-5-relaciones-muchos-uno_02.html
6/11
10/11/13
Como podemos ver, los datos se han guardado de forma correcta ^-^.
Ahora veamos cmo podemos hacer lo mismo usando anotaciones.
@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;
}
}
www.javatutoriales.com/2009/08/hibernate-parte-5-relaciones-muchos-uno_02.html
7/11
10/11/13
@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;
www.javatutoriales.com/2009/08/hibernate-parte-5-relaciones-muchos-uno_02.html
8/11
10/11/13
@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:
www.javatutoriales.com/2009/08/hibernate-parte-5-relaciones-muchos-uno_02.html
9/11
10/11/13
Ahora comprobemos que en la base de datos tengamos las 3 cadenas televisivas y los 2 televidentes:
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
Ms
Siguiente blog
Pgina de Concursos
Presentaciones Capacitacin
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
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
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
Java file
libraries
www.aspose.com
DOC, XLS, PPT, PDF,
MSG and more APIs
to Manage, Print and
Convert
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:
Miembros (173) Ms
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.
www.javatutoriales.com/2009/08/hibernate-parte-6-relaciones-muchos.html
2/23
10/11/13
Aprovecharemos para crear nuestro archivo de configuracin de Hibernate, "hibernate.cfg.xml", el cual ser muy parecido al del
primer tutorial:
DATOS PERSONALES
Alex
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/08/hibernate-parte-6-relaciones-muchos.html
3/23
10/11/13
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:
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
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:
www.javatutoriales.com/2009/08/hibernate-parte-6-relaciones-muchos.html
5/23
10/11/13
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
<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>
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":
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:
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
<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:
www.javatutoriales.com/2009/08/hibernate-parte-6-relaciones-muchos.html
8/23
10/11/13
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:
www.javatutoriales.com/2009/08/hibernate-parte-6-relaciones-muchos.html
9/23
10/11/13
@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;
}
}
www.javatutoriales.com/2009/08/hibernate-parte-6-relaciones-muchos.html
10/23
10/11/13
@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>();
www.javatutoriales.com/2009/08/hibernate-parte-6-relaciones-muchos.html
11/23
10/11/13
@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:
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
www.javatutoriales.com/2009/08/hibernate-parte-6-relaciones-muchos.html
13/23
10/11/13
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:
www.javatutoriales.com/2009/08/hibernate-parte-6-relaciones-muchos.html
14/23
10/11/13
www.javatutoriales.com/2009/08/hibernate-parte-6-relaciones-muchos.html
15/23
10/11/13
<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>
www.javatutoriales.com/2009/08/hibernate-parte-6-relaciones-muchos.html
16/23
10/11/13
Podemos comprobar que todo sali como esperbamos ^-^. Por lo que solo queda que veamos cmo crear relaciones bidireccionales con
anotaciones:
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:
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
@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
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
Ms
Siguiente blog
Pgina de Concursos
Presentaciones Capacitacin
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
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...":
www.javatutoriales.com/2009/09/hibernate-parte-7-hql-primera-parte.html
1/25
10/11/13
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
Miembros (173) Ms
2012 (2)
2011 (11)
2010 (10)
2009 (22)
septiembre (2)
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
</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".
Aunque estas relaciones son simples, nos ayudaran a mostrar las consultas que realizamos con mayor frecuencia en las aplicaciones.
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
@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
@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
@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
Haramos
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.
www.javatutoriales.com/2009/09/hibernate-parte-7-hql-primera-parte.html
7/25
10/11/13
www.javatutoriales.com/2009/09/hibernate-parte-7-hql-primera-parte.html
8/25
10/11/13
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
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
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:
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:
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
O as:
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:
Tambin podemos proporcionar condiciones extra al join con la palabra reservada WITH:
www.javatutoriales.com/2009/09/hibernate-parte-7-hql-primera-parte.html
12/25
10/11/13
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:
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 ^-^.
www.javatutoriales.com/2009/09/hibernate-parte-7-hql-primera-parte.html
13/25
10/11/13
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:
Esta consulta regresar la direccionde los usuarios. Podemos expresar esta misma consulta de una forma ms compacta haciendo
uso de los joins implcitos:
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:
www.javatutoriales.com/2009/09/hibernate-parte-7-hql-primera-parte.html
14/25
10/11/13
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:
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:
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
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
new Main();
obtenNombres();
www.javatutoriales.com/2009/09/hibernate-parte-7-hql-primera-parte.html
16/25
10/11/13
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:
www.javatutoriales.com/2009/09/hibernate-parte-7-hql-primera-parte.html
17/25
10/11/13
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:
listaResultados.get(i)[0]
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
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:
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
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)
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
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
Alex
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
Ms
Siguiente blog
Pgina de Concursos
Presentaciones Capacitacin
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
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.
www.javatutoriales.com/2010/05/hibernate-parte-8-hql-segunda-parte.html
1/19
10/11/13
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
Miembros (173) Ms
2012 (2)
2011 (11)
2010 (10)
diciembre (1)
octubre (3)
septiembre (2)
agosto (2)
julio (1)
mayo (1)
www.javatutoriales.com/2010/05/hibernate-parte-8-hql-segunda-parte.html
2/19
10/11/13
DATOS PERSONALES
Alex
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:
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:
www.javatutoriales.com/2010/05/hibernate-parte-8-hql-segunda-parte.html
3/19
10/11/13
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:
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.
www.javatutoriales.com/2010/05/hibernate-parte-8-hql-segunda-parte.html
4/19
10/11/13
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:
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
Estas restricciones pueden extenderse para valores de propiedades de objetos relacionados (componentes), como por ejemplo:
Tambin podemos obtener los valores de los Usuarios que tienen una Direccionasociada, o sea, cuya Direccionno est nula:
www.javatutoriales.com/2010/05/hibernate-parte-8-hql-segunda-parte.html
6/19
10/11/13
Algo interesante en HQL es que el operador "=" no solo sirve para comparar valores de atributos, sino que tambin nos sirva para
comparar instancias:
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:
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
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:
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
www.javatutoriales.com/2010/05/hibernate-parte-8-hql-segunda-parte.html
8/19
10/11/13
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:
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:
www.javatutoriales.com/2010/05/hibernate-parte-8-hql-segunda-parte.html
9/19
10/11/13
Como este resultado no nos dice mucho ^-^! Crearemos un mtodo que ejecute esta consulta:
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:
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)
www.javatutoriales.com/2010/05/hibernate-parte-8-hql-segunda-parte.html
10/19
10/11/13
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.
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:
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:
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
Crearemos un mtodo llamado "obtenNombreDireccion" en nuestra clase "Main" para asegurarnos que la consulta anterior
efectivamente nos devuelve los valores que hemos pedido:
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:
www.javatutoriales.com/2010/05/hibernate-parte-8-hql-segunda-parte.html
12/19
10/11/13
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.
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:
www.javatutoriales.com/2010/05/hibernate-parte-8-hql-segunda-parte.html
13/19
10/11/13
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.
SELECT u FROM Usuario u left join u.permisos p GROUP BY u ORDER BY COUNT(p) asc
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:
www.javatutoriales.com/2010/05/hibernate-parte-8-hql-segunda-parte.html
14/19
10/11/13
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?):
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)
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
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
www.javatutoriales.com/2010/05/hibernate-parte-8-hql-segunda-parte.html
15/19
10/11/13
Ms
Siguiente blog
Pgina de Concursos
Presentaciones Capacitacin
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
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
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
SEGUIDORES
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
2012 (2)
2011 (11)
2010 (10)
diciembre (1)
octubre (3)
septiembre (2)
agosto (2)
julio (1)
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.
www.javatutoriales.com/2010/07/hibernate-parte-9-parametros-en-hql.html
2/19
10/11/13
Tambin crearemos el archivo de configuracin hibernate.cfg.xml que ser prcticamente igual que el de los ltimos 8 tutoriales:
Alex
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
@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
@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
@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
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
@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
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:
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:
www.javatutoriales.com/2010/07/hibernate-parte-9-parametros-en-hql.html
9/19
10/11/13
www.javatutoriales.com/2010/07/hibernate-parte-9-parametros-en-hql.html
10/19
10/11/13
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.
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:
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
query.setParameter(nombreUsuario, username);
query.setParameter(password, password);
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.
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:
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
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.
www.javatutoriales.com/2010/07/hibernate-parte-9-parametros-en-hql.html
13/19
10/11/13
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:
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:
www.javatutoriales.com/2010/07/hibernate-parte-9-parametros-en-hql.html
todo
lo
anterior
en
un
mtodo
llamado
14/19
10/11/13
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
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
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)
www.javatutoriales.com/2010/07/hibernate-parte-9-parametros-en-hql.html
17/19
10/11/13
Ms
Siguiente blog
Pgina de Concursos
Presentaciones Capacitacin
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
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...":
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
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
Miembros (173) Ms
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)
octubre (3)
septiembre (2)
agosto (2)
www.javatutoriales.com/2010/08/hibernate-parte-10-herencia.html
2/35
10/11/13
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
3/35
10/11/13
www.javatutoriales.com/2010/08/hibernate-parte-10-herencia.html
4/35
10/11/13
www.javatutoriales.com/2010/08/hibernate-parte-10-herencia.html
5/35
10/11/13
Bien, ya que tenemos las clases entidades que estaremos usando, comencemos con el tutorial.
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.
www.javatutoriales.com/2010/08/hibernate-parte-10-herencia.html
6/35
10/11/13
<?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:
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>
<?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
<?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":
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
www.javatutoriales.com/2010/08/hibernate-parte-10-herencia.html
8/35
10/11/13
<?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>
<?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>
<?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":
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
<?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":
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
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.
@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
@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
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
www.javatutoriales.com/2010/08/hibernate-parte-10-herencia.html
13/35
10/11/13
@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;
}
}
@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;
}
}
www.javatutoriales.com/2010/08/hibernate-parte-10-herencia.html
14/35
10/11/13
@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;
}
}
<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".
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
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.
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.
www.javatutoriales.com/2010/08/hibernate-parte-10-herencia.html
16/35
10/11/13
<?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:
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:
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
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>
<?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>
<?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>
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
<?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":
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
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.
@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
@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
@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":
www.javatutoriales.com/2010/08/hibernate-parte-10-herencia.html
22/35
10/11/13
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
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
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
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
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.
www.javatutoriales.com/2010/08/hibernate-parte-10-herencia.html
25/35
10/11/13
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.
<?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:
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
<?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>
<?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>
<?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>
www.javatutoriales.com/2010/08/hibernate-parte-10-herencia.html
27/35
10/11/13
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
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.
@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
@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
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":
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);
www.javatutoriales.com/2010/08/hibernate-parte-10-herencia.html
31/35
10/11/13
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);
www.javatutoriales.com/2010/08/hibernate-parte-10-herencia.html
32/35
10/11/13
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.
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
Ms
Siguiente blog
Pgina de Concursos
Presentaciones Capacitacin
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
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...":
www.javatutoriales.com/2010/08/hibernate-parte-11-interceptores-y.html
1/20
10/11/13
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
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.
2012 (2)
2011 (11)
2010 (10)
diciembre (1)
octubre (3)
septiembre (2)
agosto (2)
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
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
www.javatutoriales.com/2010/08/hibernate-parte-11-interceptores-y.html
3/20
10/11/13
@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;
}
}
www.javatutoriales.com/2010/08/hibernate-parte-11-interceptores-y.html
4/20
10/11/13
Veamos primero cmo trabaja el mtodo "onSave" y cmo lo usaremos para nuestros propsitos de auditora.
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
@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:
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":
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):
www.javatutoriales.com/2010/08/hibernate-parte-11-interceptores-y.html
6/20
10/11/13
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);
}
}
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:
www.javatutoriales.com/2010/08/hibernate-parte-11-interceptores-y.html
7/20
10/11/13
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:
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":
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
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
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:
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:
www.javatutoriales.com/2010/08/hibernate-parte-11-interceptores-y.html
10/20
10/11/13
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:
Lo primero que haremos es regresar un valor de "false", ya que NO queremos que la operacin de eliminacin sea cancelada.
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:
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:
Esta
interface
tiene
un
solo
mtodo:
"onPostDelete",
"org.hibernate.event.PostDeleteEvent", de la siguiente forma:
que
recibe
un
parmetro
de
tipo
www.javatutoriales.com/2010/08/hibernate-parte-11-interceptores-y.html
11/20
10/11/13
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:
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.
<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
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
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>
www.javatutoriales.com/2010/08/hibernate-parte-11-interceptores-y.html
13/20
10/11/13
Veamos que nuestra aplicacin funciona correctamente colocando el siguiente cdigo en el mtodo "main" de nuestra clase "Main":
//
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
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".
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:
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:
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
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
//
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
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.
iv
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!
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;
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.
@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
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.
Entity Beans
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:
@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
(1)
name
(2)
unique
(3)
(4)
(5)
(6)
(7)
(8)
(8)
(10)
(1)
(2)
(3)
(4)
(5)
(6)
(7)
(8)
(9)
Entity Beans
@AttributeOverride
@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; }
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.
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:
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
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.IDENTITY)
Entity Beans
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
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
10
Entity Beans
Single Table per Class Hierarchy Strategy: the <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:
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() { ... }
...
}
12
Entity Beans
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 {
...
}
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,
@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() { ...}
}
@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() {
...
}
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.
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;
}
...
}
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
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.
@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
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;
}
...
}
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() {
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
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.
@Entity
public class RegionalArticle implements Serializable {
@Id
21
Entity Beans
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;
...
22
Entity Beans
@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.
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
description
org.hibernate.cacheable
org.hibernate.cacheRegion
org.hibernate.timeout
Query timeout
org.hibernate.fetchSize
org.hibernate.flushMode
org.hibernate.cacheMode
org.hibernate.readOnly
org.hibernate.comment
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.
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-
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;
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.
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
selectBeforeUpdate: Specifies that Hibernate should never perform an SQL UPDATE unless it is certain
that an object is actually modified.
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
class is retrieved.
@org.hibernate.annotations.Check
@OnDelete(action=OnDeleteAction.CASCADE)
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
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
@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:
fine tune the access type at the class level or at the property level
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;
}
}
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
@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;
}
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 { ... }
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.
32
Entity Beans
It is possible to set
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>();
33
Entity Beans
34
Entity Beans
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)
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
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)
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.
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.
36
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.
Apply on
Runtime checking
property (String)
@Max(value=)
@Min(value=)
37
Hibernate Validator
Annotation
Apply on
Runtime checking
@NotNull
property
@Past
@Future
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
@Range(min=, max=)
@Size(min=, max=)
@AssertFalse
property
@AssertTrue
property
@Valid
property (object)
property (String)
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.
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}
39
Hibernate Validator
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.
40
Hibernate Validator
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.
41
Hibernate Validator
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.
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
42
Hibernate Validator
buch of methods describing the individual issues.
getBeanClass()
getBean()retrieves
getValue()
getMessage()
retrieves the root bean instance generating the issue (useful in conjunction with @Valid), is null
if getPotentianInvalidValues() is used.
getRootBean()
getPropertyPath()
retrieves the dotted path of the failing property starting from the root bean
43
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.
44
<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>
45