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.
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:
1: public class Profesor implements Serializable { 2: private int id; 3: private Nombre nombre; 4: 5: public Profesor(){ 6: } 7: 8: public Profesor(int id, Nombre nombre) { 9: this.id = id; 10: this.nombre=nombre; 11: } 12: } 13: 14: public class Nombre implements Serializable { 15: private String nombre; 16: private String ape1; 17: private String ape2; 18: 19: public Nombre() { 20: 21: } 22: 23: public Nombre(String nombre, String ape1, String ape2) { 24: this.nombre = nombre; 25: this.ape1 = ape1; 26: this.ape2 = ape2; 27: } 28: 29: public String getNombreCompleto() { 30: StringBuilder sb=new StringBuilder(); 31: if ((ape1!=null) && (ape1.trim().length()>0)) { 32: sb.append(ape1); 33: } 34: if ((ape2!=null) && (ape2.trim().length()>0)) { 35: if (sb.length()>0) { 36: sb.append(" "); 37: } 38: sb.append(ape2); 39: } 40: if ((nombre!=null) && (nombre.trim().length()>0)) { 41: if (sb.length()>0) { 42: sb.append(","); 43: } 44: sb.append(nombre); 45: } 46: 47: 48: return sb.toString(); 49: } 50: 51: public String getIniciales() { 52: StringBuilder sb=new StringBuilder(); 53: if ((nombre!=null) && (nombre.trim().length()>0)) { 54: sb.append(nombre.substring(0,1)); 55: } 56: if ((ape1!=null) && (ape1.trim().length()>0)) { 57: sb.append(ape1.substring(0,1)); 58: } 59: if ((ape2!=null) && (ape2.trim().length()>0)) { 60: sb.append(ape2.substring(0,1)); 61: } 62: 63: return sb.toString().toUpperCase(); 64: } 65: }
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
.
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
.
Al persistir las dos clases será necesario un único fichero de persistencia:
Profesor.hbm.xml
El fichero Profesor.hbm.xml
quedará de la siguiente forma:
1: <?xml version="1.0" encoding="UTF-8"?> 2: <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd"> 3: <hibernate-mapping> 4: <class name="ejemplo04.Profesor" > 5: <id column="Id" name="id" type="integer"/> 6: 7: <component name="nombre"> 8: <property name="nombre" /> 9: <property name="ape1" /> 10: <property name="ape2" /> 11: </component> 12: 13: </class> 14: </hibernate-mapping>
El fichero básicamente es muy sencillo excepto por el nuevo tag component
de la línea 7.
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 atributo nombre
.
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: @Entity 2: @Table(name="Profesor") 3: public class Profesor implements Serializable { 4: 5: @Id 6: @Column(name="Id") 7: private int id; 8: @Embedded 9: private Nombre nombre; 10: 11: 12: public Profesor(){ 13: } 14: 15: public Profesor(int id, Nombre nombre) { 16: this.id = id; 17: this.nombre=nombre; 18: } 19: }
En la línea 8 se ha incluido la anotación @Embedded
.
nombre
se guardará en la misma tabla que Profesor
.
La clase Java Nombre
quedará de la siguiente forma:
1: @Embeddable 2: public class Nombre implements Serializable { 3: 4: @Column(name="nombre") 5: private String nombre; 6: 7: @Column(name="ape1") 8: private String ape1; 9: 10: @Column(name="ape2") 11: private String ape2; 12: 13: public Nombre() { 14: 15: } 16: 17: public Nombre(String nombre, String ape1, String ape2) { 18: this.nombre = nombre; 19: this.ape1 = ape1; 20: this.ape2 = ape2; 21: } 22: 23: 24: 25: public String getNombreCompleto() { 26: StringBuilder sb=new StringBuilder(); 27: if ((ape1!=null) && (ape1.trim().length()>0)) { 28: sb.append(ape1); 29: } 30: if ((ape2!=null) && (ape2.trim().length()>0)) { 31: if (sb.length()>0) { 32: sb.append(" "); 33: } 34: sb.append(ape2); 35: } 36: if ((nombre!=null) && (nombre.trim().length()>0)) { 37: if (sb.length()>0) { 38: sb.append(","); 39: } 40: sb.append(nombre); 41: } 42: 43: 44: return sb.toString(); 45: } 46: 47: public String getIniciales() { 48: StringBuilder sb=new StringBuilder(); 49: if ((nombre!=null) && (nombre.trim().length()>0)) { 50: sb.append(nombre.substring(0,1)); 51: } 52: if ((ape1!=null) && (ape1.trim().length()>0)) { 53: sb.append(ape1.substring(0,1)); 54: } 55: if ((ape2!=null) && (ape2.trim().length()>0)) { 56: sb.append(ape2.substring(0,1)); 57: } 58: 59: return sb.toString().toUpperCase(); 60: } 61: }
A nivel de clase se ha incluido en la línea 1 el atributo @Embeddable
.
Ahora que ya tenemos preparadas las clase Java para que puedan persistirse veamos el código necesario para persistirlas.
1: Profesor profesor=new Profesor(410, new Nombre("Gabriel", "Sáez", "Izquierdo")); 2: 3: Session session=sessionFactory.openSession(); 4: session.beginTransaction(); 5: 6: session.save(profesor); 7: 8: session.getTransaction().commit(); 9: session.close();
Como podemos ver, el usar componentes no añade ningún tipo de complejidad al código Java que se usa.
Veamos ahora qué diferencias hay entre crear una relación uno a uno y el uso de componentes.