Esta semana vuelvo con los ORM, ya hemos descubierto algunas de las ventajasque aporta a nuestros desarrollos, pero ahora vamos a conocer una herramienta concreta y ver algún pequeño ejemplo, en especial vamos a ver un poquito de Hibernate, que es el ORM que empleé durante mi primera experiencia como desarrollador.
Veamos la definición de la wikipedia:
“Hibernate es una herramienta de Mapeo objeto-relacional (ORM) para la plataforma Java que facilita el mapeo de atributos entre una base de datos relacional tradicional y el modelo de objetos de una aplicación, mediante archivos declarativos (XML) o anotaciones en los beans de las entidades que permiten establecer estas relaciones.”
Como vimos en el artículo anterior se trata de una especie de traductor situado entre nuestra aplicación y la base de datos, que nos abstraerá del diseño de la base de datos, permitiéndonos centrarnos en las funcionalidades básicas de nuestra aplicación.
Como bien dice la señora wikipedia la manera de poder abstraerse de ésta es con un mapeo entre las columnas de una tabla de la base de datos y los atributos de una clase. En este artículo he decidido emplear archivos de configuración xml para realizar el mapeo.
Ejemplo Práctico de Hibernate
El primer paso que debemos realizar es configurar el conector jdbc para que sea empleado por Hibernate. A continuación muestro el fichero de configuración base, donde además de los datos de conexión a la BBDD se deben de establecer ciertos parámetros de configuración para Hibernate, por ejemplo true establece mostrar las traducciones a sql por la salida estandar (en esta introducción no es objetivo conocer todos estos parámetros, ver documentación oficial). Además se incluyen las referencias a los recursos de mapeo correspondientes:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
<?xml version='1.0' encoding='utf-8'?> <!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd"> <hibernate-configuration> <session-factory> <!-- Database connection settings --> <property name="connection.driver_class"> com.mysql.jdbc.Driver </property> <property name="connection.url"> jdbc:mysql://localhost:3306/mydb </property> <property name="connection.username">root</property> <property name="connection.password">root</property> <!-- JDBC connection pool (use the built-in) --> <property name="connection.pool_size">1</property> <!-- SQL dialect --> <property name="dialect"> org.hibernate.dialect.MySQLDialect </property> <!-- Enable Hibernate's automatic session context management --> <property name="current_session_context_class">thread</property> <!-- Disable the second-level cache --> <property name="cache.provider_class"> org.hibernate.cache.NoCacheProvider </property> <!-- Echo all executed SQL to stdout --> <property name="show_sql">true</property> <!-- Drop and re-create the database schema on startup --> <property name="hbm2ddl.auto">update</property> <mapping resource="maps/Cliente.hbm.xml"/> <mapping resource="maps/Pedido.hbm.xml"/> </session-factory> </hibernate-configuration> |
Tras configurar la conexión con la base de datos debemos desarrollar las clase java (modelos) que se asociaran con las tablas de la base de datos. Es importante incluir un constructor vació y los getters y setters de todos los atributos, ya que es necesario para Hibernate para el proceso de Mapeo.
En este ejemplo mapearemos una Relacion de Asociación 1 a N, concretamente la siguiente relación: “un cliente puede llegar a tener N pedidos, mientras que un pedido solo corresponde a un solo cliente”. Como podemos comprobar estas clases implementan la interfaz Serializable, ya que el contenido de los objetos de estas clases se serializarán en la base de datos.
Para completar la relación el Cliente requiere de un medio de almacenamiento de los pedidos, para este mapeo empleamos un ArrayList de Pedidos. A continuación os dejo los beans a ser mapeados:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
public class Cliente implements Serializable { int id; String nombre; String apellidos; String domicilio; List pedidos = new ArrayList(); public Cliente() { } public Cliente(int id, String nombre, String apellidos, ArrayList pedidos) { super(); this.id = id; this.nombre = nombre; this.apellidos = apellidos; this.pedidos = pedidos; } // getters & setters } public class Pedido implements Serializable { int idpedido; Date ficha; int estadotipo; int cliente_id; float descuentof; String descripcion; float preciofinal; public Pedido() { } public Pedido(int id, String descripcion) { this.idpedido = id; this.descripcion = descripcion; } // getters & setters } |
Tras tener configurada la conexión a la base de datos y nuestros modelos (clases) desarrollados, debemos de preparar los ficheros de mapeo. En los siguientes xml podemos comprobar como los atributos de las clases definidas anteriormente se asocian con las columnas de la base de datos además de definir que tipos de datos se emplean depende del sistema.
Ciertas características interesantes de estos ficheros a comentar son, por ejemplo, la auto-generación de ids, o como se realiza el mapeo de las asociaciones con las claves foráneas y si atributos, por ejemplo, el atributo lazy (conexión perezosa) puesto a false determina que al consultar los clientes deben de recuperarse recursivamente todos los pedidos)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping> <class name="model.Cliente" table="CLIENTE"> <id name="id" type="int"> <column name="ID" /> <generator class="increment" /> </id> <property name="nombre" type="java.lang.String"> <column name="NOMBRE" /> </property> <property name="apellidos" type="java.lang.String"> <column name="APELLIDOS" /> </property> <property name="domicilio" type="java.lang.String"> <column name="DOMICILIO" /> </property> <bag name="pedidos" lazy="false"> <key column="CLIENTE_ID" /> <one-to-many class="model.Pedido" /> </bag> </class> </hibernate-mapping> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping> <class name="model.Pedido" table="PEDIDOS"> <id name="idpedido" type="int"> <column name="ID" /> <generator class="increment" /> </id> <property name="descripcion" type="java.lang.String"> <column name="DESCRIPCION" /> </property> <property name="fecha" type="java.util.Date"> <column name="FECHA" /> </property> <property name="cliente_id" type="int"> <column name="CLIENTE_ID" /> </property> <property name="estadotipo" type="int"> <column name="ESTADO_IDESTADO" /> </property> <property name="preciofinal" type="float"> <column name="PRECIOFINAL" /> </property> <property name="descuentof" type="float"> <column name="DESCUENTO" /> </property> </class> </hibernate-mapping> |
En el siguiente artículo veremos como una vez todo configurado, se emplean estos mapeos para realizar consultas en la aplicación abstrayéndose del SGBD y como empleamos el patrón Singleton