Una introducción a los conceptos y las características básicas de la API de persistencia para la plataforma Java, desde un punto de vista neutral (sin una preferencia por algún proveedor de persistencia en particular) comenzando desde el planteo de la necesidad de un ORM, y pasando luego por conceptos básicos como las relaciones entre entidades, ciclo de vida de las mismas, JPQL, criteria API.
2. Introducción
• Nuestro proyecto esta escrito en torno a
objetos, sin embargo la mayoría de las
soluciones actuales de Base de Datos se basan
en relaciones y vínculos entre estas: son
Bases de Datos Relacionales (RDB).
3. Introducción
• Los objetos contienen datos muy diversos y
dinámicos. Un mismo objeto puede contener
datos simples, datos complejos, datos de
tamaño variable, colecciones variables de
datos, incluso mas objetos dentro de éste!
4. Introducción
• Las tablas o relaciones por lo general
almacenan objetos escalares y de un tamaño
fijo conocido.
6. Introducción
• El núcleo del problema reside en traducir
estos objetos a formas que puedan ser
almacenadas en la base de datos para
recuperarlas fácilmente, mientras se
preservan las propiedades de los objetos y sus
relaciones; estos objetos se dice entonces que
son persistentes.
7. Introducción
• Desde el punto de vista de un programador, el
sistema debe lucir como un almacén de
objetos persistentes. Uno puede crear objetos
y trabajar normalmente con ellos, los cambios
que sufran terminarán siendo reflejados en la
base de datos.
8. Mapeo Objeto-relacional (ORM)
• Es una técnica de programación que sirve para
convertir datos entre el sistema de tipos
utilizado en un lenguaje de programación
orientado a objetos y el utilizado en una Base
de Datos Relacional.
• Se crea una «Base de Datos
Orientada a Objetos» virtual.
9. Mapeo Objeto-relacional (ORM)
• Existen varios frameworks para distintos
lenguajes y aplicaciones que nos realizan de
manera automática este mapeo.
• En esta ocasión veremos como funciona JPA,
el framework estándar de
Java para realizar la
persistencia de objetos.
10. ¿Qué es JPA?
• Framework del lenguaje de programación Java
que maneja datos relacionales en aplicaciones
usando la Plataforma Java en sus ediciones
Standard (Java SE) y Enterprise (Java EE).
• Es una abstracción sobre JDBC que nos
permite realizar dicha correlación objeto-
relacional de forma sencilla, realizando por
nosotros toda la conversión entre nuestros
objetos y las tablas de una base de datos.
11. ¿Qué es JPA?
• Nos permite realizar tanto la conversión
objetos-tabla así como la recuperación de
estos objetos de las tablas correspondientes,
sin utilizar ni siquiera una línea de SQL.
• Puede crear por nosotros el esquema
completo de tablas, y modificaciones
posteriores, simplemente a partir de nuestra
estructura de objetos persistentes!
12. ¿Qué es JPA?
• También nos permite basarnos en un
esquema de tablas ya existente y modelarlo a
través de objetos sin tener q adaptar ninguna
tabla (el framework se adapta a las tablas y
sus relaciones).
13.
14. Componentes de JPA
• La API en sí misma, definida en
javax.persistence.package
• La Java Persistence Query Language (JPQL)
• Metadatos objeto/relacional
15. Interfaz JPA
• JPA solo establece una interfaz común que es
implementada por diversos proveedores de
persistencia, dándonos la posibilidad de elegir
entre varias implementaciones.
• Algunos ejemplos de proveedores de
persistencia son:
17. Conceptos básicos: Entidad
• El concepto principal sobre el que se apoya
este framework es el de Entidad.
• Una entidad de JPA es el equivalente a lo que
sería una entidad del modelo Entidad-Relación
• Una entidad es la mínima unidad de
persistencia.
• Modelamos las entidades mediante clases
Java que cumplen ciertos requisitos.
18. Entidad: Requisitos
• Las entidades se modelan mediante POJO’s (Plain
Old Java Objects)
• La clase entidad debe cumplir cuatro requisitos:
– Tener un constructor sin argumentos (public o
protected).
– Ser una clase de primer nivel (no interna).
– No ser declarada final.
– Implementar la interface java.io.Serializable si es
accedida remotamente.
19. Entidad: Requisitos
• Generalmente, las clases de entidad serán
simples clases que solo contendrán variables
de instancia y sus respectivos getters y
setters.
21. Entidad: ¿Qué se persiste?
• Por defecto, el estado persistente de un objeto
entidad es representado mediante sus variables de
instancia (field access)
• Si se desea, puede indicarse al framework que en vez
de persistir las variables de instancia utilice los
getters y setters del objeto para obtener los datos a
persistir (property access)
22. Relaciones
• El segundo concepto básico es el de las
relaciones.
• Al igual que en el modelo Relacional, estas
vincularán ciertas entidades entre si, con una
cierta cardinalidad y una cierta navegabilidad.
• Las representaremos mediante punteros a las
entidades correspondientes dentro de la
entidad correspondiente.
24. Metadatos
• ¿Cómo le indicamos al framework cuales son
nuestras entidades persistentes y las diversas
configuraciones de las mismas?
• Dos opciones:
– Mediante un archivo de configuración XML
– Mediante Anotaciones en el código fuente
25. Anotaciones
¿Qué son?
• Son una forma de añadir metadatos al código
fuente Java que están disponibles para la
aplicación en tiempo de ejecución.
• El compilador Java almacena los metadatos de
la Anotación en los archivos de clases.
Posteriormente, la JVM u otros programas
pueden buscar los metadatos para determinar
cómo interactuar con los elementos del
programa o cambiar su comportamiento.
26. Anotaciones
¿Qué aportan?
• Información para el compilador (ej.: Detectar
errores, suprimir advertencias)
• Procesamiento de tiempo de compilador y de
tiempo de instalación (ej.: Generación de
XML)
• Procesamiento de tiempo de ejecución
29. Configuración de las entidades
mediante anotaciones
• @Entity: Le indica al framework cuales son
nuestros objetos que se van a persistir.
• La clase marcada con esta anotación debe
cumplir todos los requisitos anteriormente
mencionados
31. Entidades:
Propiedades persistentes
• Lo que se persistirá en nuestra DB por defecto
son los valores de las variables de instancia
(propiedades) de nuestras clases de entidad.
• Excepto que se lo indiquemos explícitamente,
todas las propiedades de la entidad serán
persistidas, al menos las de tipos básicos.
32. Entidades:
Identidad
• Toda entidad debe tener al menos una
propiedad marcada como identidad, cuyo
valor para cada instancia particular la
diferencie del resto.
• La variable de instancia que identificará a la
entidad debe ser marcada con la
anotación @Id
33. Entidades:
Identidad
• Podemos también indicarle al proveedor de
persistencia que nos genere automáticamente
el valor de este campo a medida que creamos
los objetos.
• La manera más sencilla de hacer esto es
anotando al identificador con la anotación
@GeneratedValue
35. Entidades:
Configuración por defecto
• JPA trabaja por configuración por excepción
• Si no se especifica nada, se asume la
configuración por defecto
• Las únicas anotaciones requeridas para que
una entidad sea funcional son @Entity y @Id
36. Entidades:
Propiedades no persistentes
• La manera de indicar que una propiedad
específica de una entidad no debe ser
persistida, es mediante la anotación
@Transient
• Es útil para marcar propiedades derivables.
37. Entidades:
@Table y @Column
• Podemos especificar de manera específica el
nombre que tendrán en la DB los elementos
mapeados.
• Muy útil si la aplicación debe utilizar un
esquema de BD existente.
38. Entidades:
@Table y @Column
• @Table nos permite definir el nombre que
tendrá la tabla que será mapeada en base a
una entidad.
• @Column sirve para indicar explícitamente el
nombre que llevará la columna que guarde el
estado de la propiedad marcada.
• Si no se utilizan las anotaciones @Table y
@Column, JPA asignará los nombres de las
clases y las propiedades.
40. Entidades:
Tipo de acceso a las propiedades
• Permite especificar la manera en que JPA
accederá a los datos de la entidad para
realizar el mapeo.
• Puede ser de dos tipos:
– Acceso a variable (Field access)
– Acceso a propiedad (Property access)
41. Entidades:
Field Access
• Se realiza el mapeo a través de las propias
variables de instancia de la entidad.
• Hay una correlación directa datos del objeto-
datos en los campos de las tablas.
• Anotaciones colocadas sobre las variables de
instancia.
42. Entidades:
Property Access
• El mapeo se hace a través de los métodos getters
y setters de la entidad.
• Permite una mayor encapsulación de los datos.
• Permite aplicar validaciones antes de cargar los
datos desde la DB.
• Hay que asegurarse que su estructura permita
recuperar exactamente el estado.
• Las anotaciones se realizan sobre los «getters»
de la entidad
44. Entidades:
Mapeo de tipos Básicos
• Los tipos mas simples de Java son mapeados
directamente en la BD como columnas del
tipo mas aproximado al tipo de Java (que
permita recuperar exactamente los valores).
• Por lo general no es necesario marcarlos, al
menos que necesitemos indicar alguna opción
de mappeado. Si es así, se utiliza la marca
@Basic.
45. Entidades:
Acceso temprano y demorado
• Podemos indicar el momento en que una
propiedad específica va a ser realmente
obtenida de la BD.
• Esto nos permite ahorrarnos el coste de cargar
dicha propiedad inmediatamente si por su
naturaleza o por su ubicación es ineficiente
traerla sino hasta el momento de su
utilización.
46. Entidades:
Acceso temprano y demorado
• Por defecto, la mayoría de los tipos Java es
obtenido mediante una lectura temprana. De
todos modos, puede explicitarse, por ejemplo
en un tipo básico, mediante
– @Basic(fetch = FetchType.EAGER)
• Para indicar explícitamente la lectura
demorada sobre un tipo básico utilizamos:
– @Basic(fetch = FetchType.LAZY)
48. Entidades: Mapeo de colecciones
• Una entidad puede tener propiedades de tipo
java.util.Collection y/o java.util.Map que
contengan tipos básicos.
• Los elementos de estas colecciones serán
almacenados en una tabla diferente a la que
contiene la entidad donde están declarados.
• El tipo de colección tiene que ser concreto
(como ArrayList o HashMap) y nunca una
interface.
49. Entidades: Mapeo de colecciones
• Podemos definir la lectura temprana o
demorada de los elementos de estas
colecciones mediante la anotación:
– @ElementCollection(fetch = FetchType.EAGER)
– @ElementCollection(fetch = FetchType.LAZY)
• Por defecto la lectura será demorada (Lazy).
50. Entidades: Mapeo de tipos
enumerados
• Podemos mapear tipos enumerados (enum)
mediante la anotacion @Enumerated
• La configuración por defecto de JPA mapeará
cada valor ordinal de un tipo enumerado a
una columna de tipo numérico en la base de
datos.
51. Entidades: Mapeo de tipos embebidos
• Los tipos insertables (embeddables) son
objetos que no tienen identidad, por lo que
para ser persistidos deben ser primero
insertados dentro de una entidad.
• Cada propiedad del tipo insertable será
mapeada a la tabla de la entidad que lo
contenga, como si fuera una propiedad
declarada en la propia entidad.
52. Entidades: Mapeo de tipos embebidos
• Definimos un tipo insertable con la anotación
@Embeddable
• Y lo insertamos en una entidad (u otro tipo
insertable) con la anotación @Embedded
53. Asociaciones entre entidades
• Los modelos de datos incluyen asociaciones
entre las distintas entidades que lo
comprenden.
54. Asociaciones entre entidades
• Estas asociaciones incluyen además de las
entidades involucradas, una cardinalidad que
indica la participación de cada parte en la
asociación.
55. Asociaciones entre entidades
• Otro concepto involucrado es la
navegabilidad, que nos permite determinar la
visión que tiene cada entidad sobre la relación
en cuestión.
56. Asociaciones entre entidades
• En una Base de datos relacional, estas
asociaciones están representadas mediante
campos de clave foranea referenciando a
algún campo clave de alguna tabla que o bien
es la entidad referenciada o bien es una tabla
auxiliar para acceder a los datos
referenciados.
59. Asociaciones entre entidades
• En nuestro modelo de objetos, las
asociaciones simplemente se representan
mediante punteros al objeto o a los objetos en
cuestión.
61. Asociaciones entre entidades
• JPA nos gestiona automáticamente las
relaciones binarias, creando automáticamente
las tablas auxiliares necesarias.
• Según su navegabilidad, existen dos tipos de
relaciones binarias:
– Relaciones unilaterales
– Relaciones bilaterales
62. Asociaciones entre entidades
• Para que el framework realmente maneje
estas asociaciones, necesitamos indicarlas
mediante las anotaciones correspondientes.
– @OneToOne
– @OneToMany
– @ManyToOne
– @ManyToMany
63. Asociaciones unidireccionales
• Solo requieren especificar del lado que es
dueño de la relación (el lado que «ve» la
misma) la propiedad que referencia al objeto
más la anotación correspondiente al tipo de
asociación.
65. Asociaciones bidireccionales
• Requieren de un lado dueño de la relación, el
cual deberá ser anotado de la misma manera
que en las relaciones unidireccionales, y un
lado no-dueño o lado inverso, el cual deberá
tener la referencia a su dueño mas la
anotación inversa correspondiente modificada
por la opción «mappedBy»
67. Asociaciones: Ejemplos
«OneToOne»
• Es la relación mas sencilla.
• En relaciones bidireccionales la foreign key se
coloca del lado dueño de la relación.
71. Asociaciones: Ejemplos
«OneToMany» y «ManyToOne»
• Veremos primero el caso bidireccional, que es
el mas sencillo y se aplica también para
relaciones ManyToOne unidireccionales.
• En este caso, el dueño de la relación debe ser
el lado «Many»
76. Asociaciones: Ejemplos
«ManyToMany»
• Una relacion ManyToMany puede ser
unidireccional.
• El mapeado será realizado de la misma
manera, solo que una de las entidades nunca
usara la tabla de join.
79. Persistencia
• Con lo visto hasta acá, podemos construir
nuestros objetos del negocio e indicar
(mediante anotaciones) la forma en que se
relacionan estas entidades y como queremos
que se persistan en la DB.
• Pero necesitamos ahora un mecanismo que
haga efectiva esta persistencia.
80. Persistencia
• Podríamos pensar que la simple manipulación
de los objetos declarados como entidades
resultará en la persistencia inmediata de los
cambios realizados en la DB; En realidad no
funciona de esa manera, y tampoco sería una
forma eficiente de hacerlo.
• Necesitamos más control sobre que queremos
persistir y cuando.
81. Persistencia:
Entity Manager
• Este control esta dado por un conjunto de
acciones encapsuladas en un objeto
denominado «EntityManager».
• Un EntityManager nos permite básicamente
realizar todas las operaciones de persistencia
(CRUD) de los objetos desde y hacia la DB.
83. Persistencia:
Persistence Context
• Para JPA, una entidad puede estar en uno de
los dos estados siguientes:
– Managed (gestionada)
– Detached (separada)
• Al crear un entityManager, se asocia al mismo
un «Contexto de Persistencia» (inicialmente
vacío) el cuál contiene el conjunto de
entidades que están siendo manejadas por él.
84. Persistencia:
Persistence Context
• A medida que realizamos operaciones sobre
nuestras entidades a través de un Entity
Manager, éstas pasan a pertenecer al
Contexto de Persistencia de éste.
• Las entidades que se encuentran gestionadas
por algun EntityManager son sincronizadas
con la Base de Datos mientras pertenezcan a
ese Contexto de
Persistencia.
85. Persistencia:
Transacciones
• El EntityManager trabaja mediante
Transacciones.
• Podemos trabajar con dos tipos de
transacciones:
– Manejada por la aplicacion (RESOURCE_LOCAL)
– Manejada por el contenedor (JTA)
• Utilizaremos RESOURCE_LOCAL.
87. Persistencia:
Peristence Unit
• Los EntityManager son configurados para
persistir ciertos objetos, para trabajar contra
una base de datos en particular, y para utilizar
un determinado tipo de transacciones.
• Esta configuración es agrupada en lo que se
denomina un Unidad de Persistencia
(«PersistenceUnit»)
88. Persistencia:
Resumen
• El mapeo de entidades se realiza a través de
transacciones utilizando un Entity Manager.
• Las entidades que está manejando
actualmente un Entity Manager se denomina
su Contexto de Persistencia.
• La configuración específica de los
componentes que realizan el mapeo (ORM) se
denomina Unidad de Persistencia.
89.
90. Utilizando los EM
• Se verá como utilizar los Entity Manager en un
entorno Java SE, es decir, «Entity Managers
administrados por la aplicación».
• En entornos Java EE normalmente se utilizan
Entity Managers administrados por el
contenedor, los cuales si bien su
administración es mas sencilla, no es posible
utilizalos en aplicaciones Java SE.
91. Configurando un «Persistence Unit»
• Cada Unidad de Persistencia tiene un nombre
y es declarada mediante un archivo xml.
• Básicamente especificamos tres cosas en una
configuración determinada:
– Nuestras clases marcadas como entities.
– El tipo de transacciones a utilizar.
– El driver JDBC a utilizar para la conexión con la DB.
96. Obtención de un Entity Manager
• Al trabajar Con EntityMangers administrados
por la aplicación, debemos explicitamente
configurar y crear nuestros EntityManagers,
iniciar las transacciones, hacer commit o
rollback de las mismas, etc.
97. Obtención de un Entity Manager:
Paso previo: Factory
• Esta factory nos permitirá obtener Entity
Manager’s pertenecientes a una unidad de
persistencia particular.
• Al crear la factory, debemos pasarle el nombre
de la Unidad de Persistencia que queremos
que utilice para crear nuestros Entity
Manager.
99. Operaciones básicas
• Con lo visto, ya podemos comenzar a persistir
y traer nuestros objetos de la DB.
• A continuación se presenta un conjunto de
operaciones básicas que podemos realizar con
nuestro Entity Manager una vez creado.
100. Persistir una entidad
• Utilizamos el método persist()
• Si el Entity Manager por alguna razón no
puede completar esta acción, arroja una
«PersistenceException»
101. Recuperar una entidad vía #id
• Podemos realizar esta acción directamente
mediante el método find().
• Si la entidad cuyo id es el pasado como
argumento no existe en la BD, find() retorna
null.
102. Borrar una entidad
• Utilizamos el método remove()
• La entidad a borrar debe estar dentro del
contexto de persistencia del Entity Manager.
103. Actualizar una entidad
• Para actualizar una entidad, trabajamos
directamente sobre la entidad en cuestión, es
decir no le avisamos al Entity Manager de los
cambios a realizar, simplemente los
efectuamos.
• Los cambios serán persistidos en la BD al
momento del cierre de la transacción.
104. Actualizar una entidad
• Es importante aclarar que la entidad a
modificar debe estar dentro del Contexto de
Persistencia, de otra manera el Entity
Manager nunca podrá saber que se han
realizado cambios sobre tal entidad y por
ende nunca los persistirá.
• Podemos hacer que una entidad desasociada
de nuestro contexto pase a formar parte de el
utilizando el comando merge()
107. Obtención avanzada de objetos
• Podemos realizar consultas sobre la DB
utilizando un lenguaje muy parecido a SQL
pero orientado a objetos, el JPQL
• JPA 2.0 nos permite crear consultas tipadas
108. JPQL: Ejemplo
• Con getResultList() obtenemos una lista de los
objetos que resultan de la ejecucion de la
consulta.
109. • Si realizamos una consulta la cual estamos
seguros que retorna un único objeto como
resultado, usamos getSingleResult()
110. Patrametros
• La utilización de parametros permite reutilizar
una misma query.
• Esto es más eficiente que modificar el String y
crear otra query ya que no debe recompilarse
la consulta.
111. Otras caracteristicas
• Mapeo de objetos embebidos y enumerados
• Identificadores compuestos
• Restricciones en operaciones en cascada,
orphan remove
• Herencia de entidades
• JPA Criteria API
112. Por donde seguir?
• Buenos tutoriales en internet:
– David Marco, Introducción a JPA:
http://www.davidmarco.es/blog/entrada.php?id=144
– Tutorial oficial de Java EE 6, sección JPA:
http://docs.oracle.com/javaee/6/tutorial/doc/
• Documentaciones de las páginas de los
proveedores de persistencia
• Libros:
– Pro JPA 2: Mastering the Java™ Persistence API
113. That’s all Folks!!
Introducción Práctica a JPA por Manuel Schnidrig se encuentra bajo una Licencia
Creative Commons Atribución-NoComercial-CompartirIgual 3.0 Unported.