Tutorial Hibernate
Tutorial Hibernate
Tutorial de Hibernate
Índice de contenido
Introducción............................................................................................................................................... 4
Herramientas necesarias.............................................................................................................................6
Hibernate............................................................................................................................................... 6
HSQL.....................................................................................................................................................6
Eclipse................................................................................................................................................... 6
Derby..................................................................................................................................................... 6
Aplicación sencilla usando Hibernate........................................................................................................7
Crear el proyecto Java con Eclipse........................................................................................................7
Configuración del Build Path................................................................................................................ 9
Creación de las clases Java..................................................................................................................12
Clase del objeto de dominio........................................................................................................... 12
Clase de Manejo del objeto de dominio......................................................................................... 14
Configuración de Hibernate................................................................................................................ 18
El archivo hibernate.cfg.xml...........................................................................................................18
El archivo Libro.hbm.xml...............................................................................................................19
Creación del archivo log2j.properties.............................................................................................20
Automatización del proceso de construcción con ANT......................................................................20
Correr la aplicación............................................................................................................................. 22
Aplicación sencilla utilizando Hibernate y Derby................................................................................... 26
Configuración de el archivo hibernate.cfg.xml................................................................................... 27
Corriendo la aplicación....................................................................................................................... 28
Creando aplicaciones con Hibernate........................................................................................................32
Anatomía de los archivo de mapeo..................................................................................................... 33
Tipos de datos soportados por Hibernate........................................................................................33
Atributos del elemento <hibernate-mapping>................................................................................33
Atributos del elemento <class>...................................................................................................... 34
Atributos del elemento <id>........................................................................................................... 36
Atributos del elemento <generator>.......................................................................................... 36
Atributos del elemento <property>.................................................................................................37
Relaciones entre tablas........................................................................................................................ 38
Atributos del elemento <one-to-one>.............................................................................................39
Atributos del elemento <one-to-many>..........................................................................................40
Atributos del elemento <many-to-many>.......................................................................................42
Atributos comunes de los elementos de colección......................................................................... 42
Atributos del elemento <set>..................................................................................................... 43
Atributos del elemento <list>.....................................................................................................45
Atributos del elemento <idbag>.................................................................................................45
Atributos del elemento <map>...................................................................................................45
Atributos del elemento <bag>....................................................................................................46
Relaciones bidireccionales.................................................................................................................. 46
Relaciones del tipo <one-to-many>................................................................................................46
Relaciones del tipo <many-to-many>.............................................................................................47
Mapeo de clases y sus relaciones........................................................................................................ 49
Introducción
Al trabajar con programación orientada a objetos en muchas ocasiones nos encontramos con el
problema de hacer persistir los objetos en una base de datos relacional, esto nos involucra en el
problema de que el mundo relacional y el orientado a objetos no son del todo compatibles.
Para evidenciar este problema imaginemos que tenemos que hacer persistir un solo objeto en una tabla
relacional, esto evidentemente involucra la creación de un DAO (Data Access Object) que nos permita
hacer persistir a este objeto. Este DAO debe tener la implementación de código SQL para tener acceso
a la base de datos en la queremos realizar la persistencia y este código debe permitir almacenar en los
campos de la tabla todo el estado del objeto
Ejemplo:
Libro
-id: Integer
-titulo: String
-autor: String
+getId(): Integer
+setId(Integer)
+getTitulo(): String
+setTitulo(String)
+getAutor(): String
+setAutor(String)
La Ilustración 1 muestra el objeto de dominio Libro que deseamos hacer persistir. Para esto en el
objeto DAO deberíamos tener implementado el método create que deberia ser similar al siguiente
código:
public boolean create(Libro libro){
try {
// Prepara el statement
PreparedStatement statement =
DatabaseManager.getConnection().prepareStatement(
"INSERT INTO Libro VALUES ( ? , ? , ? )");
statement.setInteger(1,libro.getId());
statement.setString(2,libro.getTitulo());
statement.setString(3,libro.getAutor());
statement.executeUpdate();
return true;
} catch (SQLException e) {
// Cacha excepcion
e.printStackTrace();
return false;
}
}
En realidad hacer persistir un solo objeto en una tabla relacional es bastante sencillo, el problema es
que en la vida real no solo se realiza persistencia de un solo objeto y mucho menos de varios objetos
sin relación entre ellos, como se puede notar el realizar persistencia en bases de datos relacionales es
bastante complejo.
Para solventar estos problemas existen frameworks que se encargan de realizar este mapeo de Objeto a
Relacional, a estos frameworks se les denomina ORM (Object-Relational Mapping). En esta tutorial
vamos a trabajar con Hibernate, un ORM open source bastante maduro.
Antes de entrar en el detalle de Hibernate vamos a mostrar como un ORM realiza el mapeo de
Orientado a Relacional para que se observen las ventajas de utilizar estos frameworks.
● Un buen ORM permite tomar un objeto Java y hacerlo persistir de una forma similar a la
siguiente:
orm.save(object);
la instrucción anterior debe generar todo el código SQL para realizar la persistencia del objeto
● El ORM debe permitir cargar un objeto Java complejo (con relaciones hacia otros objetos) de la
base de datos a memoria:
myObject = orm.load(MyObject.class,objectId);
Como se puede observar en estos ejemplos los métodos save, load y find tienen una correspondencia
con los métodos create y retrieve que se implementan usualmente en un DAO, pero con la ventaja
de que son mas sencillos e intuitivos de emplear y reducen fallas al crear todo el código SQL.
Herramientas necesarias
Hibernate
Se puede obtener Hibernate directamente de su pagina en Internet http://hibernate.org/, de aquí se
puede obtener el zip de Hibernate 3.0.2 que es la versión que vamos a utilizar.
Después de obtener el zip lo vamos a crear una carpeta llamada home en la unidad C:, y en esta vamos a
descomprimir el zip de Hibernate.
Nota: El nombre y la localización de la carpeta es una sugerencia propuesta en este tutorial, si se
cambia el nombre y la localización se deben ajustar las direcciones en los sitios en donde se solicite
HSQL
HSQL se puede obtener de la pagina http://hsqldb.sourceforge.net/ , de esta vamos a descargar la
versión 1.7.3.3 que viene en zip.
Suponiendo que ya tenemos Hibernate vamos a descomprimir el zip de HSQL en la carpeta home (o en
la misa en donde se descomprimió Hibernate).
Eclipse
Eclipse es la herramienta que vamos a emplear para realizar el desarrollo de nuestras aplicaciones, este
se puede obtener de la pagina http://www.eclipse.org/downloads/ . La versión que vamos a utilizar sera
la 3.2 que también viene en un zip que vamos a descomprimir en C:.
Derby
Derby es una base de datos embebida, open source que utilizaremos en lugar de HSQL en algunos de
los ejemplos de este tutorial. Se puede obtener de la pagina http://db.apache.org/derby/releases/release-
10.1.2.1.cgi. Para este tutorial utilizaremos la versión 10.1.2.1 que se obtiene en un zip de la pagina
antes mencionada.
Una vez en Eclipse vamos a crear un nuevo proyecto al que llamaremos PruebaHibernate. Al crearla le
agregamos la carpeta de fuentes src y el package mx.uam.hibernate.
Ahora vamos a crear los directorios lib en donde vamos a agregar las librerías que vamos a ocupar y
data en donde HSQL genera una bitácora de las operaciones hechas en la base de datos, estos
directorios se crean en la raíz del proyecto.
En el directorio de lib vamos a copiar del directorio lib de Hibernate los siguientes jars:
● cglib-2.1
● commons-logging-1.0.4
● hibernate3
● jta
● commons-collections-2.1.1
● dom4j-1.6
● jdbc2_0-stdext
● log4j-1.2.9
● asm
● antlr-2.7.5H3
y del directorio lib de hsql el jar hsql.jar
Realizamos la misma operación para todos los jar que se encuentren en el directorio lib y una vez
agregados presionamos OK.
package mx.uam.hibernate;
Cabe hacer notar que el método setId es privado, esto es por que solo Hibernate debe encargarse de
administrar los id's de los objetos Libro, también se debe notar que este método marcara un warning
por que ningún otro método de la clase lo esta utilizando.
Otra cosa que vale la pena mencionar es que no se debe declarar la variable id como un tipo de datos
primitivo, esto por facilidad de manejo para Hibernate.
package mx.uam.hibernate;
import java.util.List;
import org.hibernate.HibernateException;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.Configuration;
import org.hibernate.classic.Session;
public ManejadorLibro() {
try {
System.out.println("Inicalizando Hibernate");
sessionFactory = new Configuration().configure().buildSessionFactory();
System.out.println("terminado la inicializacion de Hibernate");
} catch (HibernateException e) {
e.printStackTrace();
}
}
session.save(libro);
tx.commit();
session.close();
} catch (HibernateException e) {
e.printStackTrace();
}
}
private List listaLibros() {
try {
Session session = sessionFactory.openSession();
Transaction tx = session.beginTransaction();
tx.commit();
session.close();
return result;
} catch (HibernateException e) {
throw new RuntimeException(e.getMessage());
}
}
public static void main(String[] args) {
}
}
Configuración de Hibernate
Hasta ahora solo hemos mencionado algunos aspectos de Hibernate pero no hemos hecho ninguna
configuración del servicio, en este momento vamos a configurar a Hibernate para que conozca al objeto
que debe hacer persistir y en donde lo hará persistir.
El archivo hibernate.cfg.xml
En directorio src creamos el archivo hibernate.cfg.xml y agregamos el siguiente codigo:
<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration
PUBLIC "-//Hibernate/Hibernate Configuration DTD//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
<session-factory>
<property
name="hibernate.connection.driver_class">org.hsqldb.jdbcDriver</property>
<property name="hibernate.connection.url">jdbc:hsqldb:data/test</property>
<property name="hibernate.connection.username">sa</property>
<property name="hibernate.connection.password"></property>
<property name="dialect">org.hibernate.dialect.HSQLDialect</property>
<property name="show_sql">true</property>
<property name="transaction.factory_class">
org.hibernate.transaction.JDBCTransactionFactory
</property>
<property name="hibernate.cache.provider_class">
org.hibernate.cache.HashtableCacheProvider
</property>
<property name="hibernate.hbm2ddl.auto">update</property>
<mapping resource="mx/uam/hibernate/data/Libro.hbm.xml"/>
</session-factory>
</hibernate-configuration>
Este archivo contiene varios tags, pero lo importante es lo que contiene el tag hibernate-configuration,
en este tag aparece otro llamado session-factory que contiene, en orden de aparición:
● La clase del manejador de JDBC
● La URL del la conexión con JDBC
El archivo Libro.hbm.xml
Este archivo le dice a Hibernate como es el objeto que debe persistir. Este archivo se debe colocar en el
directorio que se dijo en el archivo de configuración de Hibernate, para esto debemos crear un
directorio en el package mx.uam.hibernate llamado data y crear un archivo llamado Libro.hbm.xml con
la siguiente información:
<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
"-//hibernate/hibernate Mapping DTD 2.0//EN"
"http://hibernate.sourceforge.net/hibernate-mapping-2.0.dtd">
<hibernate-mapping>
</hibernate-mapping>
Este documento contiene el tag hibernate-mapping que contiene el tag class que es el que contiene la
información de la estructura del objeto, esta información es:
● El nombre de la clase y la tabla en la que se hará la persistencia
● El tag id que dice a que columna se va a mapear, su tipo y la forma en que se genera el
identificador
● Las propiedades de la clase y su tipo
Cabe mencionar que Hibernate puede generar de varias formas un identificador y que en las
propiedades se pueden especificar otras cosas tales como: el nombre de la columna, la integridad
referencial, etc.
</fileset>
</copy>
</target>
<target name="run" depends="compile">
<java classname="${mainclass}" fork="true">
<arg value="agrega"/>
<arg value="Tutorial"/>
<arg value="IngSW"/>
<classpath refid="classpath" />
</java>
</target>
</project>
Correr la aplicación
Para poder correr la aplicación vamos a abrir la vista de ANT, para esto vamos a al menú principal y
seleccionamos Window->Show View->Ant, después seleccionamos el archivo build.xml y lo
arrastramos hasta colocarlo en la vista de ANT.
El siguiente para es dar doble click cobre la tarea “run” y en la consola debe desplegarse algo similar a:
Buildfile: C:\home\hsqldb\hibernate\PruebaHibernate\build.xml
init:
prepare:
copy-resources:
compile:
run:
[java] Inicalizando Hibernate
[java] INFO - Hibernate 3.0.2
Con esto hemos agregado una entrada a la tabla LIBRO con la informacion:
Titulo: Tutorial
Autor: IngSW
Esta es la información que le pasamos al programa en las lineas de ANT de la tarea run:
<arg value="agrega"/>
<arg value="Tutorial"/>
<arg value="IngSW"/>
Para observar que esta entrada en la tabla ha sido persistida por Hibernate cambiaremos estas lineas
por:
<arg value="lista"/>
Ahora damos doble click en la tarea run y debe aparecer algo similar a:
Buildfile: C:\home\hsqldb\hibernate\PruebaHibernate\build.xml
init:
prepare:
copy-resources:
compile:
run:
[java] Inicalizando Hibernate
[java] INFO - Hibernate 3.0.2
[java] INFO - hibernate.properties not found
[java] INFO - using CGLIB reflection optimizer
[java] INFO - using JDK 1.4 java.sql.Timestamp handling
[java] INFO - configuring from resource: /hibernate.cfg.xml
[java] INFO - Configuration resource: /hibernate.cfg.xml
[java] INFO - Mapping resource: mx/uam/hibernate/data/Libro.hbm.xml
[java] INFO - Mapping class: mx.uam.hibernate.Libro -> LIBRO
<hibernate-configuration>
<session-factory>
<property
name="hibernate.connection.driver_class">org.apache.derby.jdbc.EmbeddedDriver</prop
erty>
<property
name="hibernate.connection.url">jdbc:derby:build/derby/hibernate;create=true</prope
rty>
<property name="hibernate.connection.username">sa</property>
<property name="hibernate.connection.password"></property>
<property name="dialect">org.hibernate.dialect.DerbyDialect</property>
<property name="show_sql">true</property>
<property name="transaction.factory_class">
org.hibernate.transaction.JDBCTransactionFactory
</property>
<property name="hibernate.cache.provider_class">
org.hibernate.cache.HashtableCacheProvider
</property>
<property name="hibernate.hbm2ddl.auto">update</property>
<mapping resource="mx/uam/hibernate/data/Libro.hbm.xml"/>
</session-factory>
</hibernate-configuration>
Corriendo la aplicación
Una vez realizadas las modificaciones mencionadas modificamos los parámetros que se le pasan al
programa para que agregue una entrada en la base de datos Derby.
Ejemplo:
Ahora salvamos el archivo build.xml y en la vista de ANT damos doble click sobre la tarea run, esto
debe generar una entrada en la base de datos y dar la siguiente traza:
Buildfile: C:\home\hsqldb\hibernate\PruebaHibernate\build.xml
init:
prepare:
copy-resources:
compile:
run:
[java] Inicalizando Hibernate
[java] INFO - Hibernate 3.0.2
[java] INFO - hibernate.properties not found
[java] INFO - using CGLIB reflection optimizer
[java] INFO - using JDK 1.4 java.sql.Timestamp handling
[java] INFO - configuring from resource: /hibernate.cfg.xml
[java] INFO - Configuration resource: /hibernate.cfg.xml
[java] INFO - Mapping resource: mx/uam/hibernate/data/Libro.hbm.xml
[java] INFO - Mapping class: mx.uam.hibernate.Libro -> LIBRO
[java] INFO - Configured SessionFactory: null
[java] INFO - processing extends queue
[java] INFO - processing collection mappings
[java] INFO - processing association property references
[java] INFO - processing foreign key constraints
[java] INFO - Using Hibernate built-in connection pool (not for production
use!)
[java] INFO - Hibernate connection pool size: 20
[java] INFO - autocommit mode: false
[java] INFO - using driver: org.apache.derby.jdbc.EmbeddedDriver at URL:
jdbc:derby:build/derby/hibernate;create=true
[java] INFO - connection properties: {user=sa, password=****}
[java] INFO - RDBMS: Apache Derby, version: 10.1.2.1
[java] INFO - JDBC driver: Apache Derby Embedded JDBC Driver, version:
10.1.2.1
[java] INFO - Using dialect: org.hibernate.dialect.DerbyDialect
[java] INFO - Scrollable result sets: enabled
[java] INFO - JDBC3 getGeneratedKeys(): disabled
[java] INFO - Aggressive release : disabled
[java] INFO - Default batch fetch size: 1
[java] INFO - Generate SQL with comments: disabled
[java] INFO - Order SQL updates by primary key: disabled
[java] INFO - Query translator:
org.hibernate.hql.ast.ASTQueryTranslatorFactory
[java] INFO - Using ASTQueryTranslatorFactory
Ahora para probar que se agrego la entrada en la base de datos cambiando los argumentos de la tarea
run por:
<arg value="lista"/>
Buildfile: C:\home\hsqldb\hibernate\PruebaHibernate\build.xml
init:
prepare:
copy-resources:
compile:
run:
[java] Inicalizando Hibernate
[java] INFO - Hibernate 3.0.2
[java] INFO - hibernate.properties not found
[java] INFO - using CGLIB reflection optimizer
[java] INFO - using JDK 1.4 java.sql.Timestamp handling
[java] INFO - configuring from resource: /hibernate.cfg.xml
[java] INFO - Configuration resource: /hibernate.cfg.xml
[java] INFO - Mapping resource: mx/uam/hibernate/data/Libro.hbm.xml
[java] INFO - Mapping class: mx.uam.hibernate.Libro -> LIBRO
[java] INFO - Configured SessionFactory: null
[java] INFO - processing extends queue
[java] INFO - processing collection mappings
[java] INFO - processing association property references
[java] INFO - processing foreign key constraints
[java] INFO - Using Hibernate built-in connection pool (not for production
use!)
[java] INFO - Hibernate connection pool size: 20
[java] INFO - autocommit mode: false
[java] INFO - using driver: org.apache.derby.jdbc.EmbeddedDriver at URL:
jdbc:derby:build/derby/hibernate;create=true
[java] INFO - connection properties: {user=sa, password=****}
[java] INFO - RDBMS: Apache Derby, version: 10.1.2.1
[java] INFO - JDBC driver: Apache Derby Embedded JDBC Driver, version:
10.1.2.1
[java] INFO - Using dialect: org.hibernate.dialect.DerbyDialect
[java] INFO - Scrollable result sets: enabled
[java] INFO - JDBC3 getGeneratedKeys(): disabled
[java] INFO - Aggressive release : disabled
[java] INFO - Default batch fetch size: 1
[java] INFO - Generate SQL with comments: disabled
[java] INFO - Order SQL updates by primary key: disabled
[java] INFO - Query translator:
org.hibernate.hql.ast.ASTQueryTranslatorFactory
[java] INFO - Using ASTQueryTranslatorFactory
[java] INFO - Query language substitutions: {}
[java] INFO - Transaction strategy:
org.hibernate.transaction.JDBCTransactionFactory
[java] INFO - No TransactionManagerLookup configured (in JTA environment, use
of read-write or transactional second-level cache is not recommended)
[java] INFO - Automatic flush during beforeCompletion(): disabled
[java] INFO - Automatic session close at end of transaction: disabled
[java] INFO - Second-level cache: enabled
[java] INFO - Query cache: disabled
[java] INFO - Cache provider: org.hibernate.cache.HashtableCacheProvider
[java] INFO - Optimize cache for minimal puts: disabled
[java] INFO - Structured second-level cache entries: enabled
[java] INFO - Echoing all SQL to stdout
[java] INFO - Statistics: disabled
[java] INFO - Deleted entity synthetic identifier rollback: disabled
1 Los datos tomados en esta sección están basados en el capitulo 6 del libro Pro Hibernate 3 que se encuentra en books24x7
batch-size 1 El numero de objetos que pueden ser obtenidos con el mismo id de la clase.
check SQL para crear una sentencia multirow check para generar un esquema
discriminator- null, not-null Valor usado para distinguir entre subclases idénticas de un tipo persistente
value común.
dynamic-insert true, false false Si es true, columnas nulas aparecerán al ejecutar un comando INSERT cuando
no ha colocado un valor por default.
dynamic-update true, false false Si es true, columnas sin cambios aparecerán al ejecutar un comando UPDATE
optimistic-lock none, version Especifica la estrategia de optimistic lock que sera usada.
version,
dirty, all
persister Permite que un objeto ClassPersister sea usado al hacer persistir esta clase.
polymorphism implicit, implicit Determina el tipo de polimorfismo que sera usado, el polimorfismo implícito
explicit permite regresar instancias de la clase cuando la superclase sea utilizada en el
query
proxy Especifica una clase o interface que sera utilizada como proxy para la
inicialización perezosa.
select-before- true, false false Si es true, Hibernate realiza un SELECT antes de un UPDATE para asegurarse
update que la actualización es necesaria.
where Condición de la sentencia SQL WHERE que sera usada al recuperar objetos.
Se puede especificar una clase de tipo PropertyAccesor para definir otros tipos de
acceso
unsaved- El valor que el atributo debe tomar cuando una instancia de la clase ha sido creado. Es
value obligatorio.
Tabla 4: Tag Id
En la Tabla 5 se muestran los formas en que Hibernate genera llaves primarias y si son portables o no.
Nombre Descripción
guid Genera un identificador globalmente único, no es portable.
hilo Genera identificadores únicos empleando una tabla y una columna de la base de datos, es portable.
identity Soporta el tipo de columna identity proporcionado por algunos manejadores de bases de datos
increment Genera llaves que empiezan en 1 y que se van incrementando en 1 cada vez que se agrega un nuevo registro
a la base de datos, puede ser aplicado a los tipos int, short y long. Es portable
native Selecciona entre sequence, identity e hilo como la forma de generar la llave primaria.
sequence Soporta el tipo sequence proporcionado por algunos manejadores de bases de datos.
uuid La llave se compone de la dirección IP local, la hora de JVM, lo hora del sistema y un valor continuo, no
garantiza que la llave primaria sea única.
column El nombre de la columna que almacenara el valor del atributo, por default el nombre
de la columna es el nombre del atributo.
insert true, false true Especifica si en la creación de una instancia de la clase el atributo relacionado con
esta propiedad debe ser almacenado.
name Nombre del atributo en la clase que debe empezar con minúscula, este atributo es
obligatorio.
update true, false true Especifica si en la actualización del atributo de la clase esta columna también es
modificada.
sino por tablas que interactúen entre si, el problema ahora es como hacemos que Hibernate maneje
estas relaciones entre las tablas.
Hasta donde nosotros sabemos la interacción entre tablas se hace colocando una llave foránea en la
tabla que deseamos que interactúe con otra, esta llave foránea corresponde a la llave primaria de la otra
tabla, sabemos también, que la interacción entre tablas debe tener una cardinalidad y que nosotros
debemos manejar esta cardinalidad (en una relación n a n, nosotros debemos definir el indice que
administra la relación).
En Hibernate la adminstración de las relaciones entre tablas es mas sencilla ya que tiene elementos que
ademas de definir un atributo como llave foránea le asignan la cardinalidad de la relación, estos
elementos son descritos en las siguientes secciones con los atributos que pueden tener.
cascade Determina como los cambios en la entidad padre afectan a los objetos
relacionados.
persister Especifica que ClassPersister sera usado para sobreescribir el que se encuentra
definido por default
class El tipo del atributo, es decir, el nombre de la clase a la que se hace referencia.
foreign-key El nombre de la llave foránea generada por esta asociación. Por default
Hibernate asigna un nombre
index Indica el orden de la entidades cuando sean recuradas por la tabla inversa.
insert true, false true Puesto en false, si al atributo ya tiene un valor asignado advierte cuando se
intente cambiar.
class El tipo del atributo, es decir, el nombre de la clase a la que se hace referencia.
Es común que los atributos que están relacionados con otros atributos de otras clases estén
almacenados en colecciones de datos, por ejemplo:
Hibernate proporciona soporte para poder hacer persistir a estos elementos y hacer mas fácil su
manipulación.
En la siguiente sección mostraremos las colecciones que soporta Hibernate, como se describen en el
archivo de mapeo y como podemos trabajar con ellas.
name El nombre que tiene el atributo en la clase, debe empezar con minúscula
order-by Especifica un criterio SQL para ordenar a los atributos cuando se recuperan de la base
de datos.
sort Especifica la clase Collection que sera usada, puede tomar los valores de unsorter,
natural o cualquier otra clase Comparator.
Usuario Libro
Nota: Cabe mencionar que esto es solo un ejemplo y que por comodidad se obligo a que sea
unidireccional.
En la clase Usuario existe el atributo:
private Set<Libro> librosPrestados = new HashSet<Libro>();
En el tag Set se especifica el nombre del atributo en la clase (name), la tabla que se asocia como indice
de la relación (table), ya que en las relaciones de muchos a muchos es necesario contar con uno, y si los
objetos están en memoria o no (lazy).
En el tag Key se especifica la columna que se usa como llave primaria en la tabla.
En el tag many-to-many se espacifica con que clase se relaciona y que columna usa como llave
primaria.
Al parecer no existe diferencia entre Set y List, la diferencia consiste en el contexto de la aplicación y
en que Hibernate no soporta que en relaciones bidireccionales en el lado de la relación que tiene
cardinalidad muchos que se utilicen listas, mapas o arreglos.2
Relaciones bidireccionales
Así como es común que interactúen 2 tablas, también lo es que se pueda navegar en ambos sentidos de
la relación, en esta sección vamos a tratar este problema para mostrar como se mapean estas
visibilidades empleando Hibernate.
Hay que mencionar que Hibernate soporta 2 tipos de asociaciones bidireccionales
● one-to-many
● many-to-many
por lo que en las 2 siguientes secciones vamos a tratar la forma en que se manejan estas relaciones por
medio de un ejemplo y vamos a omitir la descripción de los atributos de cada relación.
Padre Hijo
-idPadre -idHijo
1 0..*
En esta relación un objeto Padre puede tener de 0 a muchos Hijos y los Hijos están interesados en
conocer a su respectivo Padre.
Archivo Padre.hbm.xml:
<hibernate-mapping>
<class name=”package.Padre” table=”Padre”>
<id name=”idPadre” type=”int”>
<generator class=”increment”/>
</id>
<!-- Otros atributos del Padre -->
<set name=”hijos” inverse=”true” lazy=”false”>
<key column=”idPadre”/>
<one-to-many class=”package.Hijo”/>
</set>
</class>
</hibernate-mapping>
Archivo Hijo.hbm.xml:
<hibernate-mapping>
<class name=”package.Hijo” table=”Hijo”>
<id name=”idHijo” type=”int”>
<generator class=”increment”/>
</id>
<!-- Otros atributos del Hijo -->
<many-to-one name=”padre” class=”package.Padre” column=”idPadre”/>
</class>
</hibernate-mapping>
Las cosas que cabe hacer notar es que el padre tiene un atributo:
private Set<Hijo> hijos = new HashSet<Hijo>();
y que en el caso del Padre la relación va como one-to-many con inverse = true y que esta relación se
invierte en el Hijo a many-to-one (el hecho de que la relación se invierta de esta forma no tiene nda que
ver con que inverse sea igual a true).
Padre Hijo
-idPadre -idHijo
1..* 0..*
En esta relación un objeto Padre tiene de 0 a muchos Hijos, y los Hijos tienen al menos un Padre
(idealmente solo 2).
Archivo Padre.hbm.xml:
<hibernate-mapping>
<class name="package.Padre">
<id name=”idPadre” type=”int”>
<generator class=”increment”/>
</id>
<!-- Otros atributos del Padre -->
</hibernate-mapping>
Archivo Hijo.hbm.xml:
<hibernate-mapping>
<class name="package.Hijo">
<id name=”idHijo” type=”int”>
<generator class=”increment”/>
</id>
<!-- Otros atributos del Hijo -->
</hibernate-mapping>
Las cosas que cabe hacer notar es que ahora el Hijo tiene un atributo:
y que en ambos casos los identificadores de cada clase se encuentran en una misma tabla (Hijos) que
Hibernate utiliza y administra como indice.
Persona Nombre
-idPersona 1 1
-nombre: Nombre
</hibernate-mapping>
En esta relación el objeto de tipo Nombre es guardado como un valor no como una entidad, por lo que
en la clase no es necesario definir un identificador, pero en la clase Persona se deben definir los getters
y setters para el objeto de tipo Nombre.
El tag component puede tener los atributos de cualquier otro elemento y ademas define un subelemento
llamado <parent> que permite definir una asociación con el objeto que lo contiene. Por ejemplo:
Persona Nombre
1 1
-idPersona -personaNombrada: Persona
-nombre: Nombre
</hibernate-mapping>
Con esto permitimos que desde el objeto de tipo Nombre se pueda tener visibilidad con un objeto de
tipo Persona.
Empleado
-idEmpleado
-nombre
Secretaria Administrador
Hibernate soporta 3 formas de mapear este tipo de asociaciones que describiremos a continuación.
1. Una tabla por clase concreta
Se mapea cada clase de la relación de herencia como una clase concreta normal, en cada clase se
mapean todos los atributos incluyendo los que son heredados. En esta filosofía de mapeado no se
mapean interfaces ni clases abstractas.
Desventajas:
● En las subclases se tienen datos replicados, es decir, que por cada subclase de la relación se
deben repetir los datos que son heredados.
● Los cambios en la superclase afectan a muchas tablas.
Ejemplo de como se mapearía la clase Secretaria con esta estrategia
Archivo Secretaria.hbm.xml:
<hibernate-mapping>
<class name=”package.Secretaria” table=”Secretaria”>
<!-- El identificador y el nombre son los atributos que
hereda de Empleado -->
<id name=”id” type=”int”>
<generator class=”increment”>
</id>
<property name=”nombre” tupe=”string”/>
<!-- Otros atributos de Secretaria -->
</class>
</hibernate-mapping>
<<table>>
Empleado
-idEmpleado
-nombre
<<table>> <<table>>
Secretaria Administrador
Ventajas:
● Es conceptualmente mas fácil de comprender
● No requiere de cambios complejos en la base de datos cuando se modifica a la superclase
Desventajas:
● Puede resultar en un pobre desempeño de la aplicación si la arquitectura del sistema esta mal
planteada.
Ejemplo de mapeo de la clase Administrador empleando esta estrategia
Archivo Administrador.hbm.xml:
<hibernate-mapping>
<joined-subclass name=”package.Administrador” extends=”package.Empleado”>
<!-- Identificador de la clase Empleado -->
<key column=”idEmpleado”>
En esta ocasión sustituimos el tag class por el joined-subclass para establecer una relación directa con
la superclase, en este tag especificamos cual es la clase que extiende y con el tag key hacemos
referencia a los elementos de la superclase que no han sido agregados en este archivo, es decir, no es
necesario redefinir los elementos de idEmpleado y nombre.
El tag joined-subclass no puede contener tags de subclass y viceversa.
<<table>>
Empleado
-idEmpleado
-nombre
-atributosDeSecretria
-atributosDeAdministrador
Ventajas:
● Ofrece un mejor desempeño ya que los queries se realizan en una misma tabla y se puede
recuperar el objeto mas fácilmente.
● Los cambios en los atributo solo requieren del cambio de una columna.
Desventajas:
● No es una buena representación de los atributos en las clases.
● Si el numero de subclases crece también lo hace el numero de columnas.
● Cada subclase debe definir la clase que extiende y su elemento discriminador.
Ejemplo de como se realiza el mapeo con esta estrategia
Archivo Empleado.hbm.xml:
<hibernate-mapping>
<class name="package.Empleado" table="Empleado">
<!-- Identificador de la superclase -->
<id name="idEmpleado" type="int">
<generator class="increment"/>
</id>
<!-- Columna que sirve como discriminador del tipo de subclase -->
<discriminator column="tipoEmpleado" type="string"/>
</class>
</hibernate-mapping>
Referencias
En ingles
● Pro Hibernate 3. Jeff Linwood y Dave Minter. (Este libro se encuentra en books24x7).
● http://www.hibernate.org/hib_docs/reference/en/html/index.html. (Documentación de
Hibernate, esta disponible en otros idiomas menos en español).
● http://anonhibernate.labs.jboss.com/trunk/sandbox/jdbc/src/test/resources/hibernate.properties.
(Da una lista de propiedades para configurar Hibernate con cualquiera de los Manejadores de
Bases de Datos que conoce).
● http://www.hibernate.org/116.html#A8. (FAQ del sitio de Hibernate)
En español
● http://www.javahispano.org/articles.article.action?id=93. (Articulo de Francsec Roses Albiol
sobre Hibernate).
● http://www.programacion.com/java/tutorial/hibernate/. (Tutorial para aprender a manejar
Hibernate).
● http://www.programacion.com/java/articulo/jap_persis_hib/. (Versión en español del articulo
publicado por Jeff Hanson, trata de la persistencia de objetos Java con Hibernate).
● http://www.javahispano.org/articles.article.action?id=95. (Articulo de Martín Pérez Mariñán,
que trata sobre manejo de caches y concurrencia con Hibernate).
● http://www.epidataconsulting.com/tikiwiki/tiki-
pagehistory.php?page=Hibernate&diff2=21&diff_style=sideview&PHPSESSID=8abd9818af16
07b0f7df3a86764d39b7. (Trata sobre problemas de mapeo recursivo de objetos).