Herramientas de usuario

Herramientas del sitio


unidades:03_relaciones:04_uno_a_muchos_ordenada

Diferencias

Muestra las diferencias entre dos versiones de la página.


unidades:03_relaciones:04_uno_a_muchos_ordenada [2023/04/07 21:26] (actual) – creado - editor externo 127.0.0.1
Línea 1: Línea 1:
 +====== Uno a muchos (ordenada) ======
 +La relación uno a muchos consiste simplemente en que un objeto //padre// tenga una lista **Ordenar** de otros objetos //hijo// de forma que al persistirse el objeto principal también se persista la lista de objetos //hijo//. Esta relación también suele llamarse //maestro-detalle// o //padre-hijo//.
  
 +
 +===== Clases Java =====
 +Antes de entrar en cómo se implementa en Hibernate , veamos las clases Java y las tablas que definen la relación uno a muchos. 
 +
 +Para nuestro ejemplo vamos a usar las clases:
 +  * ''Profesor''
 +  * ''CorreoElectronico''
 +
 +Estas dos clases van a tener una relación uno a muchos.
 +
 +<code java 1 | Listado 1.Relación 1 a n>
 +public class Profesor implements Serializable  {
 +    private int id;
 +    private String nombre;
 +    private String ape1;
 +    private String ape2;
 +    private List<CorreoElectronico> correosElectronicos;
 +    
 +
 +    public Profesor(){ 
 +    }
 +
 +    public Profesor(int id, String nombre, String ape1, String ape2) {
 +        this.id = id;
 +        this.nombre = nombre;
 +        this.ape1 = ape1;
 +        this.ape2 = ape2;
 +    }
 +    
 +}
 +
 +public class CorreoElectronico implements Serializable {
 +    private int idCorreo;
 +    private String direccionCorreo;
 +    private Profesor profesor;
 +    
 +    public CorreoElectronico() {
 +        
 +    }
 +    
 +    public CorreoElectronico(int idCorreo,String direccionCorreo,Profesor profesor) {
 +        this.idCorreo=idCorreo;
 +        this.direccionCorreo=direccionCorreo;
 +        this.profesor=profesor;
 +    }
 +}
 +</code>
 +
 +
 +En el listado 1 podemos ver cómo la clase ''Profesor'' tiene una propiedad llamada ''correosElectronicos'' de la clase ''CorreoElectronico'' (línea 6) y además la clase ''CorreoElectronico'' también posee referencia a ''Profesor'' ya que hemos definido que la relación es bidireccional desde ''Profesor'' hacia ''Direccion'' y viceversa.
 +
 +El mecanismo que usamos en Java para almacenar una serie de objetos //hijo// es el interfaz <javadoc jdk7>java.util.List|List</javadoc>. Se utiliza este interfaz ya que nos va a permitir que los objetos //hijo// se encuentren ordenados.
 +
 +<note important>En la clases Java ''Profesor'' y ''CorreoElectronico'' no se han incluido los métodos get/set de cada propiedad para facilitar la lectura pero deben estar en la clase Java.</note>
 +
 +En el siguiente diagrama UML se ve  la relación desde ''Profesor'' hacia ''CorreoElectronico'' y viceversa.
 +
 +<uml>
 +class Profesor 
 +Profesor : int id
 +Profesor : String nombre
 +Profesor : String ape1
 +Profesor : String ape2
 +
 +
 +class CorreoElectronico
 +CorreoElectronico: int idCorreo
 +CorreoElectronico: String direccionCorreo
 +
 +
 +Profesor "1" -- "0..n" CorreoElectronico: correosElectronicos {Ordenada}
 +</uml>
 +
 +
 +===== Tablas =====
 +La tablas de base de datos quedarían de la siguiente forma:
 +
 +<uml>
 +class Profesor <<Table>>
 +Profesor : INTEGER id
 +Profesor : VARCHAR nombre
 +Profesor : VARCHAR ape1
 +Profesor : VARCHAR ape2
 +
 +
 +class CorreoElectronico <<Table>>
 +CorreoElectronico: INTEGER idCorreo
 +CorreoElectronico: VARCHAR direccionCorreo
 +CorreoElectronico: INTEGER idProfesor
 +CorreoElectronico: INTEGER idx
 +
 +
 +Profesor "1" -- "0..n" CorreoElectronico
 +</uml>
 +
 +Podemos ver cómo la tabla ''CorreoElectronico'' contiene como clave ajena la clave primaria de la tabla ''Profesor'' y de esa forma se establece la relación uno a muchos.
 +
 +<note important>Se ha añadido la columna ''idx'' la cual almacenará el orden de los objetos ''hijos'' dentro de la lista. Sin esta columna sería imposible posteriormente saber el orden en el que se encontraban los elementos.</note>
 +
 +===== Fichero de mapeo ''.hbm.xml'' =====
 +Al persistir dos clases serán necesarios dos ficheros de persistencia:
 +  * ''Profesor.hbm.xml''
 +  * ''CorreoElectronico.hbm.xml''
 +
 +==== Profesor.hbm.xml ====
 +
 +
 +El fichero ''Profesor.hbm.xml'' quedará de la siguiente forma
 +
 +<code xml 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="ejemplo05.Profesor" >
 +    <id column="Id" name="id" type="integer"/>
 +    <property name="nombre" />
 +    <property name="ape1" />
 +    <property name="ape2" />
 +    
 +    <list name="correosElectronicos"  cascade="all" inverse="false"  >
 +        <key>
 +            <column name="idProfesor"  />
 +        </key> 
 +        <list-index>
 +            <column name="Idx"  />
 +        </list-index>
 +        <one-to-many class="ejemplo07.CorreoElectronico" />
 +    </list>
 +  </class>
 +</hibernate-mapping>
 +</code>
 +
 +El fichero básicamente contiene lo que se ha explicado en las lecciones anteriores excepto por el tag ''<list>'' (líneas 10 a 17).
 +
 +=== Tag list ===
 +El tag ''<list>'' se utiliza para definir una relación //uno a muchos// entre las dos clases Java en las cuales hay un orden. 
 +
 +== Atributos ==
 +  * **name**: Es el nombre de la propiedad Java del tipo <javadoc jdk7>java.util.Set|Set</javadoc> en la cual se almacenan todos los objetos //hijos//.En nuestro ejemplo el valor es ''correosElectronicos'' ya que es la propiedad que contiene el <javadoc jdk7>java.util.Set|Set</javadoc>.
 +  * **cascade**: Como ya hemos explicado en anteriores lecciones, este atributo indica que se realizan las mismas operaciones con el objeto //padre// que con los objetos //hijos//, es decir si un se borra los otros también, etc. Su valor habitual es ''all''.Mas información en [[unidades:03_relaciones:06_cascade]].
 +  * **inverse**: En este caso el atributo ''inverse'' debe tener el valor ''false'' ya que de esa forma se guardará en valor del orden de cada objeto. Si se estableciera a ''true'' no se guardaría el valor.
 +
 +<note important>Recuerda poner el valor del atributo ''inverse'' a ''false''
 +
 +
 +  inverse="false"
 +
 +
 +</note>
 +
 +== Tags anidados ==
 +  * **key** Este tag contiene otro anidado llamado ''column'' con el atributo ''name'' que indica el nombre de una columna de la base de datos. Esta columna debe ser de la tabla //hijo// y ser el nombre de la clave ajena a la tabla //padre//. En nuestro ejemplo es ''idProfesor'' ya que es el nombre de la clave ajena en la tabla ''CorreoElectronico''.
 +  * **list-index** Este tag contiene otro anidado llamado ''column'' con el atributo ''name'' que indica el nombre de una columna de la base de datos. Esta columna debe ser de la tabla //hijo// y ser la columna donde se guarda el **orden** que ocupa dentro de la lista. En nuestro ejemplo es ''idx''.
 +  * **one-to-many** Este tag contiene el atributo ''class'' con el FQCN de la clase Java //hija//. En nuestro ejemplo es el nombre de la clase ''CorreoElectronico'' cuyo FQCN es ''ejemplo05.CorreoElectronico''.
 +
 +<note>
 +Podemos pensar que el valor del atributo ''class'' en el tag ''one-to-many'' sea opcional ya que hibernate podría ser capaz de deducirlo como ha hecho en otras ocasiones, sin embargo no es así. En caso de no indicarlo se producirá la siguiente excepción:
 +
 +  org.hibernate.MappingException: Association references unmapped class: null
 +  
 +</note> 
 +==== CorreoElectronico.hbm.xml ====
 +
 +El fichero ''CorreoElectronico.hbm.xml'' quedará de la siguiente forma:
 +<code xml 1| Fichero CorreoElectronico.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="ejemplo05.CorreoElectronico" >
 +    <id column="IdCorreo" name="idCorreo" type="integer"/>
 +    <property name="direccionCorreo" />
 +
 +
 +    <many-to-one name="profesor">
 +            <column name="idProfesor"  />
 +    </many-to-one>
 +
 +
 +  </class>
 +</hibernate-mapping>
 +</code>
 +
 +El fichero básicamente contiene lo que se ha explicado en las lecciones anteriores excepto por el tag ''<many-to-one>'' (líneas 9 a 11).
 +
 +=== Tag many-to-one ===
 +El tag ''<many-to-one>'' se utiliza para definir una relación //muchos a uno// entre las dos clases Java. 
 +
 +== Atributos ==
 +  * **name**: Es el nombre de la propiedad Java que enlaza con el objeto //padre//. En nuestro ejemplo el valor es ''profesor'' ya que es la propiedad que contiene la referencia a la clase ''Profesor''.
 +
 +== Tags anidados ==
 +  * **column ** Este tag contiene el atributo ''name'' que indica el nombre de una columna de la base de datos. Esta columna debe ser de la tabla //hijo// y ser el nombre de la clave ajena a la tabla //padre//. En nuestro ejemplo es ''idProfesor'' ya que es el nombre de la clave ajena en la tabla ''CorreoElectronico''.
 +
 +===== Anotaciones =====
 +Para usar notaciones 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:
 +
 +<code java 1 | Clase profesor anotada>
 +@Entity
 +@Table(name="Profesor")
 +public class Profesor implements Serializable  {
 +    
 +    @Id
 +    @Column(name="Id")
 +    private int id;
 +    
 +    @Column(name="nombre")
 +    private String nombre;
 +    
 +    @Column(name="ape1")
 +    private String ape1;
 +    
 +    @Column(name="ape2"   
 +    private String ape2;
 +    
 +    @OneToMany(cascade= CascadeType.ALL)
 +    @JoinColumn(name="IdProfesor")
 +    @IndexColumn(name="idx")
 +    private List<CorreoElectronico> correosElectronicos;
 +    
 +
 +    public Profesor(){ 
 +    }
 +
 +    public Profesor(int id, String nombre, String ape1, String ape2) {
 +        this.id = id;
 +        this.nombre = nombre;
 +        this.ape1 = ape1;
 +        this.ape2 = ape2;
 +    }
 +}
 +</code>
 +
 +A la propiedad ''correosElectronicos'' se ha añadido una anotación para indicar la relación //uno a muchos//.
 +  * **OneToMany**:Como su nombre indica le dice a Hibernate que esta propiedad contendrá la lista de //hijos//.
 +      * **cascade**: Este atributo tiene el mismo significado que el del fichero de mapeo de Hibernate. Mas información en [[unidades:03_relaciones:06_cascade]].
 +  * **JoinColumn**: Indicaremos el nombre de la columna que en la tabla //hija// contiene la clave ajena a la tabla //padre//. En nuestro ejemplo es la columna de la base de datos ''IdProfesor'' que se encuentra en la tabla ''CorreoElectronico'' la cual enlaza con la tabla ''Profesor''.
 +  * **IndexColumn**: Indicaremos el nombre de la columna que en la tabla //hija// contiene el orden dentro de la lista de //hijos//. En nuestro ejemplo es la columna de la base de datos ''idx'' que se encuentra en la tabla ''CorreoElectronico''.
 +
 +El código de la clase CorreoElectronico es el siguiente:
 +<code java 1 | Clase CorreoElectronico anotada>
 +@Entity
 +@Table(name="CorreoElectronico")
 +public class CorreoElectronico implements Serializable {
 +    
 +    @Id
 +    @Column(name="IdCorreo"   
 +    private int idCorreo;
 +    
 +    @Column(name="DireccionCorreo")
 +    private String direccionCorreo;
 +    
 +    @ManyToOne
 +    @JoinColumn(name="IdProfesor")
 +    private Profesor profesor;
 +    
 +    public CorreoElectronico() {
 +        
 +    }
 +    
 +    public CorreoElectronico(int idCorreo,String direccionCorreo,Profesor profesor) {
 +        this.idCorreo=idCorreo;
 +        this.direccionCorreo=direccionCorreo;
 +        this.profesor=profesor;
 +    }
 +}
 +</code>
 +
 +A la propiedad ''profesor'' se han añadido dos anotaciones para indicar la relación:
 +  * **ManyToOne**:Al ser el otro lado de la relación indicamos que desde este lado es una relación //mucho a uno//.
 +  * **JoinColumn**: Indicaremos el nombre de la columna que en la tabla //hija// contiene la clave ajena a la tabla //padre//. En nuestro ejemplo es la columna de la base de datos ''IdProfesor'' que se encuentra en la tabla ''CorreoElectronico'' la cual enlaza con la tabla ''Profesor''.
 +====== Código Java ======
 +Ahora que ya tenemos preparadas las clase Java para que puedan persistirse veamos el código necesario para persistirlas.
 +
 +<code java 1 | Persistiendo la clase Profesor>
 +Profesor profesor=new Profesor(9, "Rosa", "Díaz", "Del Toro");
 +List<CorreoElectronico> correosElectronicos=new ArrayList<>();
 +correosElectronicos.add(new CorreoElectronico(3, "rosa@yahoo.com",profesor));
 +correosElectronicos.add(new CorreoElectronico(2, "rosa@hotmail.com",profesor));
 +correosElectronicos.add(new CorreoElectronico(1, "rosa@gmail.com",profesor));
 +
 +profesor.setCorreosElectronicos(correosElectronicos);
 +
 +Session session=sessionFactory.openSession();
 +session.beginTransaction();
 +
 +session.save(profesor);
 +
 +session.getTransaction().commit();
 +session.close();
 +</code>
 +
 +La explicación del código es la siguiente:
 +  * En la línea 1 se crea el objeto ''Profesor''
 +  * En la segunda línea se crea el objeto <javadoc jdk7>java.util.ArrayList|ArrayList</javadoc> que implementa el interfaz <javadoc jdk7>java.util.List|List</javadoc> el cual contendrá la lista de hijos.
 +  * Desde las líneas 3 a la 5 se crean los objetos ''CorreoElectronico'' y se añaden al <javadoc jdk7>java.util.List|List</javadoc>.
 +  * En la línea 7 se establece la relación entre la lista de hijos (''CorreoElectronico'' y el padre (''Profesor'').
 +  * En la línea 12 se guarda el objeto ''Profesor'' y automáticamente se guardan también sus hijos.