Trabajar con objetos pesados @Lob

Tutorial de JPA @LobJPA nos permite mediante la anotación @Lob mapear con la base de datos objetos pesados, como podría ser imágenes, xml, binarios, cadenas de texto extensas, json, etc. Cualquier objeto que pueda tener un tamaña muy grande o de longitud indefinida.

@Lob

La anotación @Lob es lo único que se requiere para indicarle a JPA que ese campo es un objeto pesado y que debe de tratarse como tal. Por lo general se utiliza con los arreglos de bytes, ya que permite almacenar cualquier cosa.

La anotación @Lob no tiene ningún atributo, por lo que solo será necesario definirla para que funcione. Otro punto importante es que esta anotación creará una columna de tipo longblob en mysql y podría variar según el manejador de base de datos utilizados, pero al final siempre será un campo para objetos pesados.

Para poner en práctica esta anotación, retomaremos la entidad Employee, en esta ya habíamos agregado la propiedad photo  de tipo byte[], en la cual vamos a almacenar la foto del empleado, sin embargo, no habíamos entrado en detalles. La entidad Employee se ve de la siguiente manera:

as

Estrategias de carga con @Basic

Tutorial de JPA @Basic@Basic es una anotación que nos permite controlar el momento en que una propiedad es cargada desde la base de datos, evitando que traer valores que no son necesario al momento de cargar el objeto. Esta anotación es utilizada generalmente para anotar objetos pesados, como una imagen o un archivo binario.

@Basic

En JPA existe dos conceptos que son claves para entender cómo es que JPA carga los objetos desde la base de datos y estos son claves para mejorar el rendimiento de la aplicación, estos conceptos se explican a continuación:

  • Lazy loading (Carga demorada): Los objetos de carga demorada no serán cargados desde la base de datos cuando el objeto sea creado, pero será cargado en cuanto se acceda a la propiedad. De esta manera JPA identifica cuando la propiedad es accedida por primera vez para cargar el valor desde la base de datos.
    • @Basic( fetch = FetchType.LAZY )
  • Eager loading (Carga ansiosa o temprana): Este es la utilizada por default para la mayoria de las propiedades en JPA, a excepción de las colecciones las cuales las analizaremos mas adelante.
    • @Basic( fetch = FetchType.EAGER )

as

Mapeo de fechas con @Temporal

Tutorial de JPA @Temporal

Mediante la anotación @Temporal es posible mapear las fechas con la base de datos de una forma simple. Una de las principales complicaciones cuando trabajamos con fecha y hora es determinar el formato empleado por el manejador de base de datos. Sin embargo, esto ya no será más problema con @Temporal.

Mediante el uso de @Temporal es posible determinar si nuestro atributo almacena Hora, Fecha u Hora y fecha, y es posible utilizar la clase Date o Calendar para estos fines. Yo siempre recomiendo utilizar Calendar, pues tiene muchas más operaciones para manipular fecha y hora.

Se pueden establecer tres posibles valores para la anotación:

  • DATE: Acotara el campo solo a la Fecha, descartando la hora.
    • @Temporal(TemporalType.DATE)
  • TIME: Acotara el campo solo a la Hora, descartando a la fecha.
    • @Temporal(TemporalType.TIME)
  • TIMESTAMP: Toma la fecha y hora.
    • @Temporal(TemporalType.TIMESTAMP)

as

JPA y los métodos hashCode & equals

Tutorial de JPA persistence.xmlPor defecto, todos los objetos en Java heredan de la case Object los métodos hashCode y equals los cuales sirvan para identificar si dos variables hacen referencia al mismo objeto.
El comportamiento de facto del método hashCode retorna la posición en memoria de un objeto, y el método equals compara el hashCode de los dos objetos evaluados, de esta forma, si las dos variables hacen referencia a la misma posición de memoria, entonces se dice que son igual, de lo contrario son diferentes.
En el caso de las Entidades, la implementación default de estos métodos no funciona correctamente, debido a que una Entidad de dice que es igual a otra si se cumplen dos condiciones:

• Los dos objetos son de la misma clase.
• El valor de su ID (@Id) son iguales

Si estas dos condiciones se cumplen entonces las dos entidades son iguales sin importar que no hagan referencia a mismo objeto en memoria. Debido a esto, es que es importante sobrescribir estos dos métodos para que evalúen a una Entidad por las dos condiciones mencionadas.

Implementando los métodos hashCode & equals

Algo que me ha llamado mucho la atención es que a pesar de que estos dos métodos son básicos y que se utilizan con regularidad, muchas personas no entienden como trabajan internamente y aún menos como sobrescribirlos correctamente, si eres una de esas personas, no te preocupes ya que los IDE’s ya tiene por default utilidades que nos ayudan a generarlos de forma adecuada.
Lo primero que haremos será abrir la entidad Employee que hemos venido trabajando a lo largo de este tutorial. Luego presionaremos Source > Insert Code del menú principal, esto arrojara una pequeña lista de acciones, seleccionamos la opción equals() and hashCode(). Nos arrojara una pantalla como la siguiente:
Método equals y hashcode as

Mapeo de enumeraciones con @Enumerated

Tutorial de JPA @EnumeratedUna de las ventajas de utilizar enumeraciones en Java, es podemos limitar los valores posibles para una propiedad, forzando a los desarrolladores a utilizar los valores ya definidos y evitando el margen de error.

@Enumerated

