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 clases Java deberán tener las siguientes características:
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.
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.
.hbm.xml
esté en otro paquete distinto al de la clase Java. En este sentido suele haber 2 posibilidades:.hbm.xml
en el mismo paquete que la clase Java a la que hace referencia..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.
<?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.
<hibernate-mapping>
y se encuentra en la línea 3.<class>
que nos indica que vamos a mapear una clase. name
deberemos poner el FQCN 4) de la clase que queremos mapear.Es decir el nombre de la clase incluyendo el paquete en el que se encuentra.table
nos indica el nombre de la tabla en la que vamos a mapear la clase. Este atributo es opcional si el nombre de la clase Java y el de la tabla coinciden.<id>
de la línea 5 se usa para indicar la propiedad de la clase que es la clave primaria.name
es el nombre de la propiedad Java que contiene la clave primaria.column
contiene el nombre de la columna de la base de datos asociado a la propiedad. Este atributo es opcional si el nombre de la propiedad Java y el nombre de la columna coinciden.type
indica el tipo de la propiedad Java. Este atributo no es necesario puesto que Hibernate por defecto ya usa el tipo de la propiedad Java. Mas información en Tipos básicos.<property>
de las líneas 6 a la 8 se usa para declarar más propiedades Java para ser mapeadas en la base de datos. Si no declaramos las propiedades Java mediante este tag no se leerán o guardarán en la base de datos.name
es el nombre de la propiedad Java que queremos mapear a la base de datos.column
contiene el nombre de la columna de la base de datos asociado a la propiedad. Este atributo es opcional si el nombre de la propiedad Java y el nombre de la columna coinciden. 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>
.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.
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.
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.
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.
@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:
@Entity
: Se aplica a la clase e indica que esta clase Java es una entidad a persistir. Es una anotación estándar de JPA. En nuestro ejemplo estamos indicando que la clase Profesor
es una entidad que se puede persistir.@Table(name=“Profesor”)
: Se aplica a la clase e indica el nombre de la tabla de la base de datos donde se persistirá la clase. Es opcional si el nombre de la clase coincide con el de la tabla. Es una anotación estándar de JPA. En nuestro ejemplo estamos indicando que la clase Profesor
se persistirá en la tabla Profesor
de la base de datos.@Id
: Se aplica a una propiedad Java e indica que este atributo es la clave primaria. Es una anotación estándar de JPA. En nuestro ejemplo estamos indicando que la propiedad Java id
es la clave primaria.@Column(name=“Id”)
: Se aplica a una propiedad Java e indica el nombre de la columna de la base de datos en la que se persistirá la propiedad. Es opcional si el nombre de la propiedad Java coincide con el de la columna de la base de datos. Es una anotación estándar de JPA. En nuestro ejemplo estamos indicando que la propiedad Java id
se persistirá en una columna llamada Id
.@Column(name=“nombre”)
: Se aplica a una propiedad Java e indica el nombre de la columna de la base de datos en la que se persistirá la propiedad. Es opcional si el nombre de la propiedad Java coincide con el de la columna de la base de datos. Es una anotación estándar de JPA. En nuestro ejemplo estamos indicando que la propiedad Java nombre
se persistirá en una columna llamada nombre
.@Column(name=“ape1”)
: Es igual al caso anterior pero para la propiedad ape1
.@Column(name=“ape2”)
: Es igual al caso anterior pero para la propiedad ape2
..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
.
.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:get/set
.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.