Tabla de Contenidos

Mapeo de una Entidad

Una entidad va a ser una simple clase Java que deseamos persistir en la base de datos.

Este tutorial está dividido en 3 partes:

La clase Java

La clases Java deberán tener las siguientes características:

1|Profesor.java
public class Profesor implements Serializable  {
    private int id;
    private String nombre;
    private String ape1;
    private String ape2;   
 
    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 int getId() {
        return id;
    }
 
    public void setId(int id) {
        this.id = id;
    }
 
    public String getNombre() {
        return nombre;
    }
 
    public void setNombre(String nombre) {
        this.nombre = nombre;
    }
 
    public String getApe1() {
        return ape1;
    }
 
    public void setApe1(String ape1) {
        this.ape1 = ape1;
    }
 
    public String getApe2() {
        return ape2;
    }
 
    public void setApe2(String ape2) {
        this.ape2 = ape2;
    }
}

Vemos en el código fuente cómo la clase Profesor tiene un constructor sin ningún tipo de argumentos (Linea 7). Además para las propiedades id,nombre,ape1 y ape2 están el par de métodos get y set y por último implementa el interfaz Serializable (Línea 1).

¿Ya podemos persistir la clase Profesor usando hibernate? Pues NO, debemos indicarle a hibernate toda la metainformación relativa a esta clase. Hay que explicarle como se mapeará el objeto en una base de datos relacional 3) , indicando para ello en que tabla de base de datos se debe guardar cuál es la clave primaria de la tabla, las columnas que tiene, etc.

Fichero de mapeo ''.hbm.xml''

Para cada clase que queremos persistir se creará un fichero xml con la información que permitirá mapear la clase a una base de datos relacional. Este fichero estará en el mismo paquete que la clase a persistir.

En nuestro caso, si queremos persistir la clase Profesor deberemos crear el fichero Profesor.hbm.xml en el mismo paquete que la clase Java.

Nada impide que el fichero .hbm.xml esté en otro paquete distinto al de la clase Java. En este sentido suele haber 2 posibilidades:
  1. Almacenar el fichero .hbm.xml en el mismo paquete que la clase Java a la que hace referencia.
  2. Crear un árbol alternativo de paquetes donde almacenar los ficheros .hbm.xml. Por ejemplo, si tenemos el paquete raíz com.miempresa.proyecto.dominio donde se guardan todas las clases Java a persistir, crear otro paquete llamado com.miempresa.proyecto.persistencia donde almacenar los ficheros .hbm.xml.

La ventaja de la segunda opción es que en caso de que no queramos usar Hibernate, simplemente hay que borrar toda la carpeta com.miempresa.proyecto.persistencia y ya está, mientras que la ventaja de la primera opción es que la clase Java y su correspondiente fichero de mapeo están mas juntos facilitando en caso de algún cambio en la clase Java el cambio en el fichero de mapeo.

Mi opinión personal es que es mejor usar la segunda opción ya que quedan más independizadas las clases de negocio del método de persistencia.

1|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" table="Profesor" >
    <id column="Id" name="id" type="integer"/>
    <property name="nombre" />
    <property name="ape1" />
    <property name="ape2" />
  </class>
</hibernate-mapping>

Podemos ver cómo el fichero Profesor.hbm.xml es un típico fichero xml.

Recuerda que usando el atributo column puedes especificar un nombre de columna en la tabla distinto del nombre de la propiedad en la clase Java.
<?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" table="Profesor" >
    <id column="Id" name="id" type="integer"/>
    <property name="nombre"  />
    <property name="ape1" column="primer_apellido" />
    <property name="ape2" column="segundo_apellido" />
  </class>
</hibernate-mapping>
Como podemos apreciar en el DTD http://www.hibernate.org/dtd/hibernate-mapping-3.0.dtd, hay muchos más tags y atributos en los ficheros .hbm.xml pero por ahora simplemente hemos visto lo mas básico. Durante el resto del curso iremos viendo muchas mas opciones de este fichero.
Si buscamos documentación sobre hibernate podemos encontrar que el DOCTYPE antes de la versión 3.6 era 5) :
<!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">

Así que no confundirlo al hacer algún copy-empastre desde algún tutorial de Internet de versiones anteriores.

Hemos comentado que necesitamos los métodos get/set para que hibernate acceda a los campos. Sin embargo nos puede interesar que no estén alguno de esos métodos para que el usuario no pueda cambiar o leer los valores. En ese caso le deberemos decir a Hibernate que acceda directamente a las propiedades privadas, ya que por suerte Hibernate sabe hacerlo.

