Herramientas de usuario

Herramientas del sitio


unidades:03_relaciones:01_uno_a_uno_direccional

Diferencias

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


unidades:03_relaciones:01_uno_a_uno_direccional [2023/04/07 21:26] (actual) – creado - editor externo 127.0.0.1
Línea 1: Línea 1:
 +====== Uno a uno (unidireccional) ======
 +La relación uno a uno en Hibernate consiste simplemente en que un objeto tenga una referencia a otro objeto de forma que al persistirse el primer objeto también se persista el segundo.
  
 +En esta lección la relación va a ser unidireccional es decir que que la relación //uno a uno// va a ser en un único sentido.
 +
 +===== Clases Java =====
 +Antes de entrar en cómo se implemente en Hibernate , veamos las clases Java y las tablas que definen la relación uno a uno. 
 +
 +Para nuestro ejemplo vamos a usar las clases:
 +  * ''Profesor''
 +  * ''Direccion''
 +
 +Estas dos clases van a tener una relación uno a uno.
 +
 +<code java 1 | Listado 1.Relación 1 a 1>
 +public class Profesor implements Serializable  {
 +    private int id;
 +    private String nombre;
 +    private String ape1;
 +    private String ape2;
 +    private Direccion direccion;
 +    
 +    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 Direccion implements Serializable  {
 +    private int id;
 +    private String calle;
 +    private int numero;
 +    private String poblacion;
 +    private String provincia;
 +    
 +    public Direccion(){ 
 +    }
 +
 +    public Direccion(int id, String calle, int numero, String poblacion, String provincia) {
 +        this.id = id;
 +        this.calle = calle;
 +        this.numero = numero;
 +        this.poblacion = poblacion;
 +        this.provincia = provincia;
 +    }    
 +}
 +
 +</code>
 +
 +En el listado 1 podemos ver cómo la clase ''Profesor'' tiene una propiedad llamada ''direccion'' de la clase ''Direccion'' (línea 6), mientras que la clase ''Direccion'' no posee ninguna referencia a ''Profesor'' ya que hemos definido una direccionalidad desde ''Profesor'' hacia ''Direccion'' pero no al revés.
 +
 +<note important>En la clases Java ''Profesor'' y ''Direccion'' 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 que la relación es solo desde ''Profesor'' hacia ''Direccion''.
 +
 +<uml>
 +class Profesor 
 +Profesor : int id
 +Profesor : String nombre
 +Profesor : String ape1
 +Profesor : String ape2
 +
 +
 +class Direccion
 +Direccion : int id
 +Direccion : String calle
 +Direccion : int numero
 +Direccion : String poblacion
 +Direccion : String provincia
 +
 +Profesor "1" --> "0..1" Direccion : direccion
 +</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 Direccion <<Table>>
 +Direccion : INTEGER id
 +Direccion : VARCHAR calle
 +Direccion : INTEGER numero
 +Direccion : VARCHAR poblacion
 +Direccion : VARCHAR provincia
 +
 +Profesor "1" -- "0..1" Direccion
 +</uml>
 +
 +Podemos apreciar que en el diseño de las tabla de la base de datos ya no existe una columna en ''Profesor'' con la clave primaria de ''Direccion'' ya que si la hubiera sería una relación //muchos a uno//. Entonces ¿cómo se establece la relación entre las dos filas? Simplemente porque tanto ''Profesor'' como ''Direccion'' **deben tener** la misma clave primaria y de esa forma se establece la relación.
 +
 +===== Fichero de mapeo ''.hbm.xml'' =====
 +Al persistir dos clases serán necesarios dos ficheros de persistencia:
 +  * ''Profesor.hbm.xml''
 +  * ''Direccion.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="ejemplo01.Profesor" >
 +    <id column="Id" name="id" type="integer"/>
 +    <property name="nombre" />
 +    <property name="ape1" />
 +    <property name="ape2" />
 +    
 +    <one-to-one name="direccion" cascade="all" />
 +
 +  </class>
 +</hibernate-mapping>
 +</code>
 +
 +El fichero básicamente contiene lo que se ha explicado en las lecciones anteriores excepto por el tag ''<one-to-one>'' de la línea 10.
 +
 +=== Tag one-to-one ===
 +El tag ''<one-to-one>'' se utiliza para definir una relación //uno a uno// entre las dos clases Java. En su forma más sencilla contiene sólamente dos atributos:
 +  * ''name'':Este atributo contiene el nombre de la propiedad Java con la referencia al otro objeto con el que forma la relación //uno a uno//. En nuestro ejemplo es el atributo ''direccion''.
 +  * ''cascade'': Este atributo indicará a hibernate cómo debe actuar cuando realicemos las operaciones de persistencia de guardar, borrar, leer, etc. En el ejemplo el valor debe ser ''all'' indicando que deberemos realizar la misma operación en ''Profesor'' que en''Direccion''.
 +
 +<note>Mas información sobre el atributo ''cascade'' en [[unidades:03_relaciones:06_cascade]]</note>
 +==== Direccion.hbm.xml ====
 +
 +El fichero ''Direccion.hbm.xml'' quedará de la siguiente forma:
 +<code xml 1| Fichero Direccion.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="ejemplo01.Direccion" >
 +    <id column="Id" name="id" type="integer"/>
 +    <property name="calle"/>
 +    <property name="numero"/>
 +    <property name="poblacion"/>
 +    <property name="provincia"/>
 +    
 +  </class>
 +</hibernate-mapping>
 +</code>
 +
 +En el fichero ''Direccion.hbm.xml'' no hay ninguna información relativa a la relación //uno a uno// puesto que en nuestro ejemplo la relación //uno a uno// tiene una direccionalidad desde ''Profesor'' hasta ''Direccion'' por lo tanto ''Direccion'' no sabe nada sobre ''Profesor'' y por ello en su fichero de persistencia no hay nada relativo a dicha relación.
 +===== 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 >
 +import java.io.Serializable;
 +import javax.persistence.*;
 +
 +
 +@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;
 +    
 +    @OneToOne(cascade=CascadeType.ALL)
 +    @PrimaryKeyJoinColumn
 +    private Direccion direccion;
 +}
 +</code>
 +
 +A la propiedad ''direccion'' (línea 24) se han añadido dos anotaciones para indicar la relación //uno a uno// y que ésta relación se implemente mediante la clave primaria.
 +  * **@OneToOne(cascade=CascadeType.ALL)**: Esta anotación indica la relación //uno a uno// de las 2 tablas. Tambien indicamos el valor de ''cascade'' al igual que en el fichero de hibernate.
 +  * **@PrimaryKeyJoinColumn**: Indicamos que la relación entre las dos tablas se realiza mediante la clave primaria.
 +<note tip>En caso de no incluir la anotación ''@PrimaryKeyJoinColumn'' se producirá un error indicando que falta la columna ''direccion_Id'' en la tabla ''Profesor''. </note>
 +<note tip>Nótese que si utilizamos anotaciones en necesario usar ''@PrimaryKeyJoinColumn'' mientras que usando el fichero ''.hbm.xml'' no es necesario indicarlo.</note>
 +
 +<note>Más información sobre el atributo ''cascade'' en [[unidades:03_relaciones:06_cascade]]</note>
 +
 +En código de ''Direccion'' no es necesario indicar nada sobre la relación tal y como hemos explicado en el caso del fichero de hibernate.
 +
 +<code java 1 | Clase Direccion anotada >
 +import java.io.Serializable;
 +import javax.persistence.Column;
 +import javax.persistence.Entity;
 +import javax.persistence.Id;
 +import javax.persistence.Table;
 +
 +
 +@Entity
 +@Table(name="Direccion")
 +public class Direccion implements Serializable  {
 +
 +    @Id
 +    @Column(name="Id")
 +    private int id;
 +    
 +    @Column(name="calle")
 +    private String calle;
 +    
 +    @Column(name="numero")
 +    private int numero;
 +    
 +    @Column(name="poblacion")
 +    private String poblacion;
 +    
 +    @Column(name="provincia")
 +    private String provincia;
 +}
 +</code>
 +====== 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>
 +        Direccion direccion=new Direccion(1, "Plaza del ayuntamiento", 8, "Xativa", "Valencia");
 +        Profesor profesor=new Profesor(1, "Juan", "Perez", "García");
 +        profesor.setDireccion(direccion);
 +        
 +        Session session=sessionFactory.openSession();
 +        session.beginTransaction();
 +        
 +        session.save(profesor);
 +        
 +        session.getTransaction().commit();
 +        session.close();
 +</code>
 +
 +Como podemos ver no hay **nada** nuevo en el código Java para persistir una relación //uno a uno//, simplemente creamos las 2 clases (Líneas 1 y 2) y establecemos la relación entre ambas asignando al objeto ''Profesor'' la referencia al objeto ''Direccion'' (Línea 3). Por último, simplemente persistimos la clase ''Profesor'' tal y como se ha explicado anteriormente.
 +
 +Al ejecutar el ejemplo Hibernate vemos cómo se han creado las  filas en las tablas ''Profesor'' y ''Direccion'' mientras que desde Java solo se ha persistido la clase ''Profesor''.
 +
 +
 +Si vemos el log que se genera al persistir los 2 objetos , podemos ver que se realiza primero una orden ''SELECT'' contra la  tabla ''Direccion'' para comprobar si ya existe la dirección en la base de datos. Ésto lo realiza hibernate ya que si ya existe no es necesario insertar la fila de la dirección pero si la fila ya existe pero los datos son distintos, hibernate lanzará un ''UPDATE'' para modificarlos.
 +
 +<note important>
 +Recuerda que la clave primaria de ''Direccion'' y ''Profesor'' debe ser la misma para que se establezca correctamente la relación.
 +</note>