Uno a muchos (desordenada)
La relación uno a muchos consiste simplemente en que un objeto padre tenga una lista sin 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.
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 Set< 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 Set . No vamos a usar el interfaz List o un array ya que dichas formas implican un orden de los objetos hijo mientras que usando un
Set no hay ningún tipo de orden. En la siguiente lección se explica cómo usar una lista ordenada de objetos hijo .
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 que la relación desde Profesor
hacía 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
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
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.
Fichero de mapeo ''.hbm.xml''
Al persistir dos clases serán necesarios dos ficheros de persistencia:
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" />
<set name ="correosElectronicos" cascade ="all" inverse ="true" >
<key>
<column name ="idProfesor" />
</key>
<one-to-many class ="ejemplo05.CorreoElectronico" />
</set>
</class>
</hibernate-mapping>
El fichero básicamente contiene lo que se ha explicado en las lecciones anteriores excepto por el tag <set>
(líneas 10 a 15).
Tag set
El tag <set>
se utiliza para definir una relación uno a muchos desordenada entre las dos clases Java.
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 uno se borra los otros también, etc. Su valor habitual es all
.
inverse : Este atributo se utiliza para minimizar las SQLs que lanza Hibernate contra la base de datos.En este caso concreto debe establecerse a true
para evitar una sentencia SQL de UPDATE
por cada hijo . Al final de esta sesión se indican enlaces donde intentan explicar (desde mi punto de vista con poco éxito) el funcionamiento del atributo inverse
.
Mas información sobre el atributo
cascade
en
Cascade
La documentación de hibernate no ayuda mucho a entender el atributo
inverse
.Se muestran a continuación algunas explicaciones que se dan sobre ello:
Marks this collection as the “inverse” end of a bidirectional association.
For you, and for Java, a bi-directional link is simply a matter of setting the references on both sides correctly. Hibernate, however, does not have enough information to correctly arrange SQL INSERT and UPDATE statements (to avoid constraint violations). Making one side of the association inverse tells Hibernate to consider it a mirror of the other side. That is all that is necessary for Hibernate to resolve any issues that arise when transforming a directional navigation model to a SQL database schema. The rules are straightforward: all bi-directional associations need one side as inverse. In a one-to-many association it has to be the many-side, and in many-to-many association you can select either side.
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
.
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
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( mappedBy= "profesor" ,cascade= CascadeType.ALL )
private Set< 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 .
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 muchos 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( 7 , "Sara" , "Barrrera" , "Salas" ) ;
Set< CorreoElectronico> correosElectronicos= new HashSet<> ( ) ;
correosElectronicos.add ( new CorreoElectronico( 3 , "sara@yahoo.com" ,profesor) ) ;
correosElectronicos.add ( new CorreoElectronico( 2 , "sara@hotmail.com" ,profesor) ) ;
correosElectronicos.add ( new CorreoElectronico( 1 , "sara@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
HashSet que implementa el interfaz
Set 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
Set .
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.
Referencias
unidades/03_relaciones/03_uno_a_muchos_desordenada.txt · Última modificación: 2023/04/07 21:26 por 127.0.0.1
Herramientas de la página