Para ello modificaremos el fichero .hbm.xml añadiendo el atributo access=“field” a la propiedad sobre la que queremos que acceda directamente.

Por ejemplo si no quisieramos tener un getNombre() o setNombre() de la clase Profesor deberíamos cambiar el fichero Profesor.hbm.xml añadiendo en la definición de la columna profesor el texto access=“field”, quedando en ese caso de la siguiente forma:

<property name="nombre" access="field" />

La propiedad access=“field” también puede aplicarse al tag <id> como a los diversos tag que definen una propiedad en Hibernate.

Realmente como norma general siempre deberíamos utilizar al tributo access=“field” ya que así, podremos decidir tranquilamente si poner o no los métodos get'/set y además dichos métodos get'/set podrían tener reglas o calculos que hicieran que se generaran errores en nuestra aplicación al ser cargados desde Hibernate.Más información sobre este tema en Avoiding Anemic Domain Models with Hibernate

Sin embargo, durante el resto del curso no haremos uso de esta característica para simplificar las explicaciones/ejemplos.

Anotaciones

En el apartado anterior hemos visto cómo mediante un fichero .hbm.xml podemos especificar cómo mapear la clases Java en tablas de base de datos.

Desde hace algunos años en Java se ha creado el concepto llamado El infierno XML.Este infierno ha consistido en que en demasiados frameworks 6) se hacía un uso intensivo de XML , siendo el XML un formato de ficheros demasiado largo de escribir , muy repetitivo , verboso, etc. Ésto ha llevado a crear una solución para evitar los ficheros XML de persistencia en hibernate 7): El uso de Anotaciones Java en el propio código. Estas anotaciones permiten especificar de una forma más compacta y sencilla la información de mapeo de las clases Java.

Inicialmente Hibernate creó sus propia anotaciones en el paquete org.hibernate.annotations pero a partir de la versión 4 de Hibernate la mayoría de dichas anotaciones han sido java.lang.Deprecated y ya no deben usarse. Las anotaciones que deben usarse actualmente son las del estándar de JPA que se encuentran en el paquete javax.persistence. Sin embargo hay características específicas de Hibernate que no posee JPA lo que hace que aun sea necesario usar alguna anotación del paquete org.hibernate.annotations pero en ese caso Hibernate 4 no las ha marcado como java.lang.Deprecated

Veamos ahora el ejemplo de la clase Profesor pero mapeada con anotaciones.

1|Profesor.java anotado
@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;
 
 
    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 int getId() {
        return id;
    }
 
    public void setId(int id) {
        this.id = id;
    }
 
    public String getNombre() {
        return nombre;
    }
 
    public void setNombre(String nombre) {
        this.nombre = nombre;
    }
 
    public String getApe1() {
        return ape1;
    }
 
    public void setApe1(String ape1) {
        this.ape1 = ape1;
    }
 
    public String getApe2() {
        return ape2;
    }
 
    public void setApe2(String ape2) {
        this.ape2 = ape2;
    }
}

Las anotaciones que se han usado son las siguientes:

Una diferencia importante entre usar el fichero de mapeo .hbm.xml y las anotaciones es que en el fichero es obligatorio indicar todas las propiedades que queremos que se persistan en la base de datos, mientras que usando las anotaciones éso no es necesario. Usando anotaciones se persisten todas las propiedades que tengan los métodos get/set.
Ya hemos comentado en el apartado anterior sobre como Hibernate accede a los datos al usar el fichero .hbm.xml, si mediante el uso de los métodos get/set o mediante el acceso a las propiedades.Veamos como se especifica ésto mediante notaciones:
  • Si colocamos las anotaciones sobre las propiedades , el acceso será a las propiedades y no serán necesarios los métodos get/set.
  • Si colocamos las anotaciones sobre los métodos get() , el acceso será mediante los métodos get/set.

Personalmente siempre coloco las anotaciones sobre las propiedades ya que así tengo todas ellas más agrupadas visualmente y queda el código más legible.

1)
El contructor puede ser privado pero disminuirá el rendimiento de hibernate. Véase: 2.2. The entity Java class
3)
Recordar que hibernate es un ORM, que significa mapeo objeto-relacional
4)
Fully-Qualified Class Name
6)
incluido hibernate
7)
y en muchos otros frameworks