Proyecto
1.1 Tema 1 : Introducción al API de Persistencia JPA 12 1.1.1 : Entidad 12 1.1.2 : Metadata 13 1.1.3 : EntityManager 14 1.1.4 : Unidad de Persistencia 15 1.1.5 : Operaciones básicas 17 1.1.6 : Transacciones 19
1.1.7 : Ciclo de Vida de una Entidad 19
1.2 Tema 2 : OR-Mapping con JPA 23
1.2.1 : Anotaciones 23
1.2.2 : Manejo de la Llave Primaria 28
1.2.3 : Generación de la Llave Primaria 28
1.2.4 : Llave Primaria Compuesta 32
1.2.5 : Objetos Embebidos 35
1.3 Tema 3 : Relaciones entre entidades 38
1.3.1 : Conceptos básicos 38
1.3.2 : Relación Many To One 40
1.3.3 : Relación One to One 42
1.3.4 : Bidireccionalidad de la relación One-To-One 43
1.3.5 : Relación One To Many 44
1.3.6 : Relación Many To Many 46
1.3.7 : Opciones de Fetch 49
1.4 Tema 4 : The Java Persistence Query Language. 51
1.4.1 : Introducción a JP-QL 51 1.4.2 : Consultas dinámicas 56 1.4.3 : Consultas nombradas 58 1.4.4 : Uso de parámetros 60 1.4.5 Ejecución de Queries 61 1.4.6 Sintaxis de JPQL 63 Unidad de Aprendizaje 2
JAVA SERVER FACES 2 69
2.1 Tema 5 : Fundamentos de JSF 72
2.1.1 : Introducción a JSF 72
2.1.2 : Arquitectura de JSF 73
2.1.3 : Ciclo de vida de un request 77
2.1.4 : Facelets 81
2.1.5 : Managed Bean 89
2.1.6 : Lenguaje de Expresiones JSF 92
2.2 Tema 6 : Componentes de Interfaz de usuario 97
2.2.1 : Introducción 97
2.2.2 : Arquitectura de Componentes UI 98
2.2.3 Librería Core 102
2.2.4 Librería HTML 108
2.2.5 Librería User Interface 117
2.2.6 Librería de Componentes Compuestos 117
2.3 Tema 7 : Conversiones, Validaciones y Eventos 119
2.3.1 : Introducción 119 2.3.2 : El sistema de Conversión de JSF 119 2.3.3 El sistema de Validación de JSF 122 2.3.4 El sistema de Mensajes de JSF 123 2.3.5 El modelo de Eventos de JSF 131
2.4 Tema 8 : Integración JSF y JPA 127
2.4.1 : JSF y AJAX 127
2.4.2 : Integración JSF + JPA 136
2.4.3 : Empleando otras implementaciones de JSF 137 2.4.4 : Tablas JSF: Facets, dataTable y panelGrid 141
2.4.5 : Mantenimiento de tablas 148
Unidad de Aprendizaje 3
SPRING FRAMEWORK 155
3.1 Tema 9 : Spring Core 157
3.1.1 : Introducción 157
3.1.2 : Arquitectura 161
3.2 Tema 10 : Spring Web 164
3.2.1 : Introducción 164
3.2.2 : Configuración 164
3.3 Tema 11 : Spring Módulos 174
3.3.1 : Spring security 174
El curso de “Proyecto Empresarial” pertenece a la línea de Programación dentro de la Carrera de Computación e Informática y brinda un conjunto de conocimientos y herramientas que permitirán a los alumnos poder desarrollar aplicaciones web de n-capas utilizando los frameworks Java : Java Persistence API ( JPA ), Java Server Faces ( JSF ) y Spring Framework.
El manual del curso ha sido diseñado bajo la modalidad de Unidades de Aprendizaje, las que desarrollan determinados temas a lo largo de las semanas establecidas para el dictado del curso. Cada capítulo del manual indica los temas a ser tratados, los logros que se deben alcanzar y los contenidos que se deben desarrollar. Finalmente, se encontrará las actividades recomendadas que el alumno deberá desarrollar para reforzar lo trabajado y aprendido en la clase. Se incluye bibliografía y recursos de internet que puede colaborar en el logro de un autoaprendizaje efectivo.
El curso es eminentemente práctico, pero requiere horas adicionales de investigación y práctica por parte del alumno. Se inicia con un los conceptos de “OR-Mapping” con la especificación JPA (Java Persistence API) y su implementación en EclipseLink: se abordan las anotaciones, mapeo y relaciones entre entidades así como los fundamentos básicos de JP-QL para la construcción de consultas. Luego, la segunda unidad del manual aborda la especificación JSF (Java Server Faces) tratando de abarcar gran parte de la funcionalidad que proporciona. Finalmente, se aborda en la tercera unidad el framework de Spring: Arquitectura, Web y Security.
Proyecto Empresarial
Spring
Spring Core Spring Web
Java Persistence API (JPA) Java Server Faces (JSF) Introducción a la API de Persistencia OR-Mapping con JPA Relaciones entre entidades Lenguaje de Consultas JPQL Tópicos avanzados de JSF Conversiones, Validaciones y Eventos Componentes de Interfaz de usuario Arquitectura de JSF, Configuración y estructura básica Spring Módulos
JAVA PERSISTENCE API
LOGRO DE LA UNIDAD DE APRENDIZAJEAl término de la unidad, el alumno puede realizar transacciones y consultas para reportes usando JPQL a nivel empresarial.
TEMARIO
1.1 Tema 1 : Introducción al API de Persistencia JPA 1.1.1 : Entidad 1.1.2 : Metadata 1.1.3 : EntityManager 1.1.4 : Unidad de Persistencia 1.1.5 : Operaciones básicas 1.1.6 : Transacciones
1.1.7 : Ciclo de Vida de una Entidad
1.2 Tema 2 : OR-Mapping con JPA 1.2.1 : Anotaciones
1.2.2 : Manejo de la Llave Primaria 1.2.3 : Generación de la Llave Primaria 1.2.4 : Llave Primaria Compuesta 1.2.5 : Objetos Embebidos
1.3 Tema 3 : Relaciones entre entidades 1.3.1 : Conceptos básicos
1.3.2 : Relación Many To One 1.3.3 : Relación One to One
1.3.4 : Bidireccionalidad de la relación One-To-One 1.3.5 : Relación One To Many
1.3.6 : Relación Many To Many 1.3.7 : Opciones de Fetch
1.4 Tema 4 : The Java Persistence Query Language. 1.4.1 : Introducción a JP-QL 1.4.2 : Consultas dinámicas 1.4.3 : Consultas nombradas 1.4.4 : Uso de parámetros 1.4.5 Ejecución de Queries 1.4.6 Sintaxis de JPQL ACTIVIDADES PROPUESTAS
Reconocer las clases de la API Persistencia JPA
Los alumnos escriben clases Java, las convierten en Entidades JPA y trabajan con tablas relacionales.
Las alumnos desarrollan aplicaciones Java stand-alone haciendo uso de entidades JPA.
Implementar inserciones de sentencias JPQL a la base de datos.
Implementar consultas y transacciones de sentencias JPQL a la base de datos.
Implementar inserciones de sentencias JPQL a la base de datos.
Implementar consultas y transacciones de sentencias JPQL a la base de datos.
1.1. INTRODUCCIÓN AL API DE PERSISTENCIA JPA
La técnica que permite acortar las diferencias entre el modelo relacional y el modelo de objetos se conoce como ORM (Mapeo Relacional a Objetos). La idea básica se sustenta en que para mapear los conceptos de un modelo al otro (o viceversa) se requiere de un mediador que maneje de forma automática la transformación.
La historia de JPA se origina en dos frameworks de persistencia bastante utilizados: en el lado propietario existía TopLink mientras que en el lado “open” estaba Hibernate. JPA es una especificación basada en el JSR 220 conocido como “Enterprise Java Bean 3.0” (http://jcp.org/en/jsr/detail?id=220 ).
Al ser una especificación (o un conjunto de API’s) está sujeta a diversas implementaciones de diversos fabricantes. La idea principal es que sea un Framework ligero, basado en POJOs y pueda enfrentar desafíos de arquitectura e integración en aplicaciones empresariales.
Algunas implementaciones de JPA: Hibernate http://www.hibernate.org/ TopLink http://www.oracle.com/technetwork/middlew are/toplink/overview/index.html OpenJPA http://openjpa.apache.org/ EclipseLink http://www.eclipse.org/eclipselink/ 1.1.1. Entidad
El concepto de “Entidad” fue introducido por Peter Chen en un documento llamado “The Entity-relationship model – Howard a unified view of data” publicado en “ACM Transactions on Database Systems” en el año de 19761.
En dicho documento, se describía a las entidades como cosas que tenían “atributos” y “relaciones” con la expectativa de que dichos atributos y relaciones pudieran ser almacenados en la base de datos.
En la actualidad, dicha definición es vigente dado que cualquier objeto dentro de una aplicación JPA puede ser una entidad, hay que definir las características que debe poseer una “Entidad”:
Persistencia: las entidades pueden ser manipuladas para recuperase en memoria o ser grabadas en un almacén de datos.
1
Una copia del documento se puede obtener en el enlace:
Granularidad: Las entidades son objetos que pertenecen a un dominio de negocio, poseen un conjunto de estados y por tanto son relevantes para la aplicación (no se trata de objetos con tipo primitivo, sino de objetos más complejos).
1.1.2. Metadata
Cada entidad tiene asociado una “metadata” que la describe. Dicha información puede estar almacenada dentro de la entidad Java o puede existir en un archivo externo: en ambos casos, esa información no se almacena en la base de datos.
Existen dos maneras de especificar la metadata: Usando Anotaciones
Usando XML
Las anotaciones fueron introducidas en la versión JAVA EE 5 y permiten que la metadata esté incorporada dentro del código fuente Java.
El uso de las anotaciones requiere que se importe el paquete “javax.persistence.*” dentro de la clase Java que representa a la Entidad.
El uso de XML es una opción alternativa a las anotaciones, aunque su lectura puede resultar compleja para proyectos grandes.
Un JavaBean cualquiera como el siguiente
Se puede convertir en entidad, simplemente agregándole las anotaciones: @Entity
No se debe olvidar que al ser un JavaBean, sigue las reglas de este (con los getter/setter).
1.1.3. EntityManager
La mayoría de llamadas a las API’s de JPA se encapsulan dentro de lo que se conoce como “Entity Manager” y mediante el cual se puede alcanzar a la base de datos. Esta encapsulación es implementada dentro de una interface conocida como
EntityManager que es la que ejecuta todo el trabajo de persistencia. Por tanto, una entidad mientras que no se trabaje con el Entity Manager es un objeto Java simple como cualquier otro.
Cuando el Entity manager obtiene una referencia a una Entidad, se dice que dicha entidad está en estado “managed”
El conjunto de entidades en estado “managed” dentro de un Entity Manager se conoce como “persistence context”.
Los Entity Managers son configurados para trabajar con determinados tipos de objetos, bases de datos y son implementados por un proveedor (provider) conocido como “persistence provider”. En términos prácticos este provider es la implementación de la especificación JPA.
Los Entity Managers se generan a partir de una factoría de tipo
EntityManagerFactory, que genera una especie de plantilla para la persistencia, pero toma la configuración particular desde una unidad de persistencia conocida como “persistence unit”, la cual contiene la configuración implícita o explícita (con un nombre asociado ) para las entidades y para el Entity Manager.
El gráfico2 resume las relaciones entre los conceptos mencionados:
2
Un Entity Manager se obtiene de la siguiente forma:
1.1.4. Unidad de Persistencia
La configuración de una unidad de persistencia se escribe en un archivo llamado “persistence.xml”, el cual debe estar ubicado dentro del folder META-INF de un proyecto Java.
Cada unidad de persistencia tiene un nombre, el cual es referenciado por la factoría al momento de pedirle que genere un EntityManager.
Un archivo persistence.xml puede contener una o más unidades de persistencia, siendo cada una diferente de la otra.
La estructura básica de un archivo persistence.xml es la siguiente:
Nombre de la “persistence unit” Debe ser el mismo que aparece en el archivo persistence.xml
Clase estática
Debido a que es un archivo XML, debe tener un DTD:
Luego, viene la definición de la Unidad de persistencia, el proveedor y las clases Java definidas como entidades:
El valor de RESOURCE_LOCAL indica que la conexión a la base de datos se realizará desde la misma aplicación (No emplea Pool de conexiones).
Después, se definen las propiedades de conexión a la base de datos: Nombre de la “persistence unit”
Observe que las propiedades JDBC (javax.persistence.jdbc.*) han sido estandarizadas en JPA 2.0. En versiones anteriores de JPA, esas propiedades eran definidas por cada Persistence Provider.
1.1.5. Operaciones básicas
Para aquellos desarrolladores acostumbrados al SQL en bases de datos relacionales, la equivalencia es sencilla en JPA:
SQL INSERT = Método Persist
SQL SELECT = Método Find ( o también puede usarse el SELECT JPQL ) SQL UPDATE = Método Merge
SQL DELETE = Método Remove
El “persist” de una entidad significa crear un objeto en memoria y luego almacenarlo en la base de datos para recuperarlo posteriormente. Como se ha mencionado, equivale a insertar uno o más registros en la base de datos.
Si ocurre un error durante la ejecución del “persist”, se lanza la excepción PersistenceException, la cual debe será propagada, debiendo ser manejada por el programa.
Se instancia el objeto Java
Se cargan los valores de los atributos Se ejecuta el método “persist” mediante el EntityManager
Para ubicar a una Entidad empleando el método “find”, generalmente se requiere solo una línea de código:
Si la entidad con la llave primara indicada no existe, el EntityManager devolverá NULL. La aplicación debe verificar el valor antes de usar la variable “emp” en el caso del ejemplo.
Para eliminar una entidad, se hace uso del método “remove”. Sin embargo se debe tener en consideración que para eliminar una entidad en JPA, primero debe colocarse en estado “managed”, es decir, debe cargarse al contexto de persistencia.
Como se mencionó anteriormente, si la entidad no existe el EntityManager devolverá NULL, por lo que se debe evaluar dicha condición antes de invocar al método “remove”.
Si se envía un valor de NULL al “remove”, JPA lanzará la excepción java.lang.IlegalArgumentException.
Para actualizar atributos de una entidad, se emplea el método “merge”. Se requiere ubicar a la entidad antes de actualizarla:
En este ejemplo, se está actualizando el apellido del empleado con ID = 8. variable con el EntityManager cargado
Clase de la Entidad a ser “ubicada” Evita hacer un “cast”
Llave primaria de la Entidad
1.1.7. Ciclo de Vida de una Entidad
JPA proporciona unos métodos denominados “callbacks” (listeners) para ejecutar acciones en los diferentes estados que pueden suceder dentro del ciclo de vida de una entidad. Por ejemplo, imagine que desea actualizar una entidad, pero antes de hacerlo debe verificar que algunos datos estén presentes.
En el gráfico, se puede apreciar que una entidad no existe hasta que se distancia el objeto y se graba en la base de datos. De ahí, pasa al estado “manejado” o “administrado” por el EntityManager y, luego de ello, se puede remover, actualizar, liberar (“detach”) o incluso volver a leer (refrescar).
Se inicia una transacción
Se inicia finaliza la transacción
Las anotaciones que proporciona JPA para manejar los “Callbacks” son: @PostLoad: Se ejecuta luego de un “refresh” a la entidad. @PrePersist: Se ejecuta antes de insertar la entidad.
@PostPersist: Se ejecuta después de haber insertado la entidad. @PreUpdate: Se ejecuta antes de un update a la entidad. @PostUpdate: Se ejecuta después de un update a la entidad.
@PreRemove: Se ejecuta antes de eliminar la entidad en la base de datos. @PostRemove: Se ejecuta después de haber eliminado a la entidad.
Los métodos “callback” se pueden declarar dentro de la misma entidad o también en una clase Java separada.
En cambio, si se prefiere emplear una clase Java externa, sería así:
a) A la Entidad hay que agregarle la anotación @EntityListeners para indicar cuál es la clase Java que contiene los métodos “callbacks”.
b) Se debe crear una clase Java y escribir los métodos que se requiere manejar (con las anotaciones del caso).
Resumen
1. Recordar que JPA es una especificación, por tanto, tiene muchas implementaciones. El desarrollador debe seleccionar una en particular, siendo las más conocidas: Open JPA, TopLink, EclipseLink e Hibernate.
2. Diferenciar entre Entidades y Clases Java.
3. Recordar la ubicación del archivo persistence.xml que debe ir siempre dentro del folder META-INF.
4. Recordar para qué sirve el EntityManager y la persistence-unit.
5. Las operaciones básicas sobre una Entidad: find, persist, merge, remove
Pueden revisar los siguientes enlaces para ampliar los conceptos vistos en esta unidad:
o EclipseLink: http://www.eclipse.org/eclipselink/jpa.php
Anotaciones físicas están relacionadas con el modelo en la base de datos (modelo físico) y tienen que ver con tablas, columnas, etc.
Las anotaciones dentro de una clase Java se pueden colocar a nivel de atributos o a nivel de métodos. Si se colocan a nivel de atributos se denomina “Field Access” mientras que si se coloca a nivel de métodos se denomina “Property Access”.
Es equivalente a:
En la especificación de JPA 2.0 se introduce la anotación @Access que permite combinar los dos modos presentados en el ejemplo. Esta anotación permite sobre escribir el modo de acceso por defecto, aunque no es muy usual hacerlo.
Para definir una entidad basta con emplear la anotación @Entity y la anotación @Id.
Anotación de tipo “Field Access”
Anotación de tipo “Property Access”
NOTA: Siempre va en el GETTER Atributos de la clase
Anotación @Table
Por defecto no es necesario incluir ninguna anotación para referenciar a una tabla. JPA asume que la tabla se llama igual que la clase Java en donde se define la entidad. Sin embargo, si se desea especificar un nombre de tabla en particular para asociarlo con la entidad, es preciso utilizar la anotación @Table con el parámetro “name” respectivo.
Se puede indicar además el esquema de base de datos con el atributo “schema” (para aquellos motores de base de datos que lo soporten):
Se debe tener cuidado con el uso de mayúsculas y minúsculas, pues muchos manejadores de bases de datos no son sensibles a esto.
Anotación @Basic
Cuando se “persiste” una propiedad de una entidad, el “persistente provider” verifica que el tipo de dato corresponda a un tipo soportado y trata de pasarlo hacia la base de datos vía el driver JDBC.
Los tipos de datos soportados son:
Tipos primitivos byte, int, short, long, boolean, char, float double
Clases que encapsulan a tipos primitivos
Byte, Integer, Short, Long, Boolean, Character, Float, Double
Arreglos de bytes y caracteres byte[], Byte[], char[], Character[]
Números java.math.BigInteger, java.math.BigDecimal
datos, pues el driver intentará ejecutar la mejor conversión posible.
La anotación @Basic (que es opcional) se utiliza para indicar de forma explícita que dicho atributo debe ser almacenado en la base de datos.
Anotación @Transient
Se emplea para marcar aquellos atributos de la entidad que NO deben ser guardados en la base de datos.
Anotación @Column
Es una anotación de tipo físico, pues indica las características físicas de la columna en la base de datos.
Si no se especifica para un atributo determinado marcado como persistente, JPA asume que la columna se llama igual que dicho atributo. En cambio, si la columna tiene un nombre diferente, se deberá especificar con el uso de la anotación @Column.
Elemento Descripción Valor por defecto String
columnDefinition
(Opcional)
Es el fragmento de SQL utilizado para generar el DDL de la columna (depende del manejador de base de datos)
“”
boolean
insertable
(Opcional) Indica si la columna ser incluirá dentro de una sentencia SQL INSERT generada por el Persistence Provider.
true int length (Opcional) Indica la longitud de la columna en la tabla y
funciona únicamente cuando la columna es un String o cadena de caracteres.
255
String name (Opcional) Indica el nombre de la columna. POr defecto se asume que la columna se llama igual que el atributo de la entidad.
“”
boolean nullable (Opcional) Indica si la columna permite valores nulos. true int precision (Opcional) Indica la precisión para una columna numérica
(válido solo para columnas decimales).
0 int scale (Opcional) Indica la escala para una columna numérica (válido
solo para columnas decimales).
0 String table (Opcional) Indica el nombre de la tabla en donde se asocial la
columna.
“” boolean unique (Opcional) Se emplea cuando la clave única corresponde a
una sola columna.
false boolean
updatable
(Opcional) Indica si la columna ser incluirá dentro de una sentencia SQL UPDATE generada por el Persistence Provider.
true
Ejemplo 1:
Ejemplo 2:
Anotación @Lob
Para el manejo de objetos binarios (imágenes o archivos generalmente) se requieren accesos especiales en el driver JDBC para efectuar conversiones entre el objeto Java y la columna en la tabla de la base de datos.
La anotación @Lob sirve para indicar que el atributo de dicha entidad requiere efectuar las conversiones vía JDBC.
Ahora bien, los campos LOB (acrónimo de Large Object) se pueden clasificar de dos maneras, siendo el manejo de cada manera un tanto diferente:
Byte[]
tipos serializables
En ambos casos, el driver JDBC es responsable de hacer las conversiones entre el objeto Java y la base de datos.
Ejemplo:
Anotación @Temporal
Sirve para especificar tipos de datos basados en el tiempo. Estos tipos de datos se pueden clasificar en dos ramas: los que vienen del paquete java.sql y los que vienen del paquete java.util.
En el paquete java.sql, los tipos se trabajan directamente: java.sql.Date
java.sql.Time java.sql.Timestamp
En cambio, en el paquete java.util: java.util.Date
java.util.Calendar
Anotación Tipo de dato
Se debe especificar la anotación @Temporal y además especificar el atributo “TemporalType” con uno de los tres valores que representan a cada uno de los tipos java.sql (DATE, TIME o TIMESTAMP).
Ejemplo:
1.2.2. Manejo de la Llave Primaria
Cada Entidad debe tener una llave primaria. La anotación empleada es @Id sobre el atributo que contiene la llave. Adicionalmente, se puede usar @Column para asociar al atributo con la columna en la tabla.
Una llave primaria se asume que es “insertable”, pero no puede ser “nullable” o “updatable” por lo que se debe tener cuidado de no sobre escribir esos atributos salvo excepciones muy específicas (cuando se manejan relaciones).
Los tipos de datos soportados para una llave primaria son: Tipos primitivos byte, int, short, long, char
Clases de tipos primitives Byte, Integer, Short, Long , Character Cadenas de caracteres java.lang.String
Números grandes java.match.BigInteger Tipos basados en tiempo java.util.Date, java.sql.Date
1.2.3. Generación de la Llave Primaria
También, se conoce como “Generación del ID” y se realiza mediante la anotación @GeneratedValue. En base a dicha anotación, el “Persistence Provider” genera el ID para cada entidad, y lo inserta en la columna respectiva.
Se debe tener en cuenta que dependiendo de la estrategia de generación del ID, el valor obtenido puede que no esté disponible hasta que se ejecute un “flush” o un “commit” a la transacción.
Anotación
Equivalencia JDBC Tipo de dato
ESTRATEGIA “GenerationType.AUTO”
Este tipo de estrategia delega en el “Persistence Provider” la selección de la mejor forma de generación de los “ID”. Cualquiera sea la forma elegida por el provider, se confiará en los recursos de la base de datos para la obtención de los ID’s.
En el caso particular de EclipseLink con MySQL, la estrategia AUTO emplea una tabla denominada “sequence”.
Ejemplo:
ESTRATEGIA “GenerationType.TABLE”
Esta estrategia es la más flexible y portable, pues permite que la aplicación genere ID’s diferentes de acuerdo a las necesidades.
La tabla requiere de dos columnas, una conteniendo el identificador para generar la secuencia y la otra columna contiene el último valor generado. Cada fila de la tabla es un generador diferente para los ID’s.
Dado que no se ha especificado el nombre de un “generador” ni el nombre de una tabla, el Persistence provider seleccionará sus propios valores. Lo más común es que busque (la tabla debe existir en la base de datos) una tabla como la indicada en la figura.
¿Qué sucede si se desea especificar una tabla en particular? Se debe emplear la anotación @TableGenerator.
Ejemplo:
El atributo “allocationSize” indica el incremento en la generación del ID (para el caso del ejemplo va de uno en uno). Por defecto el incremento es 50.
Si se desea especificar una secuencia en particular, debe indicarse el “generator” y la anotación @SequenceGenerator. Se debe considerar que la secuencia debe existir previamente en la base de datos (salvo que la opción de generación de DDL esté habilitada en nuestra aplicación).
Ejemplo (la secuencia es para Oracle):
ESTRATEGIA “GenerationType.IDENTITY”
Esta estrategia aprovecha las facilidades de la bases de datos para utilizar columnas de tipo “autoincremento”. Sin embargo, es menos eficiente porque el identificador generado no está disponible hasta después que ocurra el INSERT.
No requiere una anotación para el “generador” dado que el campo autoincremental es parte de la definición de la tabla que corresponde a la entidad.
Ejemplo:
1.2.4. Llave Primaria Compuesta
En algunas situaciones, en donde se requiere que la llave primaria de una entidad esté compuesta de múltiples atributos, JPA proporciona dos formas de soportar esta necesidad mediante las anotaciones:
@IdClass @EmbeddedId Se debe tener en cuenta que:
a) En ambos casos, se requiere de una clase Java externa que sea la que maneje los atributos de la llave primaria.
b) La clase Java que maneja los atributos de la llave primaria, debe implementar los métodos equals () y hashCode () con el fin que el Persistence Manager pueda almacenar e identificar las entidades.
c) La clase Java que representa a la llave primaria debe ser pública, implementar a la interface Serializable y tener un constructor sin argumento.
Ejemplo:
Dada la siguiente tabla “tbmatricula” con una llave primaria compuesta. Estrategia
La Entidad y la clase Java que maneja la llave primaria pueden representarse así (no olvidar que se debe generar los métodos getter/setter en ambas clases Java):
Observe que la anotación @IdClass especifica el nombre de la clase Java que maneja la llave primaria.
Observe, también, que la clase Java que maneja la llave primaria no posee anotaciones. Sin embargo, debe implementar los métodos nombrados líneas arriba:
El método equals () lo que hace es comparar uno a uno los atributos de la llave primaria contra los atributos de otra entidad para verificar que no se trate de la misma entidad.
El método hashCode () lo que hace es devolver un código “hash” de los valores de la llave primaria.
Para consultar una entidad con una llave primaria compuesta, solo se requiere generar una instancia de la clase que maneja la llave primaria, cargarle los valores necesarios y pasar dicha variable al EntityManager.
Por ejemplo, en el siguiente gráfico, se tiene la entidad “CUSTOMER” y la tabla “tbcustomer”. Observe que los datos de la dirección pueden constituir una clase separada:
Se debe observar que:
a) La Entidad declara un atributo con el tipo de dato de la clase “Address” y a este atributo le coloca la anotación “@Embedded” para indicar que esa clase es “embebida”.
b) La clase “Address” NO tiene anotaciones que indiquen que es una entidad. Únicamente tiene la anotación “@Embeddable” para indicar que hay “otra” clase que la incluye (o que la referencia).
c) Ambas clases tienen sus getter/setter.
d) Ambas clases deben definirse en el archivo persistente.xml.
e) Finalmente, es importante saber que solo se puede ejecutar series sobre la clase marcada como “Entidad”.
Anotación @Embedded
Anotación @Embeddable
2. Existen cuatro maneras de generar la secuencias para ID’s: AUTO
TABLE SEQUENCE IDENTITY
3. Recordar el uso de la anotación @Temporal para tipos de datos que manejan tiempo.
Pueden revisar los siguientes enlaces para ampliar los conceptos vistos en esta unidad:
1.3. RELACIONES ENTRE ENTIDADES
1.3.1. Conceptos básicosRoles
Las relaciones entre entidades tienen tres diferentes perspectivas: a) La primera es el punto de vista desde un lado de la relación. b) La segunda en el punto de vista desde el otro lado de la relación. c) La tercera es la perspectiva global que mira ambos lados de la relación.
Estos “lados” son conocidos como “roles”. Tal es así que en cada relación hay dos entidades que se relacionan mutuamente de tal manera que cada una cumple un rol dentro de la relación. Es más, una entidad puede jugar muchos roles dentro de un modelo.
Direccionalidad
Existen maneras de crear, remover y actualizar las relaciones para darles mantenimiento. Si una entidad tiene relación con otra, existirá un atributo que sirve para identificar la relación y referirse a la entidad relacionada identificando así el rol que juega en la relación.
Cuando las entidades se referencian mutuamente se dice que la relación es bi-direccional. Ejemplo: El empleado sabe en qué Proyecto trabaja y el Proyecto conoce quiénes son sus miembros (las flechas indican el sentido de la dirección).
Si una entidad apunta únicamente a otra, la relación es unidireccional. El empleado conoce su Dirección, pero la inversa no necesariamente es cierta (la flecha indica el sentido de la relación).
Ahora bien, la relación Bi-direccional puede ser descompuesta en dos relaciones uni-direccionales. Cada relación tendrá un origen (“source” o rol de referencia) y un destino (“target” o rol referido). Se debe tener en cuenta esto, pues el origen y destino varían según la perspectiva que estemos usando para analizar la relación.
Ordinalidad
Un rol puede especificarse de forma más detallada para indicar si puede o no estar presente en una relación. La ordinalidad sirve para indicar si la entidad “target”
necesita ser especificada cuando la entidad “source” es creada.
Debido a que la ordinalidad es un valor lógico (verdadero o falso) es más práctico referirse a ella como “opcionalidad” de la relación.
Mapeo de Relaciones
Existen básicamente dos formas de asociación: Las basadas en valores simples.
Las basadas en colecciones de valores.
Dentro de esas formas de asociación, existen cuatro formas de “mapeo”: Relación One-To-One (valores simples)
Relación Many-To-One (valores simples) Relación One-To-Many (colecciones de valores) Relación Many-To-Many (colecciones de valores)
A nivel de Base de Datos, la relación entre entidades significa que una tabla referencia a otra tabla: aparece el concepto de “Foreign Key” para indicar aquellos campos de una tabla que hacen referencia a la “Primary Key” de otra tabla.
A nivel de JPA las columnas que forman la “Foreign Key” se conocen como “Join Columns” y emplean la anotación @JoinColumn para indicar dicha funcionalidad.
1.3.2. Relación Many To One
Es la relación más típica que podemos encontrar en el mundo real.
En UML se requiere que la clase “source” tenga un atributo del tipo de la clase”target” para poder navegar hacia ella.
Ejemplo: Si varios Empleados pueden trabajar en un Departamento, la relación de entidades se puede modelar como se muestra a continuación:
Tenga en cuenta que:
a) La clase “source” tienen un atributo que corresponde al tipo de la clase “target” (observe el atributo “departamento”).
b) A dicho atributo se le debe colocar la anotación @ManyToOne. Ahora falta llevar la relación al modelo de base de datos siguiente:
Las tablas físicas están relacionadas mediante la columna “DPTO_ID” en la tabla “tbempleado” que apunta a la columna “DEPT_ID” en la tabla “tbdepartamento”. Entonces, la “Join Column” de la relación es la columna “DPTO_ID”.
El lado que tiene a la “Join Column” se conoce como el “OWNER SIDE” de la relación, mientras que el lado que no tiene a la “Join Column” se conoce como “INVERSE SIDE”.
En este ejemplo, el lado OWNER es la tabla “tbempleado” y el lado INVERSO es la tabla “tbdepartamento”.
La anotación @JoinColumn siempre se debe colocar en el lado “OWNER” de la relación.
Si no se coloca la anotación @JoinColumn, JPA asume el nombre por defecto, el cual está formado por el nombre del atributo en la entidad owner seguido de un guión bajo (“_”) y concatenado con el nombre de la columna PK en la tabla inversa.
1.3.3. Relación One to One
La relación “Uno a Uno” es casi igual a la relación “Muchos a Uno” con la sola excepción que una instancia de la entidad “source” puede apuntar a una única instancia de la entidad “target”. Estrictamente hablando, eso significa que la entidad “target” no puede ser compartida por otras instancias de la entidad “source”.
A nivel de base de datos esta relación implica un criterio de “unicidad” o llave única en la “Foreign Key” de la entidad “source”.
Obviamente se requiere definir la relación en la Entidad “Employee”: para ello se hace uso de la anotación @OneToOne y también se requiere usar @JoinColumn (en este caso, la columna de Join es “PARKING_ID”). La entidad “Employee” quedará así:
1.3.4. Bidireccionalidad de la relación One-To-One
En algunas situaciones se requiere considerar la relación inversa entre las entidades, también conocida como bidireccionalidad de la relación. La decisión es un criterio de modelamiento, más no una obligación a nivel de programación.
Para lograr esto, se requiere que la entidad “target” tenga un atributo de la clase correspondiente a la entidad “source”. Dicho atributo debe tener la anotación @OneToOne con el elemento “mappedBy” que indique cual es el atributo de la clase “source” que contiene la relación y apunta a la entidad “target”.
Ejemplo: en el caso de la entidad “ParkingSpace” (“es el “target” de la relación) se tendría el siguiente atributo:
Debe tenerse en cuenta dos reglas:
a) La anotación @JoinColumn se coloca en la entidad que mapea a la tabla que contiene la columna de join (o a la entidad que es “owner” de la relación). b) El elemento “mappedBy” debe colocarse a la anotación @OneToOne de la
entidad “inversa” o “target” de la relación.
1.3.5. Relación One To Many
Cuando una entidad se asocia con una “colección” de otras entidades estamos ante una relación de “uno a muchos”.
En el ejemplo del Empleado vs. El Departamento, la relación es bidireccional por naturaleza. En una relación bidireccional, siempre existen dos “mapeos”: uno por cada relación.
A nivel de base de datos, las tablas siguen siendo las mismas.
Y a nivel de entidades, la entidad “Employee” es la misma.
Como se tiene que implementar el lado inverso de la relación entre Empleado y Departamento, se debe modificar la entidad “Department” para agregar la relación inversa “One-To-Many”: se debe “mapear” una colección de entidades “Empleado” usando la anotación @OneToMany.
Adicionalmente, como este es el lado inverso de la relación, se debe usar el atributo “mappedBy” para indicar cuál es el atributo dentro de la entidad “Employee” que contiene la llave de la relación:
NOTA: En este caso se está usando una colección indicado el tipo de los elementos que almacena dicha colección: Collection<Type>. Esto genera una dependencia al compilar por lo que no es recomendable.
La otra forma de colocar la relación es especificando el atributo “targetEntity” sin especificar el tipo de dato contenido en la colección:
Es importante tener en cuenta que:
a) El lado “many-to-one” siempre es el lado “owner” de la relación. En consecuencia, la anotación @JoinColumn debe estar en dicho lado.
b) El lado “one-to-many” es el lado “inverso”, por lo que el elemento “mappedBy” debe ser utilizado en este lado.
c) Si no se especifica el “mappedBy”, JPA considera que es una relación unidireccional de tipo one-to-many por lo que requiere el uso de una tabla de Join. Tener en cuenta que esto puede ocasionar errores al desarrollar aplicaciones.
1.3.6. Relación Many To Many
Cuando una o más entidades se asocian con una “colección” de otras entidades y dichas entidades tienen relaciones sobrepuestas con las mismas entidades “target”, se dice que estamos frente a una relación de tipo “Mucho-a-Muchos”.
Por ejemplo: Un “Empleado” pueden trabajar en múltiples “Proyectos” y cada “Proyecto” puede tener a muchos “Empleados”.
La relación “Muchos-a-Muchos” se puede expresar en las dos entidades (“source” y “target”) utilizando la anotación @ManyToMany. Teniendo en cuenta que:
a) Cuando la relación “Many-To-Many” es bidireccional, ambos lados de la relación deben tener la anotación @ManyToMany.
b) No existen columnas de join en cada lado de la relación: la única forma de implementar esta relación es utilizando una tabla de join, por lo que no existe manera de determinar CUAL es el lado “owner” de la relación, en consecuencia, se debe asumir que uno de los lados es el “owner”.
c) Al igual que en las relaciones bidireccionales anteriormente tratadas, el lado que no sea “owner” debe utilizar el “mappedBy”, en caso se omita este elemento, JPA deducirá que se trata de dos relaciones unidireccionales separadas.
El modelo de base de datos es:
A nivel de base de datos, una “Join Table” consiste simplemente de dos “Foreign Key” o columnas de join que referencian (cada una) a un lado de la relación.
La anotación @JoinTable se usa para configurar la tabla de join de la relación:
a) Cada columna de Join se distingue dependiendo del papel dentro de la relación: lado owner o lado inverso.
b) La columna de Join que pertenece al lado “owner” se describe usando el elemento “joinColumns”.
c) La columna de Join que pertenece al lado “inverse” se describe usando el elemento “inverseJoinColumns”.
En el ejemplo, falta indicar la JoinTable de la siguiente forma (asumiendo que Employee es el owner de la relación).
Tenga en cuenta que el elemento “name” dentro de @JoinColumn especifica el nombre de la columna en la tabla de Join, mientras que el elemento
1.3.7. Opciones de Fetch
Las entidades y sus atributos pueden ser cargados de dos formas:
LAZY: Cuando se cargan de forma “perezosa”, es decir, se cargan en el momento en que se requieren.
EAGER: Cuando se cargan de forma “proactiva”, es decir, al momento de cargar la entidad “owner” de la relación.
En términos de JPA, se usa el elemento “fetch” acompañando a la anotación de la relación e indicando el valor de FetchType.LAZY o FetchType.EAGER.
En una relación de valores simples el FetchType por defecto es EAGER. En una relación de colecciones de valores, el FetchType por defecto es LAZY.
En una relación bidireccional, el FetchType puede ser EAGER en un sentido y LAZY en el otro dependiendo del tipo de navegación que se desea.
Resumen
1. Recordar que en JPA, existen cuatro tipos de relaciones entre entidades: One To One
One To Many Many To One Many To Many
Pueden revisar los siguientes enlaces para ampliar los conceptos vistos en esta unidad:
La API de criterios, que sirve para construir consultas basadas en objetos Java en lugar de escribir los queries en strings.
1.4.1. Introducción a JPQL
Los antecedentes de JPQL se pueden encontrar en la especificación de EJB 2.0 con el lenguaje EJB-QL en el cual se introdujo una forma de navegar entre los Beans y sus relaciones, así como filtros y funciones agregadas.
Los queries operan dentro de una unidad de persistencia y pertenecen a una de las siguientes clasificaciones:
a) SELECT, son queries que recuperan una o más entidades, filtrando los resultados si fuera necesario.
b) AGGREGATE, los queries de este tipo son variaciones de los queries del tipo SELECT, con la salvedad que agrupan resultados para producir información sumarizada (de ahí la necesidad de usar la cláusula GROUP BY).
c) UPDATE, son queries que se emplean para actualizar un conjunto de entidades.
d) DELETE, son queries que se utilizan para remover un conjunto de entidades.
Al utilizar los queries se debe considerar que las entidades son referenciadas por su nombre. Si una entidad no tiene asignado un nombre de forma explícita, JPA asume el nombre de la clase como nombre por defecto: este nombre se conoce como “abstract schema name” de la entidad dentro del contexto del query.
También, es importante resaltar que para los queries es indiferente el uso de mayúsculas y minúsculas salvo en dos casos: nombre de entidades y nombres de atributos de cada entidad.
Dada una entidad como la siguiente (entidad “Employee”):
El query más sencillo que se pueden ejecutar es el siguiente:
correspondiente a la entidad.
d) El tipo de resultado de un Query no puede ser una Colección. Debe ser un tipo simple o una Entidad.
A partir del uso del “alias” para la entidad, se puede utilizar la notación “dot” (el punto “.”) para referenciar campos persistentes de la entidad. Por ejemplo, si queremos seleccionar únicamente los nombres de los empleados sería así:
En este caso, como el campo “nombre” es un String, el resultado del query devolverá uno o más Strings. De la misma forma puede trabajarse para cualquier otro atributo, sea una lista, colección o campos simples.
El seleccionar algunos campos de la entidad (al igual que en SQL) recibe el nombre de “proyección”. Se debe tener en cuenta su uso si es que se van a descartar (no usar) varios atributos de la entidad al momento de generar reportes (dada la sobrecarga que se genera en el framework JPA).
En el siguiente ejemplo, se puede seleccionar una entidad que no está en la cláusula FROM:
Observe que “departamento” es una campo de la entidad “Employee”, pero a la vez es una Entidad (dada la relación establecida @ManyToOne). Por tanto, el resultado de ese query será una entidad “Department” obtenida a partir de la relación.
FILTROS
Al igual que en SQL, se puede filtrar los resultados a obtener utilizando la cláusula WHERE y la notación “dot”.
JPQL incluye operadores como IN, LIKE y BETWEEN, funciones como SUBSTRING y LENGTH además de soportar subqueries.
En este ejemplo, el filtro lo constituye el atributo “nombre” de la entidad “Department” que está vinculada con la entidad “Employee”.
JOIN ENTRE ENTIDADES
Al igual que en SQL, si se desea navegar entre las relaciones de las entidades y retornar elementos de la colección, se debe ejecutar un JOIN entre entidades.
Se puede ejecutar el JOIN al más puro estilo del tradicional SQL indicando los criterios de JOIN en la cláusula WHERE.
Sin embargo, JPQL proporciona la facilidad de especificar el JOIN dentro de la cláusula FROM con la finalidad de expresar el JOIN en términos de la relación existente entre las entidades: JPA se encargará de armar la sentencia SQL equivalente.
Un JOIN ocurre si se cumple cualquiera de las siguientes condiciones en el SELECT: 1) Dos o más declaraciones de variables son listadas en la cláusula FROM y
aparecen en la cláusula SELECT.
2) El operador JOIN es empleado para extender a una variable de identificación usando “expression path”.
3) Un “path expression” en cualquier parte del query navega a través de un campo de asociación en la misma o en otra entidad.
4) Una o más condiciones WHERE comparan atributos de variables de identificación diferentes.
Se debe tener en cuenta que ante la ausencia de condiciones de JOIN entre entidades, se generará un producto cartesiano entre la primera entidad y cada ocurrencia de la segunda entidad.
INNER JOIN
Un “inner join” entre dos entidades se puede especificar de cualquiera de la maneras indicadas anteriormente. Sin embargo, la forma preferida es mediante el uso del operador JOIN en la cláusula FROM.
La sintaxis básica es:
OUTER JOIN
Un “outter join” entre dos entidades produce un ámbito en el cual solo un lado de la relación es requerido para completar el resultado. Por ejemplo, un outer join entre “Empleado” y “Departamento” mostrará todos los empleados y los departamentos a los que han sido asignados, pero con la salvedad que el “Departamento” será retornado únicamente si existe dentro de la relación (a diferencia de un inner join).
Su sintaxis es la siguiente:
LEFT [OUTER] JOIN <path_expression> [AS] <identifier>
Ejemplo 1:
FETCH JOIN
Este tipo de Join sirve para ayudar a los programadores a optimizar los accesos a la base de datos. Permite que los queries especifiquen una o más relaciones que deben ser navegadas y pre-cargadas por el mecanismo de recuperación de datos de tal forma que no se ejecuten “lazy load” en tiempo de ejecución. En otras palabras, reduce la cantidad de accesos a la base de datos.
QUERIES AGREGADOS
La sintaxis es muy similar a SQL: se requiere el uso del agrupamiento con GROUP BY Es opcional el uso del filtro mediante la cláusula HAVING.
JPA incluye cinco funciones agregadas: AVG: Promedio aritmético.
COUNT: Cantidad de repeticiones. MIN: Menor valor.
MAX: Mayor valor. SUM: Suma de valores Ejemplo:
En este ejemplo se obtienen todos los departamentos, la cantidad de empleados de cada departamento, el sueldo máximo y el sueldo promedio teniendo en consideración solo aquellos departamentos que tengan más de 5 empleados.
QUERIES
Existen dos formas para definir “queries” en JP-QL:
La primera forma es definirlo dinámicamente en tiempo de ejecución como una cadena de caracteres que se construye de acuerdo al flujo de la aplicación. Esto implica compilar el “query” cada vez.
La segunda forma es definir el “query” vía anotación o XML y referenciarlo por el nombre cada vez que se requiera (algo similar a IBATIS). A diferencia de la forma anterior, los “queries nombrados” son estáticos, pero son mucho más eficientes para ser ejecutados.
1.4.2. Consultas dinámicas
Un query se puede definir de forma dinámica simplemente pasando una cadena de caracteres con la sentencia JPQL al método createQuery () del EntityManager.
Ahora bien, se puede indicar el resultado esperado o se puede omitir y de esta forma tendremos un query sin tipo definido (“unTyped query”).
Se debe tener en consideración (al igual que en JDBC) las implicancias de concatenar un query y luego pasarlo al EntityManager para evitar la inyección de código SQL malicioso. Por ello es preferible usar parámetros. También, para aquellos queries empleados con mayor frecuencia, es preferible usar los queries nombrados (NamedQueries).
Un ejemplo con TypeQuery:
Un ejemplo con Query:
La sentencia JP-QL TypedQuery
Clase que retorna el query
La clase Order.java tiene un método toString()
1.4.3. Consultas nombradas
Este tipo de query sirve para organizar y mejorar el desempeño de una aplicación. Se define empleado la anotación @NamedQuery, la cual se coloca dentro de la definición de una Entidad: la anotación define no solamente el nombre del query sino también la sentencia JPQL en sí.
Se recomienda escribir los queries de manera ordenada de tal forma que ayuden a la visibilidad y lectura de los mismos dentro de la definición de la entidad.
El nombre del query (atributo “name”) debe ser único dentro de toda la unidad de persistencia. Si se hace caso omiso a esta restricción, los resultados pueden ser imprevisibles en tiempo de ejecución.
Se puede definir múltiples queries nombrados empleando la anotación @NamedQueries, la cual es un arreglo que acepta varias anotaciones @NamedQuery.
Ejemplo: El mismo query del ejemplo anterior, pero ahora definido en la clase Order.java
Se invoca así:
La clase Order.java tiene un método toString()
Query
Query JPQL Nombre del Query
Si deseamos definir varios NamedQueries en la entidad, se tendría que hacer así:
Y se puede invocar así:
Query JPQL #1
Query JPQL #2 Anotación
1.4.4. Uso de parámetros
Los parámetros enviados a un “query” permiten la reutilización de sentencias de forma tal que las consultas ejecutadas con diferentes parámetros en cada invocación, retornen diferentes resultados. Es preferible enviar parámetros a las consultas en lugar de estar construyendo una nueva cadena de caracteres por cada invocación, pues así se evita compilar repetidas veces los “queries”.
PARÁMETROS NOMBRADOS
Se utilizan cuando dentro de la sentencia JPQL, los parámetros van precedidos por el símbolo de “:” seguido del nombre del parámetro.
Al momento de ejecutar el query, el programador debe especificar el nombre del parámetro (empleando el método setParameter) y el valor a ser cargado para reemplazarlo dentro de la sentencia JPQL.
Los parámetros nombrados proporcionan claridad al código de la sentencia JPQL (cuando se utilizan nombres adecuados), por lo que son preferidos respecto a los parámetros ordinales.
Ejemplo usando parámetros nombrados:
PARÁMETROS ORDINALES
Se utilizan cuando dentro de la sentencia JPQL, los parámetros van precedidos por el símbolo de “?” seguido del número del parámetro.
Al momento de ejecutar el query, el programador debe especificar el número del parámetro y el valor a ser cargado para reemplazarlo dentro de la sentencia JPQL. Ejemplo con parámetros ordinales:
La sentencia JP-QL
Colocando los valores Note el uso de “named parameters”
1.4.5. Ejecución de Queries
JPA proporciona tres formas de ejecutar queries:
a) Para queries que retornan un único valor se aplica el método getSingleResult ().
b) Para queries que retornan una lista de valores se aplica el método getResultList ().
c) Para queries que ejecutan sentencias de delete/update se aplica el método executeUpdate ().
Se debe tener presente que:
a) Por defecto, los queries devuelven listas desordenadas.
b) Cuando se aplica el método getResultList (), el tipo de dato retornado es una
Collection (si no hay resultados, se devuelve una Collection vacía). Sin embargo, la
variable Java que recibe los resultados debe ser de tipo List. Ejemplo:
c) Cuando se aplica el método getSingleResult (), si no existen resultados se devuelve la excepción NoResultException (la aplicación deberá controlar la excepción). La ocurrencia de esta excepción no genera un rollback de la transacción en curso.
d) Cuando se aplica el método getSingleResult (), si existen muchos resultados (en lugar de uno) se devuelve la excepción NoUniqueResultException (la aplicación deberá controlar la excepción). La ocurrencia de esta excepción no genera un rollback de la transacción en curso.
e) Cualquier query de tipo SELECT puede especificar además el uso de modos de bloqueo para los registros seleccionados con el fin de no impactar en la base de datos los indicadores de rendimiento. Esto se ejecuta vía el método setLockMode ().
variable Identificador que sigue las reglas de Java.
state_field_exp Término utilizado para apuntar hacia un campo de la entidad. Por ejemplo: Si “Alumno” está representado por la variable “a”, se puede apuntar a los campos como: a.código, a.nombre. single_rel_exp Término utilizado para apuntar hacia un campo de una entidad,
pero que resuelve relaciones de tipo one-to-one o many-to-one.
Por ejemplo: Si “Alumno” está representado por la variable “a”, se puede apuntar a los campos como: a.cursos, a.cursos.notas. multi_rel_exp Término utilizado para apuntar hacia un campo de una entidad, pero que resuelve relaciones de tipo one-to-many o many-to-many.
Por ejemplo: Si “Alumno” está representado por la variable “a”, se puede apuntar a los campos como: a.teléfonos
rel_field Término compuesto de una variable y una de los campos relacionados sin navegar por relaciones intermedias.
Por ejemplo: Si “Alumno” está representado por la variable “a”, se puede usar a.ciclo
constructor_method Constructor para una clase que no es Entidad.
Input_param Variable que representa a un parámetro de entrada y debe ser asignado antes que el query sea ejecutado.
literal Valor de un tipo particular (por ejemplo un string como “hola” o un int como 99).
pattern_value Un string que representa un valor SQL válido. Por ejemplo: “%PEREZ”
3. Recordar que el método createNamedQuery del EntityManager sirve para la creación de consultas “nombradas”, las cuales se definen como anotación (utilizando @NamedQuery) dentro de la entidad respectiva.
4. Las anotaciones @NamedQuery y @NamedQueries se utilizan para definir consultas “nombradas”.
5. El método setParameter sirve para asignar un valor a un parámetro de una sentencia JPQL. Existen dos formas: por parámetro nombrado y por parámetro ordinal.
Pueden revisar los siguientes enlaces para ampliar los conceptos vistos en esta unidad:
JAVA SERVER FACES 2
LOGRO DE LA UNIDAD DE APRENDIZAJEAl término de la unidad, el alumno, construye una aplicación Web utilizando el modelo MVC y toda la funcionalidad provista por el framework JSF (Java Server Faces) en Primefaces en la capa Vista y JPA en la capa controlador TEMARIO
2.1 Tema 5 : Fundamentos de JSF 2.1.1 : Introducción a JSF 2.1.2 : Arquitectura de JSF
2.1.3 : Ciclo de vida de un request 2.1.4 : Facelets
2.1.5 : Managed Bean
2.1.6 : Lenguaje de Expresiones JSF 2.1.7 : Backing Beans
2.2 Tema 6 : Componentes de Interfaz de usuario 2.2.1 : Introducción
2.2.2 : Arquitectura de Componentes UI 2.2.3 Librería Core
2.2.4 Librería HTML
2.2.5 Librería User Interface
2.2.6 Librería de Componentes Compuestos
2.3 Tema 7 : Conversiones, Validaciones y Eventos 2.3.1 : Introducción
2.3.2 : El sistema de Conversión de JSF 2.3.3 El sistema de Validación de JSF 2.3.4 El sistema de Mensajes de JSF 2.3.5 El modelo de Eventos de JSF
2.4 Tema 8 : Integración JSF y JPA 2.4.1 : JSF y AJAX
2.4.2 : Integración JSF + JPA
2.4.3 : Empleando otras implementaciones de JSF 2.4.4 : Tablas JSF: Facets, dataTable y panelGrid 2.4.5 : Mantenimiento de tablas
ACTIVIDADES PROPUESTAS
2.1. FUNDAMENTOS DE JSF
2.1.1. Introducción a JSFJava Server Faces (JSF) es el estándar “oficial” en la capa web para la plataforma Java EE. JSF incluye un conjunto de componentes predefinidos para la interfaz gráfica web (UI), un modelo de programación basado en eventos y la habilidad para añadir componentes desarrollados por terceros.
El objetivo de la tecnología Java Server Faces (JSF) es construir aplicaciones web de forma similar a cómo se construyen aplicaciones standalone con Java Swing, AWT (Abstract Window Toolkit), SWT (Standard Widget Toolkit) o cualquier otra API similar. JSF fue creado mediante el trabajo de la organización JCP (Java Community Process) mediante la especificación JSR 127 iniciada a mediados del año 2001 y finalizada en Marzo del 2004. Su principal objetivo es facilitar el desarrollo de interfaces gráficas para las aplicaciones web por medio de los siguientes caminos:
Proporciona un desarrollo basado en componentes, independientes del cliente. De esta manera se incrementa la productividad del desarrollador.
Simplifica el acceso y administración de los datos capturados o enviados a la interfaz de usuario.
Maneja de forma automática el estado de la interfaz de usuario entre múltiples peticiones HTTP.
Proporciona un “framework” amigable mediante el uso de patrones de arquitectura para las aplicaciones web.
En resumen, toma los mejores elementos de los frameworks que le precedieron (CGI, Servlet, JSP, Struts, Spring MVC) y los combina en un conjunto de API’s estándares para el desarrollo de interfaces de usuario.
La versión actual es JSF 2.0 y está soportada por las siguientes especificaciones: JSR 127 : Java Server Faces ( http://www.jcp.org/en/jsr/detail?id=127 ) JSR 252: Java Server Faces 1.2 ( http://www.jcp.org/en/jsr/detail?id=252 ) JSR 276: Design-Time Metadata for JavaServer Faces Components
(http://www.jcp.org/en/jsr/detail?id=276 )
JSR 314: Java Server Faces 2.0 (http://www.jcp.org/en/jsr/detail?id=314 )
Al ser JSF una especificación, se pueden encontrar implementaciones de diferentes fabricantes, lo cual permite no vincularse con ningún proveedor en particular y tener la total libertad de seleccionar aquel que más se acomode a nuestras necesidades. Algunas implementaciones de JSF 2.0 son:
Proyecto Mojarra (La implementación de referencia de SUN Microsystems ahora propiedad de Oracle Corp.). Se puede consultar en el siguiente enlace: https://javaserverfaces.dev.java.net/
jQuery. Es un proyecto alojado por Google Code en el siguiente enlace: http://code.google.com/p/jquery4jsf/
2.1.2. Arquitectura de JSF
Los objetivos de diseño de JSF y la manera en que los cumple se aprecian en el cuadro siguiente:
Objetivo de Diseño Forma de Implementación
Objetivo #1:
Crear un framework estándar de componentes UI que pueda ser potenciado por herramientas de desarrollo y que a su vez permita crear UI de alta calidad y manejar la incorporación de dichas UI’s a la aplicación.
JSF proporciona una API basada en componentes que se pueden usar para ensamblar aplicaciones web.
Los componentes UI estándar proporcionados por la especificación, están acompañados de “tag libraries” de tipo “core” y “html” (con funcionamiento muy similar a JSTL)
Objetivo #2:
Definir un conjunto ligero de clases Java para los componentes UI, el estado de los componentes y el manejo de eventos. Objetivo #3:
Proporcionar un conjunto común de componentes UI incluyendo los elementos estándares para formularios HTML. Dichos
componentes deben poder servir para definir nuevos componentes.
Objetivo #4:
Proporcionar un modelo de JavaBeans para controlar los eventos en el lado cliente y conectarlos a la aplicación.
JSF proporciona un mecanismo de fácil empleo mediante el cual los componentes UI en el lado web están débilmente acoplados (mediante un Lenguaje de expresiones similar a JSTL) a los POJO’s del servidor ( conocidos como “Managed beans” )
Los “managed Beans” se declaran en el archivo
faces-config, xml o se usan anotaciones. El control de la conversación se realiza en el “JSF request process Lifecycle”.
Objetivo #5:
Definir API’s para validación de datos de entrada.
El “JSF request process lifecycle” también permite manejar las validaciones y conversiones dependiendo de los eventos que ocurren en la aplicación.
JSF permite construir validaciones personalizadas.
Objetivo #6:
Especificar un modelo para el manejo de i18N en los componentes UI.
JSF proporciona el manejo de “resource bundles” así como de localización (L10N). Los componentes UI automáticamente reconocen estas características una vez que el “bundle” ha sido configurado.
Objetivo #7:
Proporcionar una generación automática del formato apropiado de salida hacia un cliente determinado.
JSF proporciona API’s bastante flexibles basadas en tecnologías de “rendering” que pueden ser “enchufadas” bajo demanda. Por ejemplo, si el cliente es un iPhone el “render” de la página será HTML específico para dicho equipo.
Objetivo #8:
Soportar accesibilidad
JSF confía plenamente en las tecnologías existentes de Java EE. Eso significa que una aplicación JSF es básicamente una aplicación desarrollada bajo los estándares Java EE con algunas configuraciones específicas:
Configuración #1: Dentro del “deployment descriptor” (archivo web.xml) de la aplicación, se debe registrar el servlet controlador (llamado “Faces Controller”). Tener en cuenta que en algunos contenedores web como GlassFish v3 no se requiere el archivo web.xml.
*.faces
También se puede agregar los siguientes “mappings” en el web.xml:
Configuración #2: Opcionalmente se puede tener un archivo de configuración de JSF llamado faces.config.xml el cual está ubicado al mismo nivel que el web.xml
El archivo contiene la configuración de todos los elementos de una aplicación JSF, aunque también pueden emplearse “anotaciones” en el código java para evitar el uso de este archivo. Un ejemplo del contenido del archivo faces-config.xml es:
Configuración #3: Si se está ejecutando la aplicación en un contenedor web que no soporta a JSF, las librerías del framework deben colocarse en el folder “lib” de la aplicación:
La construcción de páginas se realiza con “Facelets XHTML” empleando para ello “tag libraries”. Se puede declarar las librerías usando “XML namespaces” o usando la forma tradicional:
Estas reglas se conocen como JSF Navigation Model