Con JPA también es posible utilizar enumeraciones y pueden ser de mucha ayuda para asegurar que los programadores persistan un valor válido dentro de una lista previamente definida. JPA nos permite mediante la anotación @Enumerated definir la forma en que una enumeración será persistida, las cuales se explican a continuación:

  • String: permite persistir la enumeración por su nombre, lo que significa que será una columna alfanumérica. La anotación quedaría así:
    • @Enumerated(value = EnumType.STRING)
  • Ordinal: esta estrategia persiste un valor entero que corresponde al valor ordinal o posición de valor en la enumeración. La anotación quedaría de la siguiente manera:
    • @Enumerated(value = EnumType.ORDINAL)

Retomaremos la entidad Employee que hemos venido analizando en todo este tutorial y le agregaremos una nueva propiedad que corresponda al status:

as

Definición de columnas con @Column

Tutorial de JPAUna de las principales características cuando trabajamos con base de datos es que todas las tablas tienen Columnas, y dichas columnas esta mapeadas contra los atributos de las entidades, para lo cual es necesario que JPA identifique que columna mapea contra cada atributo de la clase y es aquí donde entra @Column.

@Column

La anotación @Column nos permitirá definir aspectos muy importantes sobre las columnas de la base de datos de la base de datos como lo es el nombre, la longitud, constrains, etc. En caso de no definir esta anotación en los atributos, JPA determinara el nombre de la columna de forma automática mediante el nombre del atributo, por lo que siempre es recomendable establecer esta anotación en todos los atributos de la clase y evitarnos problemas. as

Llaves compuestas con @IdClass

Tutorial de JPA @IdClassExisten ocasiones en donde se requieres marcar más de un campo como @Id, conformando con esto una llave primaría compuesta. En estos casos se requiere complementar la entidad con una clase adicional que será utilizada como ID y además tendrá que ser referenciada desde la clase donde se requiere una llave compuesta.

La utilización de @IdClass es una de las dos opciones para definir llaves primarias compuestas, y esta consiste en crear una clase adicional únicamente con los campos que corresponden a la llave primaria.
Veamos un caso concreto, normalmente un empleado puede tener más de un teléfono, entonces, podríamos crear una tabla donde la llave primaria sea el ID del empleado y el tipo de teléfono, de esta forma nos aseguramos de tener solo un tipo de teléfono por empleado. Veamos cómo quedaría la clase ID: as

Definir llave primaría con @Id

Tutorial de JPA @IdAl igual que en las tablas, las entidades también requieren un identificador(@Id ), dicho identificador deberá de diferenciar a la entidad del resto. Como regla general, todas las entidades deberán definir in ID, de lo contrario provocaremos que el EntityManager marque error a la hora de instanciarlo.

El ID es importante porque será utilizando por EntityManager a la hora de persistir un objeto, y es por este que puede determinar sobre que registro hacer el select, update o delete. JPA soporta ID simples de un solo campo o ID complejos, formados por más de un campo, sin embargo, esta sección abordaremos únicamente los ID simples y abordaremos las llaves compuestas en la siguiente sección del tutorial.

as

Mapeo de tablas con @Table

Tutorial de JPA @TableEn la sección hablaremos de la anotación @Table  y su importancia a la hora de definir entidades. La anotación @Table es utilizada para indicarle a JPA contra que tabla debe de mapear una entidad, de esta manera cuando se realice una persistencia, borrado o select de la entidad, JPA sabrá contra que tabla de la base de datos deberá interactuar.

Anotación @Table

Como comenté, esta anotación se utiliza para indicar la tabla contra la que mapea la entidad, pero también tiene otras propiedades interesantes como las que se muestra a continuación:

  • name: se utiliza para poner el nombre real de la tabla en la base de datos, es recomendable que el nombre sea exacto respetando mayúsculas y minúsculas, sobre todo cuando trabajamos en Linux.
  • schema: se utiliza para indicar el schema en el que se encuentra la tabla. Esta propiedad por lo general no es necesaria, a menos que la tabla se encuentre en un schema diferente al que utilizamos para logeamos.
  • Indexes: JPA permite indicar los índex que tiene nuestra tabla, esta opción toma relevancia cuando indicamos que JPA cree las tablas por nosotros (más adelante veremos esta característica).

Veamos cómo quedaría @Table en la entidad Employee que revisamos en la unidad pasada: as

Declarar entidades con @Entity

Tutorial de JPA @EntityUna de las grandes ventajas de JPA es que nos permite manipular la base de datos a través de objetos, estos objetos son conocidos como Entity, las cuales son clases comunes y corrientes también llamada POJO’s (Plain Old Java Objects), estas clases tiene la particularidad de ser clases que están mapeadas contra una tabla de la base de datos, dicho mapeo se lleva a cabo generalmente mediante Anotaciones. Dichas anotaciones brindan los suficientes metadatos como para poder por relacionar las clases contra las tablas y las propiedades contra las columnas. Es de esta forma que JPA es capaz de interactuar con la base de datos a través de las clases.

A lo largo de este capítulo y los siguientes estaremos estudiando las diversas anotaciones que nos permitirán crear nuestras Entity así como relacionar entidades con otras.

Anotación @Entity

Como ya discutimos hace un momento, las entidades son POJO’s por lo que son simples clases Java como cualquier otra, sin embargo, JPA debe de ser capaz de identificar que clases son Entity para de esta forma poderlas administrar. Es aquí donde nace la importancia de la anotación @Entity, esta anotación se debe de definir a nivel de clase y sirve únicamente para indicarle a JPA que esa clase es una Entity, veamos el siguiente ejemplo:

package com.obb.jpa.jpaturorial.entity;

import java.util.Calendar;

/**
 *
 * @author Oscar Blancarte
 */
public class Employee {
    private Long id;
    private String name; 

    /**
     * GETs and SETs
     */
}

as