====== 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 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. En la clases Java ''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''. class Profesor Profesor : int id class Nombre Nombre : String nombre Nombre : String ape1 Nombre : String ape2 Nombre : getNombreCompleto() Nombre : getIniciales() Profesor "1" --> "1" Nombre : nombre ===== Tablas ===== La tabla de base de datos quedaría de la siguiente forma: class Profesor <> Profesor : INTEGER id Profesor : VARCHAR nombre Profesor : VARCHAR ape1 Profesor : VARCHAR ape2 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: El fichero básicamente es muy sencillo excepto por el nuevo tag ''component'' de la línea 7. === Tag component === El tag '''' 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''. ===== 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: @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 que ''Profesor''. La clase Java ''Nombre'' quedará de la siguiente forma: @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. 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 [[unidades:03_relaciones:01_uno_a_uno_direccional|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.