En el ciclo de vida de las entidades está definido un conjunto de eventos que podría ocurrir o no de acuerdo a las operaciones que sobre ellas se invoquen (inserción, actualización, eliminación y carga).
Los eventos definidos en el ciclo de vida que se pueden disparar son los siguientes:
* PrePersist
* PostPersist
* PreUpdate
* PostUpdate
* PreRemove
* PostRemove
* PostLoad
Por ejemplo, si se invoca una operación de persistencia sobre una entidad y resulta exitosa, estarían disponibles los eventos PrePersist y PostPersist para esa entidad en particular.
Ahora bien, la pregunta es: ¿cómo sabe la entidad a qué evento debe responder y en qué momento? La respuesta a este interrogante es que en las entidades se deben implementar uno o más métodos de retrollamada, acompañados de las anotaciones vinculadas al tipo de evento al que desean responder. Estas están definidas dentro del paquete javax.persistence.* y son las siguientes:
* @PrePersist
* @PostPersist
* @PreUpdate
* @PostUpdate
* @PreRemove
* @PostRemove
* @PostLoad
Por ejemplo, en la entidad Facultad podríamos implementar un método de retrollamada con la anotación @PrePersist , como se observa en el siguiente fragmento de código:
El método prePersistencia() simplemente está a la espera de que ocurra una operación de inserción de una nueva entidad y, antes de que esta sea persistida en la base de datos, la intercepta, modifica su nombre (lo pasa a mayúsculas) y establece su abreviatura con los tres primeros caracteres del nombre.
Este esquema responde a la forma más básica de implementación de las retrollamadas, en la que, como se observa, los métodos no deben recibir parámetros. Por supuesto, se podrían implementar más métodos en la entidad, pero no estaríamos siendo del todo cuidadosos, ya que estaríamos agregando un poco de lógica en la definición de la entidad.
En caso de que desee implementar diversos métodos de retrollamada, lo aconsejable sería desacoplar el código y crear una clase exclusivamente con estos métodos. Dicha clase recibe el nombre de “oyente” ( Entity Listener, en inglés) y en ella los métodos sí pueden recibir parámetros. Generalmente necesitarán acceder al estado de la entidad que se encuentran “oyendo”, por lo que el parámetro que recibirán será una instancia de dicha entidad o bien de la clase Object.
2.8.1 Creación y vinculación a entidades
A modo de ejemplo, crearemos un oyente de la entidad Facultad que contendrá dos métodos: prePersistencia() y postPersistencia(), los cuales implementarán las retrollamadas mediante las anotaciones @PrePersist y @PostPersist , respectivamente.
A continuación, el código del oyente:
Una vez creado el oyente, debemos registrarlo en la entidad para la que fue creado, en este caso, Facultad. Para ello nos ubicamos en dicha entidad y debajo de la anotación @Entity agregaremos la siguiente línea de código:
@EntityListeners({FacultadListener. class})
Para probar su funcionamiento, podemos invocar el método insertar() creado en la sección 2.7, como se puede apreciar en el siguiente fragmento de código:
Si la ejecución del oyente ha ocurrido, en la consola de salida deberíamos ver el siguiente mensaje: “Se insertó FACULTAD DE DERECHO”, y en la base de datos se debería haber agregado un nuevo registro con la abreviatura compuesta por los tres primeros caracteres del nombre.
En la sección anterior estudiamos el lenguaje de consultas JPQL y su estructura básica, y analizamos algunos ejemplos sobre cómo utilizar consultas parametrizadas. En este apartado presentaremos una alternativa enfocándonos en la construcción de consultas dinámicas.
CriteriaBuilder es la interface principal que nos permite construir consultas dinámicas por partes.
Figura 2.9 CriteriaBuilder (Fuente: www.arquitecturajava.com).
Para poder utilizarla se debe invocar el método getCriteriaBuilder() del EntityManager , como se observa en el siguiente fragmento de código:
CriteriaBuilder criteriaBuilder = em.getCriteriaBuilder();
Además, la interface CriteriaBuilder nos permite definir funciones de agregación para operar sobre un conjunto de resultados. Son las siguientes:
* max (expresión) – Retorna el valor máximo de la expresión recibida como parámetro.
* min (expresión) – Retorna el valor mínimo.
* avg (expresión) – Retorna el promedio de un conjunto de registros.
* sum (expresión) – Retorna la sumatoria de un conjunto de registros.
* count (expresión) – Retorna la cantidad de registros de un determinado conjunto.
* countDistinct (expresión) – Retorna la cantidad de registros de un conjunto sin tener en cuenta los repetidos.
Para crear una consulta JPA, se debe utilizar la interface CriteriaQuery e invocar el método createQuery() del objeto CriteriaBuilder , como se observa en el siguiente fragmento de código:
CriteriaQuery criteriaQuery = criteriaBuilder.createQuery();
La interface CriteriaQuery permite definir las siguientes cláusulas:
* distinct (booleano) – Se emplea para filtrar los registros duplicados.
* from (clase o entidad) – Retorna un objeto cuyo tipo de dato se especifica como parámetro.
* select (selección) – Se utiliza para especificar qué atributos se desean recuperar en una consulta.
* where (expresión) – Se emplea para especificar la condición que deberán cumplir los registros para ser incluidos en la consulta.
* orderBy (Order) – La cláusula orderBy se utiliza para especificar un tipo de ordenamiento sobre un conjunto de resultados.
* groupBy (expresión) – Se emplea para determinar si la consulta se debe agrupar por un determinado atributo.
* having (expresión) – La cláusula having se utiliza para especificar una condición (filtro) sobre un grupo.
Se emplean de la siguiente forma:
criteriaQuery.where(expresion);
2.9.3 Root y cláusula from
La cláusula from se define a partir de CriteriaQuery y establece cuál es la clase en la que se realizará la consulta o, mejor dicho, la clase de la que obtendremos las diferentes instancias. from retorna un objeto raíz que representa al objeto y mediante el cual podemos acceder a sus atributos, tal como se puede apreciar en el siguiente fragmento de código, donde se obtiene un listado de carreras que pertenecen al tipo 1.
Читать дальше