Tabla de Contenidos

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:

Estas dos clases van a tener una relación uno a muchos.

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;
    }
}

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 List. Se utiliza este interfaz ya que nos va a permitir que los objetos hijo se encuentren ordenados.

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.

En el siguiente diagrama UML se ve la relación desde Profesor hacia CorreoElectronico y viceversa.


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}

Tablas

La tablas de base de datos quedarían de la siguiente forma:


class Profesor <>
Profesor : INTEGER id
Profesor : VARCHAR nombre
Profesor : VARCHAR ape1
Profesor : VARCHAR ape2


class CorreoElectronico <
>
CorreoElectronico: INTEGER idCorreo
CorreoElectronico: VARCHAR direccionCorreo
CorreoElectronico: INTEGER idProfesor
CorreoElectronico: INTEGER idx


Profesor "1" -- "0..n" CorreoElectronico

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.

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.

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

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>

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 Set en la cual se almacenan todos los objetos hijos.En nuestro ejemplo el valor es correosElectronicos ya que es la propiedad que contiene el Set.
  • 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 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.
Recuerda poner el valor del atributo inverse a false
inverse="false"
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.
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

CorreoElectronico.hbm.xml

El fichero CorreoElectronico.hbm.xml quedará de la siguiente forma:

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>

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:

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;
    }
}

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 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:

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;
    }
}

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.

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();

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 ArrayList que implementa el interfaz List 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 List.
  • 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.