Tabla de Contenidos
Componentes
Los componentes permiten que varias clases relacionadas se almacenen en una única tabla de la base de datos. Es similar a la relación uno a uno desde el punto de vista de Java pero en la base de datos sólo hay una tabla.
Clases Java
Antes de entrar en cómo se implemente en Hibernate , veamos las clases Java y las tablas que definen la relación.
Para nuestro ejemplo vamos a usar las clases:
- Profesor
- Nombre
- 1
public class Profesor implements Serializable { private int id; private Nombre nombre; public Profesor(){ } public Profesor(int id, Nombre nombre) { this.id = id; this.nombre=nombre; } } public class Nombre implements Serializable { private String nombre; private String ape1; private String ape2; public Nombre() { } public Nombre(String nombre, String ape1, String ape2) { this.nombre = nombre; this.ape1 = ape1; this.ape2 = ape2; } public String getNombreCompleto() { StringBuilder sb=new StringBuilder(); if ((ape1!=null) && (ape1.trim().length()>0)) { sb.append(ape1); } if ((ape2!=null) && (ape2.trim().length()>0)) { if (sb.length()>0) { sb.append(" "); } sb.append(ape2); } if ((nombre!=null) && (nombre.trim().length()>0)) { if (sb.length()>0) { sb.append(","); } sb.append(nombre); } return sb.toString(); } public String getIniciales() { StringBuilder sb=new StringBuilder(); if ((nombre!=null) && (nombre.trim().length()>0)) { sb.append(nombre.substring(0,1)); } if ((ape1!=null) && (ape1.trim().length()>0)) { sb.append(ape1.substring(0,1)); } if ((ape2!=null) && (ape2.trim().length()>0)) { sb.append(ape2.substring(0,1)); } return sb.toString().toUpperCase(); } }
Lo que hemos hecho es extraer las propiedades nombre
, ape1
y ape2
en una nueva clase llamada Nombre
. ¿Para qué hacer este cambio? Para justificarlo hemos añadido los métodos getNombreCompleto()
y getIniciales()
. Si no creáramos la nueva clase Nombre
sería necesario volver a crear estos métodos en cualquier otra entidad que necesite el nombre.
Profesor
y Nombre
no se han incluido los métodos get/set de cada propiedad para facilitar la lectura pero deben estar en la clase Java.
En el siguiente diagrama UML se ve que la relación es desde Profesor
hacia Nombre
.
Tablas
La tabla de base de datos quedaría de la siguiente forma:
Podemos apreciar que en el diseño de las tabla de la base de datos no existe ninguna tabla Nombre
aunque sí que existe la clase Java Nombre
.
Fichero de mapeo ''.hbm.xml''
Al persistir las dos clases será necesario un único fichero de persistencia:
Profesor.hbm.xml
Profesor.hbm.xml
El fichero Profesor.hbm.xml
quedará de la siguiente forma:
- 1| Fichero Profesor.hbm.xml
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> <hibernate-mapping> <class name="ejemplo04.Profesor" > <id column="Id" name="id" type="integer"/> <component name="nombre"> <property name="nombre" /> <property name="ape1" /> <property name="ape2" /> </component> </class> </hibernate-mapping>
El fichero básicamente es muy sencillo excepto por el nuevo tag component
de la línea 7.
Tag component
El tag <component>
se utiliza para especificar que la propiedad Java de la clase se persistirá en la propia tabla de la clase principal. En su forma más sencilla contiene sólo un atributo:
name
:Este atributo contiene el nombre de la propiedad Java con la referencia al otro objeto con el que forma la relación. En nuestro ejemplo es el atributonombre
.
Anotaciones
Para usar anotaciones deberemos modificar el código fuente de las clases Java y no usar los ficheros .hbm.xml
.
El código fuente de la clase Profesor
queda de la siguiente forma:
- 1| Clase Profesor anotada
@Entity @Table(name="Profesor") public class Profesor implements Serializable { @Id @Column(name="Id") private int id; @Embedded private Nombre nombre; public Profesor(){ } public Profesor(int id, Nombre nombre) { this.id = id; this.nombre=nombre; } }
En la línea 8 se ha incluido la anotación @Embedded
.
- @Embedded: Esta anotación se usa para indicar que la propiedad
nombre
se guardará en la misma tabla queProfesor
.
La clase Java Nombre
quedará de la siguiente forma:
- 1| Clase Nombre anotada
@Embeddable public class Nombre implements Serializable { @Column(name="nombre") private String nombre; @Column(name="ape1") private String ape1; @Column(name="ape2") private String ape2; public Nombre() { } public Nombre(String nombre, String ape1, String ape2) { this.nombre = nombre; this.ape1 = ape1; this.ape2 = ape2; } public String getNombreCompleto() { StringBuilder sb=new StringBuilder(); if ((ape1!=null) && (ape1.trim().length()>0)) { sb.append(ape1); } if ((ape2!=null) && (ape2.trim().length()>0)) { if (sb.length()>0) { sb.append(" "); } sb.append(ape2); } if ((nombre!=null) && (nombre.trim().length()>0)) { if (sb.length()>0) { sb.append(","); } sb.append(nombre); } return sb.toString(); } public String getIniciales() { StringBuilder sb=new StringBuilder(); if ((nombre!=null) && (nombre.trim().length()>0)) { sb.append(nombre.substring(0,1)); } if ((ape1!=null) && (ape1.trim().length()>0)) { sb.append(ape1.substring(0,1)); } if ((ape2!=null) && (ape2.trim().length()>0)) { sb.append(ape2.substring(0,1)); } return sb.toString().toUpperCase(); } }
A nivel de clase se ha incluido en la línea 1 el atributo @Embeddable
.
- @Embeddable:Se usa para indicar que esta clase se usará como un componente y que se guardará en la misma tabla que la clase que la posee.
Código Java
Ahora que ya tenemos preparadas las clase Java para que puedan persistirse veamos el código necesario para persistirlas.
- 1 | Persistiendo la clase Profesor
Profesor profesor=new Profesor(410, new Nombre("Gabriel", "Sáez", "Izquierdo")); Session session=sessionFactory.openSession(); session.beginTransaction(); session.save(profesor); session.getTransaction().commit(); session.close();
Como podemos ver, el usar componentes no añade ningún tipo de complejidad al código Java que se usa.
Diferencias
Veamos ahora qué diferencias hay entre crear una relación uno a uno y el uso de componentes.
- En una relación uno a uno las 2 clases Java se almacenan en tablas distintas mientras que en un componente lo hace en la misma tabla.
- En una relación uno a uno las 2 clases Java deben incluir la referencia a la clave primaria que ambas comparten mientras que en un componente sólo necesita clave primaria la clase principal y no el componente.
- En una relación uno a uno es posible persistir cualquiera de las 2 clases y se guardará la otra pero en un componente sólo se puede persistir la clase principal y no el componente.