Post on 02-Aug-2015
JPA
Java Persistence API (JPA) proporciona un modelo de persistencia basado en POJO"s para mapear bases de datos relacionales en Java. El Java Persistence API fue desarrollado por el grupo de expertos de EJB 3.0, aunque su uso no se limita a los componentes software EJB. También puede utilizarse directamente en aplicaciones web y aplicaciones clientes; incluso fuera de la plataforma Java EE, por ejemplo, en aplicaciones Java SE.
En su definición, se han combinado ideas y conceptos de los principales frameworks de persistencia como Hibernate, Toplink y JDO, y de las versiones anteriores de EJB. Todos estos cuentan actualmente con una implementación JPA.
El mapeo objeto/relacional, es decir, la relación entre entidades Java y tablas de la base de datos, se realiza mediante anotaciones en las propias clases de entidad, por lo que no se requieren ficheros descriptores XML. También pueden definirse transacciones como anotaciones JPA.Java Persistence API consta de tres áreas:
El Java Persistence API
El lenguaje de query
El mapeo de los metadatos objeto/relacional
Basicamente JPA es una API para ORMs (Object-Relational mapping), el cual permite:
Abstraer del proveedor de persistencias, que no es mas que la implementacion que se use. Por ejemplo puede utilizar Hibernate, Toplink, JDO y otros utilizando la misma API (al estilo de JDBC y los drives para cada BD)
Eliminar la necesidad de escribir el SQL que mapea la base de datos a los objetos utilizando simples anotaciones. Ya no se escribiran líneas sql en los programas, sino que se realizaran consultas sobre los objetos.
Poder crear relaciones muchos a uno, uno a uno, uno a muchos y muchos a muchos entre cualquier cantidad de objetos que se quieras una vez mas solo con anotaciones
Controlar la transaccionalidad (utilizando JTA o JDBC) de las consultas y demás. Obviamente ayuda mucho con el tema de la concurrencia y en la forma en que se gestiona
Tiene un cache de primer nivel que por defecto evita estar viendo a la BD muchas veces para lo mismo en una misma transaccion.
Puede utilizar un cache de segundo nivel que incrementara en gran mayoria el rendimiento de la aplicacion y la escalabildidad
Trae un lenguaje de consultas OO facil de usar que permite hacer navegacion entre tablas como si fueran objetos.
por ejemplo,
where empresa.ciudad.pais.nombre = "El Salvador"
donde empresa ciudad y pais son tres tablas diferentes y nombre es una propiedad de Pais.
Requisitos de una Entity JPA
Se anotan con @Entity
Tienen una propiedad anotada con @Id
Constructor sin argumentos public/protected
No puede ser final
Puede extender de otra
Puede ser abstracta
Es un POJO (Plain Old Java Objects), objeto
liviano que no implementan ninguna interfaz
INCO - Facultad de Ingeniería – Montevideo, Uruguay 10
Estado Persistente
Definido por atributos con visibilidad no
pública (privada, protegida, o de paquete)
Atributos persistentes
o Tipos primitivos
o Wrappers de tipos primitivos
o Otras entidades
o Colecciones
INCO - Facultad de Ingeniería – Montevideo, Uruguay 11
Entity JPA - Ejemplo
@Entity
public class Employee {
@Id private int id;
private String name;
private long salary;
public Employee() {}
public Employee(int id) { this.id = id; }
public int getId() { return id; }
public void setId(int id) { this.id = id; }
INCO - Facultad de Ingeniería – Montevideo, Uruguay 12
Entity JPA - Ejemplo
public String getName() { return name; }
public void setName(String name) {
this.name = name;
}
public long getSalary() { return salary; }
public void setSalary (long salary) {
this.salary = salary; }
}
INCO - Facultad de Ingeniería – Montevideo, Uruguay 13
@Table
Es una anotación opcional
Por defecto, la entidad se mapea en el
esquema actual, a una tabla con el mismo
nombre que la entidad
INCO - Facultad de Ingeniería – Montevideo, Uruguay 14
@UniqueConstraints
Permite definir restricciones de integridad
sobre la tabla que estamos creando
En general es usada cuando utilizamos la
facilidad de auto-creación de esquema
@Table(name="CATEGORIES",
uniqueConstraints=
{@UniqueConstraint(
columnNames={"CATEGORY_ID"})
}
)
INCO - Facultad de Ingeniería – Montevideo, Uruguay 15
@Column
Mapea una propiedad o campo persistente a
una columna de una tabla de la base de
datos
@Column(name="USER_ID")
protected Long userId;
INCO - Facultad de Ingeniería – Montevideo, Uruguay 16
@Column
String name
boolean unique
boolean nullable
String table
length (255)
@Column(name=“DESC”,
nullable=false,
length=512, ...
)
private String description;
INCO - Facultad de Ingeniería – Montevideo, Uruguay 17
@Enumerated
Permite mapear enumerados en columnas
de la base de datos
o public enum UserType {SELLER, ADMIN};
Al persistir, tenemos dos opciones
o Salvar el ordinal
o Salvar el string
INCO - Facultad de Ingeniería – Montevideo, Uruguay 18
@Enumerated
Salvamos 0, 1
o @Enumerated(EnumType.ORDINAL)
o protected UserType userType;
Salvamos los strings “SELLER” o “ADMIN”
o @Enumerated(EnumType.STRING)
o protected UserType userType;
Por defecto, se salva el ordinal
INCO - Facultad de Ingeniería – Montevideo, Uruguay 19
Tipos de datos temporales
Las bases de datos hoy día soportan
diferentes tipos de datos temporales
o DATE
o TIME
o TIMESTAMP (DATE + TIME)
@Temporal
o define contra cual de los tipos anteriores
queremos mapear un java.util.Date o un
java.util.Calendar
INCO - Facultad de Ingeniería – Montevideo, Uruguay 20
Tipos de datos temporales
Usamos el enumerado TemporalType
@Temporal(TemporalType.DATE)
protected Date creationDate;
Por defecto, se asume TIMESTAMP,
el de menor granularidad
INCO - Facultad de Ingeniería – Montevideo, Uruguay 21
Tipos de datos temporales
En el caso de los tipos de datos…
o java.sql.Data
o java.sql.Time
o java.sql.TimeStamp
…el mapeo es redundante
INCO - Facultad de Ingeniería – Montevideo, Uruguay 22
Generación de PKs
Cuando identificamos una columna como PK,
lo que le estamos pidiendo a la base es que
fuerce unicidad
Las claves primarias que consisten en datos
del negocio, se denominan natural keys
Un ejemplo de esto, es el número de cédula
de identidad
INCO - Facultad de Ingeniería – Montevideo, Uruguay 23
Generación de PKs
Claves de la forma CATEGORY_ID,
USER_ID se denominan surrogate keys
Estas últimas son muy populares, por su
facilidad de autogeneración
En sistemas que utilizan frameworks de
persistencia, son altamente recomendadas
INCO - Facultad de Ingeniería – Montevideo, Uruguay 24
Generación de PKs
Existen tres formas populares de generar
claves primarias
o A través de campos identity
o A través de secuencias
o Utilizando una tabla numeradora
Cualquiera de los tres mecanismos se
soportan a través de la anotación
@GeneratedValue
INCO - Facultad de Ingeniería – Montevideo, Uruguay 25
Identities
Muchas bases de datos soportan el tipo de
datos IDENTITY
En el caso del usuario, podemos generar la
PK de esta forma:
@Id
@GeneratedValue(strategy=
GenerationType.IDENTITY
)
@Column(name="USER_ID")
protected Long userId;
INCO - Facultad de Ingeniería – Montevideo, Uruguay 26
Identities
Cuidado …
En general este valor es obtenido una vez
que el registro es “commiteado” en la base
Tener en cuenta que no siempre estará
disponible en el programa
INCO - Facultad de Ingeniería – Montevideo, Uruguay 27
Sequences
En este caso, se necesita un generador para
la clave primaria
Las secuencias de la BD cumplen ese rol
Por ejemplo, una secuencia Oracle se puede
declarar de esta forma:
CREATE SEQUENCE USER_SEQUENCE
START WITH 1
INCREMENT BY 10;
INCO - Facultad de Ingeniería – Montevideo, Uruguay 28
@SequenceGenerator
La utilizamos para declarar un generador
asociado a la secuencia
@SequenceGenerator(
name="USER_SEQUENCE_GENERATOR",
sequenceName="USER_SEQUENCE",
initialValue=1,
allocationSize=10
)
INCO - Facultad de Ingeniería – Montevideo, Uruguay 29
Sequence Generator
En la entidad que utiliza el generador,
podemos generar la clave de esta forma:
@Id
@GeneratedValue(
strategy=GenerationType.SEQUENCE,
generator="USER_SEQUENCE_GENERATOR")
@Column(name="USER_ID")
protected Long userId;
INCO - Facultad de Ingeniería – Montevideo, Uruguay 30
Table Generator
Es muy similar al caso anterior, solo que los
valores salen de una tabla numeradora, con
un formato similar a este:
CREATE TABLE SEQUENCE_GENERATOR_TABLE (
SEQUENCE_NAME VARCHAR2(80) NOT NULL,
SEQUENCE_VALUE NUMBER(15) NOT NULL,
PRIMARY KEY (SEQUENCE_NAME)
);
INCO - Facultad de Ingeniería – Montevideo, Uruguay 31
Table Generator
Luego, debemos preparar la tabla para
insertar el primer valor de la secuencia
INSERT INTO SEQUENCE_GENERATOR_TABLE
(SEQUENCE_NAME, SEQUENCE_VALUE)
VALUES
('USER_SEQUENCE', 1);
INCO - Facultad de Ingeniería – Montevideo, Uruguay 32
Table Generator
Luego, configuramos el TableGenerator en el
código
@TableGenerator (
name="USER_TABLE_GENERATOR",
table="SEQUENCE_GENERATOR_TABLE",
pkColumnName="SEQUENCE_NAME",
valueColumnName="SEQUENCE_VALUE",
pkColumnValue="USER_SEQUENCE“
)
INCO - Facultad de Ingeniería – Montevideo, Uruguay 33
Table Generator
Por último, referenciamos este generador
desde la entidad
@Id
@GeneratedValue(
strategy=GenerationType.TABLE,
generator="USER_TABLE_GENERATOR")
@Column(name="USER_ID")
protected Long userId;
INCO - Facultad de Ingeniería – Montevideo, Uruguay 34
Estrategia por defecto
La última opción para la estrategia de
generación, es dejar que el provider de base
de datos decida la mejor alternativa
@Id
@GeneratedValue(
strategy=GenerationType.AUTO)
@Column(name="USER_ID")
protected Long userId;
Herencia
Entidades Concretas (hojas)
Entidades Abstractas: definen estado y
comportamiento a heredar por las subclases
– No anotada: define estado persistente y puede
participar en queries y relaciones con entidades
– Anotada con @MappedSuperclass: define estado
persistente ; no participa en queries ni en relaciones
con entidades
Transient Classes: no definen estado persistente;
pueden ser heredadas
INCO - Facultad de Ingeniería – Montevideo, Uruguay 43
Herencia
INCO - Facultad de Ingeniería – Montevideo, Uruguay 44
Herencia
@Entity
public class Employee {
@Id private int id;
private String name;
@Temporal(TemporalType.DATE)
@Column(name="S_DATE")
private Date startDate;
// ...
}
INCO - Facultad de Ingeniería – Montevideo, Uruguay 45
Herencia
@Entity
public class ContractEmployee extends
Employee {
@Column(name="D_RATE")
private int dailyRate;
private int term;
// ...
}
INCO - Facultad de Ingeniería – Montevideo, Uruguay 46
@MappedSuperclass
public abstract class CompanyEmployee
extends Employee {
private int vacation;
// ...
}
@Entity
public class PartTimeEmployee
extends CompanyEmployee {
@Column(name="H_RATE")
private float hourlyRate;
// ...
}
INCO - Facultad de Ingeniería – Montevideo, Uruguay 47
Herencia
@MappedSuperclass
public abstract class CompanyEmployee extends
Employee {
private int vacation;
// ...
}
@Entity
public class FullTimeEmployee
extends CompanyEmployee {
private long salary;
private long pension;
// ...
}
INCO - Facultad de Ingeniería – Montevideo, Uruguay 48
Transient Classes
public abstract class CachedEntity {
private long createTime;
public CachedEntity() {
createTime =
System.currentTimeMillis();
}
public long getCacheAge() {
return System.currentTimeMillis() -createTime;
}
}
INCO - Facultad de Ingeniería – Montevideo, Uruguay 49
Transient Classes
@Entity
public class Employee extends CachedEntity {
public Employee() {
super();
}
// ...
}
INCO - Facultad de Ingeniería – Montevideo, Uruguay 50
Mapeo de Herencia
Estrategia Single-Table
Estrategia Joined
Estrategia Table-per-Concrete-Class
INCO - Facultad de Ingeniería – Montevideo, Uruguay 51
Estrategia Single-Table
Una sola tabla para guardar instancias de
todas las entidades concretas
Se diferencian por un campo discriminador
Eficiente (no requiere join)
Gran cantidad de valores nulos (una entidad
utiliza sólo sus atributos)
INCO - Facultad de Ingeniería – Montevideo, Uruguay 52
Estrategia Single-Table
@Entity
@Table(name="EMP")
@Inheritance
@DiscriminatorColumn(name="EMP_TYPE")
public abstract class Employee { ... }
INCO - Facultad de Ingeniería – Montevideo, Uruguay 53
Estrategia Single-Table
@MappedSuperclass
public abstract class CompanyEmployee
extends Employee { ... }
@Entity
@DiscriminatorValue("FTEmp")
public class FullTimeEmployee
extends CompanyEmployee { ... }
INCO - Facultad de Ingeniería – Montevideo, Uruguay 54
Estrategia Single-Table
INCO - Facultad de Ingeniería – Montevideo, Uruguay 55
Estrategia Joined
Cada entidad de la jerarquía tiene una tabla
asociada
Refleja la jerarquía
Guarda los datos en forma normalizada sin
desperdiciar espacio
Una instancia de entidad se guarda en
múltiples tablas
Requiere joins para obtener una instancia de
una entidad concreta
INCO - Facultad de Ingeniería – Montevideo, Uruguay 56
Estrategia Joined
INCO - Facultad de Ingeniería – Montevideo, Uruguay 57
Estrategia Joined
@Entity
@Table(name="EMP")
@Inheritance(strategy=InheritanceType.JOINED)
@DiscriminatorColumn(name="EMP_TYPE",
discriminatorType=DiscriminatorType.INTEGER)
public abstract class Employee { ... }
INCO - Facultad de Ingeniería – Montevideo, Uruguay 58
Estrategia Joined
@Entity
@Table(name="CONTRACT_EMP")
@DiscriminatorValue("1")
public class ContractEmployee
extends Employee { ... }
INCO - Facultad de Ingeniería – Montevideo, Uruguay 59
Estrategia Joined
@MappedSuperclass
public abstract class CompanyEmployee
extends Employee { ... }
@Entity
@Table(name="FT_EMP")
@DiscriminatorValue("2")
public class FullTimeEmployee
extends CompanyEmployee { ... }
INCO - Facultad de Ingeniería – Montevideo, Uruguay 60
Estrategia Joined
@Entity
@Table(name="PT_EMP")
@DiscriminatorValue("3")
public class PartTimeEmployee
extends CompanyEmployee { ... }
INCO - Facultad de Ingeniería – Montevideo, Uruguay 61
Estrategia
Table-per-Concrete-Class
Una tabla por cada clase no abstracta
Las propiedades heredadas se repiten en
cada tabla
Se evita la redundancia y también se
evitan todos los joins a nivel de base de
datos
Mapeo
o En la clase raíz añadir @DiscriminatorColumn
o En cada clase hija añadir @DiscriminatorValue
INCO - Facultad de Ingeniería – Montevideo, Uruguay 62
Estrategia
Table-per-Concrete-Class
INCO - Facultad de Ingeniería – Montevideo, Uruguay 63
Estrategia
Table-per-Concrete-Class
@Entity
@Inheritance(strategy=
InheritanceType.TABLE_PER_CLASS)
public abstract class Employee {
@Id private int id;
private String name;
@Temporal(TemporalType.DATE)
@Column(name="S_DATE")
private Date startDate;
// ...
}
INCO - Facultad de Ingeniería – Montevideo, Uruguay 64
Estrategia
Table-per-Concrete-Class
public class ContractEmployee extends
Employee {
@Column(name="D_RATE")
private int dailyRate;
private int term;
// ...
}
INCO - Facultad de Ingeniería – Montevideo, Uruguay 65
Estrategia
Table-per-Concrete-Class
@Entity @Table(name="FT_EMP")
public class FullTimeEmployee extends
CompanyEmployee {
private long salary;
@Column(name="PENSION")
private long pensionContribution;
// ...
}
INCO - Facultad de Ingeniería – Montevideo, Uruguay 66
Entity manager
El API del EntityManager es la parte más
importante e interesante de JPA
Maneja el ciclo de vida de las entidades
Actúa de puente entre el mundo O.O y el
mundo relacional
INCO - Facultad de Ingeniería – Montevideo, Uruguay 67
Entity manager – métodos
public void persist(Object entity);
public <T> T merge(T entity);
public void remove(Object entity);
public <T> T find(Class<T> entityClass,
Object primaryKey);
public void flush();
public void setFlushMode(FlushModeType
flushMode);
public FlushModeType getFlushMode();
INCO - Facultad de Ingeniería – Montevideo, Uruguay 68
Entity manager – metodos
public void refresh(Object entity);
public Query createQuery(String
jpqlString);
public Query createNamedQuery(String
name);
INCO - Facultad de Ingeniería – Montevideo, Uruguay 69
Ciclo de vida
Por más que anotemos una entidad con
@Entity, el EntityManager no sabe nada de
estas, hasta que no se asocia la misma con
el EntityManager
Esta idea es opuesta a como funciona un
MDB o un Session bean
Es más, la idea del EM, es manejar una
entidad el menor tiempo posible
INCO - Facultad de Ingeniería – Montevideo, Uruguay 70
Ciclo de vida
Una entidad que esta siendo administrada
por el EntityManager, se considera managed
o attached
Cuando el EntityManager termina de
administrar la entidad, decimos que esta en
estado detached
Cuando una entidad no pasa por el
EntityMangaer, decimos que esta en estado
transient
INCO - Facultad de Ingeniería – Montevideo, Uruguay 71
Transient entities
Cuando una entidad es recien creada a
traves de new, entonces esta en estado new
o transient
Bid bid = new Bid();
INCO - Facultad de Ingeniería – Montevideo, Uruguay 72
Managed entities
Una entidad entra a estado managed,
cuando es pasada como parámetro a los
métodos persist, merge o refresh
También una entidad esta en estado
managed cuando es recibida como resultado
de un método find
INCO - Facultad de Ingeniería – Montevideo, Uruguay 73
Detached entities
Es una entidad que ya no esta asociada a un
EntityManager
En este estado, ya no tenemos garantía de
que el estado de la entidad se encuentre
sincronizado con la base de datos
La acción de perder ese vinculo, se
denomina Detachment, la de volver a
vincularlo, se denomina Merge
INCO - Facultad de Ingeniería – Montevideo, Uruguay 74
Detached entities
Este tipo de estado es importante, ya que es
necesario cuando una entidad cruza entre
capas de una aplicación
INCO - Facultad de Ingeniería – Montevideo, Uruguay 75
Ciclo de vida de la entidad
INCO - Facultad de Ingeniería – Montevideo, Uruguay 76
Persistence context
Formalmente, un persistence context es un
conjunto de entidades administradas,
controladas por un EntityMangager, durante
un persistence scope
El persistence scope, es el tiempo que un
conjunto de entidades permanecen
administradas
INCO - Facultad de Ingeniería – Montevideo, Uruguay 77
Persistence context
Tenemos dos tipos de persistence scopes
o Transaction
o Extended
INCO - Facultad de Ingeniería – Montevideo, Uruguay 78
Transaction-scoped
EntityManager
Es un entity manager asociado con
persistence scope transaccional
Las entidades “attacheadas” durante la
transacción, son automáticamente
“desatacheadas” al terminar la misma
INCO - Facultad de Ingeniería – Montevideo, Uruguay 79
Extended EntityManager
Un entity manager tiene un tiempo de vida
que abarca varias transacciones
Solo puede ser utilizado dentro de un
Session Bean stateful, durando tanto como la
instancia permanezca activa
INCO - Facultad de Ingeniería – Montevideo, Uruguay 80
Persistiendo entidades
public Item addItem(String title,
String description, byte[] picture,
double initialPrice, long sellerId) {
Item item = new Item();
item.setTitle(title);
item.setDescription(description);
item.setPicture(picture);
item.setInitialPrice(initialPrice);
INCO - Facultad de Ingeniería – Montevideo, Uruguay 81
Persistiendo entidades
…
Seller seller = entityManager.find(
Seller.class,
sellerId);
item.setSeller(seller);
entityManager.persist(item);
return item;
}
INCO - Facultad de Ingeniería – Montevideo, Uruguay 82
Persistiendo relaciones
public User addUser(String username,
String email, String creditCardType,
String creditCardNumber,
Date creditCardExpiration) {
User user = new User();
user.setUsername(username);
user.setEmail(email);
BillingInfo billing = new BillingInfo();
billing.setCreditCardType(creditCardType);
INCO - Facultad de Ingeniería – Montevideo, Uruguay 83
Persistiendo relaciones
…
billing.setCreditCardNumber(
creditCardNumber);
billing.setCreditCardExpiration(
creditCardExpiration);
user.setBillingInfo(billing);
entityManager.persist(user);
return user;
}
INCO - Facultad de Ingeniería – Montevideo, Uruguay 84
Cascading
Por defecto, el comportamiento de JPA es
de NO persistir entidades relacionadas
En el caso anterior, el BillingInfo no sería
insertado automáticamente
Para que esto funcione, debemos modificar
el cascading de la relación
INCO - Facultad de Ingeniería – Montevideo, Uruguay 85
Cascading
El cascading define como se propaga la
operación sobre los elementos relacionados,
cuando hacemos una operación en el
elemento “padre”
public class User {
@OneToOne(cascade=CascadeType.PERSIST)
public void setBillingInfo(
BillingInfo billing) {
INCO - Facultad de Ingeniería – Montevideo, Uruguay 86
Cascading
La idea es similar al cascading en base de
datos
Por defecto el cascading esta vacío, por lo
que no existe propagación de operaciones de
persistencia
Los valores posibles salen del enumerado
CascadeType
o ALL, MERGE, PERSIST, REFRESH, o REMOVE
INCO - Facultad de Ingeniería – Montevideo, Uruguay 87
Cascading
Si el cascading no es especificado, entonces
deberemos manualmente propagar las
operaciones de persistencia
Para esto, en el ejemplo anterior, debemos
primero persistir el BillingInfo y luego el User
INCO - Facultad de Ingeniería – Montevideo, Uruguay 88
Recuperación por primary key
JPA soporta el método find en el
EntityManager
A este método debemos pasarle la clase que
estamos buscando, y el valor de la primary
key que estamos filtrando
Seller seller = entityManager.find(
Seller.class,
sellerId);
INCO - Facultad de Ingeniería – Montevideo, Uruguay 89
Fetch modes
Tenemos dos posibilidades
o Eager o Lazy
En el modo Lazy, los datos son cargados de
la base de datos en demanda, cuando son
utilizados
En el modo Eager, los datos son cargados al
levantar la entidad
INCO - Facultad de Ingeniería – Montevideo, Uruguay 90
Ejemplo de Fetch mode
A nivel de relación:
@ManyToOne(fetch=FetchType.LAZY)
public Seller getSeller() {
return seller;
}
INCO - Facultad de Ingeniería – Montevideo, Uruguay 91
Fetch modes por defecto
Por la característica especial de alguna
relaciones, el comportamiento por defecto del
fetch para relaciones es diferente según el
tipo de relación
o One-to-one = EAGER
o One-to-many = LAZY
o Many-to-one = EAGER
o Many-to-many = LAZY
INCO - Facultad de Ingeniería – Montevideo, Uruguay 92
Actualizando entidades
Lo interesante de utilizar JPA como
mecanismo de ORM, es que todos los
detalles de la actualización de entidades
persistentes, es transparente
Esto es debido a que los objetos que están
asociados al EntitiyManager, son
administrados por el mismo, lo que incluyeoperaciones de actualización
INCO - Facultad de Ingeniería – Montevideo, Uruguay 93
Actualizando entidades
public void calculateCredit(Long sellerId) {
PowerSeller seller = entityManager.find(
PowerSeller.class, sellerId);
seller.setCreditWorth(100);
.. código ..
seller.setCreditMax(200);
.. código ..
}
INCO - Facultad de Ingeniería – Montevideo, Uruguay 94
Detachment y merge
Si bien una entidad attached es
extremadamente útil, es difícil mantenerlas
attacheadas todo el tiempo
Un caso típico se da en las aplicaciones web
Es común que las entidades tengan que ser
serializadas y enviadas a la capa web
En la capa web, las entidades serán
cambiadas, fuera del scope del
EntityManager
INCO - Facultad de Ingeniería – Montevideo, Uruguay 95
Detachment y merge
public Item addItem(String title,
String description, byte[] picture,
double initialPrice, long sellerId) {
Item item = new Item();
item.setTitle(title);
...
entityManager.persist(item);
return item;
}
INCO - Facultad de Ingeniería – Montevideo, Uruguay 96
Detachment y merge
El ítem devuelto por el método, será enviado
a presentación (web), donde puede ser
modificado
En algún momento, necesitamos asociar este
elemento con la base de datos nuevamente,
para sincronizar su estado
Para esto usamos el método merge
INCO - Facultad de Ingeniería – Montevideo, Uruguay 97
Detachment y merge
INCO - Facultad de Ingeniería – Montevideo, Uruguay 98
Detachment y merge
merge nos garantiza que el objeto está
asociado nuevamente con el persistence
context, y que eventualmente será
sincronizado con la base de datos
public Item updateItem(Item item) {
entityManager.merge(item);
return item;
}
INCO - Facultad de Ingeniería – Montevideo, Uruguay 99
Detachment y merge
Cuando el método updateItem termine, la
base de datos será actualizada con el estado
del ítem
El método merge solo puede ser usado para
entidades que existan en la base de datos
Si tratamos de mergear un elemento no
existente, se producirá una
IllegalArgumentException.
INCO - Facultad de Ingeniería – Montevideo, Uruguay 100
Borrado de entidades
Utilizamos el método remove del entity
manager
El único detalle de este método, es que solo
pueden eliminarse entidades que han sido
“mergeadas” con el persistence context
public void deleteItem(Item item) {
entityManager.remove(
entityManager.merge(item));
}
INCO - Facultad de Ingeniería – Montevideo, Uruguay 101
Refresh de entidades
Permite cargar los datos de una entidad,
desde la base de datos
No es muy común de usar, aunque a veces
puede ser útil para deshacer los cambios en
una transacción
public Item undoItemChanges(Item item) {
entityManager.refresh(
entityManager.merge(item));
return item;
}
INCO - Facultad de Ingeniería – Montevideo, Uruguay 102
Refresh de entidades
Sin embargo, hay un escenario donde es
muy útil.
Que pasa si al insertar un registro en la base
de datos, la propia base modifica el valor de
algunas columnas a través de un trigger
En este caso, desde Java solo veremos lo
insertado, ya que los datos generados por la
base no serán cargados
INCO - Facultad de Ingeniería – Montevideo, Uruguay 103
Refresh de entidades
public Item addItem(String title,
String description, byte[] picture,
double initialPrice, long sellerId) {
Item item = new Item();
item.setTitle(title);
...
entityManager.persist(item);
entityManager.flush();
entityManager.refresh(item);
return item;
}
INCO - Facultad de Ingeniería – Montevideo, Uruguay 104
Flushing
Las operaciones del EntityManager, como
persist, merge y remove, no alteran la base
de datos inmediatamente
Principalmente esto se hace por motivos de
performance
Las operaciones SQL en modo batch suelen
ser mas performantes que las operaciones
emitidas de a una por vez
INCO - Facultad de Ingeniería – Montevideo, Uruguay 105
Flushing
Las operaciones anteriores (alteraciones de
la base) son pospuestas hasta que se
flushee el EntityManager
Por defecto, el modo de flush es AUTO
Esto significa que el flush es emitido por el
EntityManager según sea necesario
INCO - Facultad de Ingeniería – Montevideo, Uruguay 106
Flushing
El modo de flush lo controlamos utilizando el
enumerado FlushModeType
Para efectuar el flush, hacemos:
entityManager.setFlushMode(
FlushModeType.COMMIT);
entityManager.flush();
INCO - Facultad de Ingeniería – Montevideo, Uruguay 107
Entity Manager
Persistence Scope Transaction
@Stateless
public class ProjectServiceBean implements
ProjectService {
@PersistenceContext(
unitName="EmployeeService")
EntityManager em;
INCO - Facultad de Ingeniería – Montevideo, Uruguay 108
Entity Manager
Persistence Scope Transaction
public void assignEmployeeToProject(
int empId, int projectId) {
Project project = em.find(Project.class,
projectId);
Employee employee =
em.find(Employee.class, empId);
project.getEmployees().add(employee);
employee.getProjects().add(project);
}
INCO - Facultad de Ingeniería – Montevideo, Uruguay 109
Entity Manager
Persistence Scope Extended
@Stateful
public class DepartmentManagerBean implements
DepartmentManager {
@PersistenceContext(
unitName="EmployeeService",
type=PersistenceContextType.EXTENDED)
EntityManager em;
Department dept;
INCO - Facultad de Ingeniería – Montevideo, Uruguay 110
Entity Manager
Persistence Scope Extended
public void setName(String name) {
dept.setName(name);
}
public void addEmployee(int empId) {
Employee emp = em.find(Employee.class,
empId);
dept.getEmployees().add(emp);
emp.setDepartment(dept);
}
}
INCO - Facultad de Ingeniería – Montevideo, Uruguay 111
Entity Manager
Persistence Scope Extended
Que ocurre si en el ejemplo anterior omitimos
declarar como EXTENDED el
PersistenceContextType ?
INCO - Facultad de Ingeniería – Montevideo, Uruguay 112
Entity Manager
Persistence Scope Extended
o Se asume por defecto PersistenceContextType
TRANSACTION
o Asumiendo que no hay una transacción activa en
el cliente, cada método iniciaría y terminará una
transacción (recordar REQUIRED)
o Lo anterior hará que el entity manager use
diferentes Persistence Contexts cada vez
o Si ya pasamos por el método init, se tendrá una
instancia creada de Departament, por lo tanto
cada vez que se invoque por ejemplo setName,
actuará sobre esta entidad. Y ???
INCO - Facultad de Ingeniería – Montevideo, Uruguay 113
Entity Manager
Persistence Scope Extended
o Como la ejecución de init terminó su transacción,
dejó a la instancia Departament detached
o Las sucesivas invocaciones a setName actuarán
sobre la misma instancia, cambiando el valor del
atributo name
o Pero …
o Los cambios nunca se impactarán en la base
de datos
INCO - Facultad de Ingeniería – Montevideo, Uruguay 114
Recuperando información
Con JPA podemos usar los siguientes
métodos para recuperar información
o El metodo EntityManager.find(…)
o Queries escritas en JPQL
o Queries nativas escritas en SQL
INCO - Facultad de Ingeniería – Montevideo, Uruguay 115
Query API
Los pasos para utilizar una consulta con JPA
son los siguientes:
o Obtener una referencia al EntityManager
o Crear una instancia de una Query
o Ejecutar la query
o Recuperar los resultados (entities)
INCO - Facultad de Ingeniería – Montevideo, Uruguay 116
Queries
El API de consultas de JPA soporta dos tipos
de consultas:
o Named
o Dynamic
INCO - Facultad de Ingeniería – Montevideo, Uruguay 117
Queries
Las Named queries son consultas
almacenadas que pueden ser reutilizadas en
un programa
Las Dynamic queries son consultas que se
forman dinámicamente en el programa
Su estructura se construye
programáticamente
En cualquier caso, su uso es similar
INCO - Facultad de Ingeniería – Montevideo, Uruguay 118
Queries
@PersistenceContext em;
...
public List findAllCategories() {
Query query = em.createQuery(
"SELECT c FROM Category c");
...
return query.getResultList();
}
INCO - Facultad de Ingeniería – Montevideo, Uruguay 119
Named Queries
Se crean asociadas a la entidad que
queremos consultar
La definición puede ser almacenada en
formato XML o en el propio código de la
clase
Las named queries deben tener nombre
único dentro de una persistence unit
INCO - Facultad de Ingeniería – Montevideo, Uruguay 120
Named Queries
@Entity
@NamedQuery(
name = "findAllCategories",
query = "SELECT c
FROM Category c
WHERE c.categoryName
LIKE :categoryName ")
public class Category
implements Serializable {
...
}
INCO - Facultad de Ingeniería – Montevideo, Uruguay 121
Named Queries
@Entity
@NamedQueries({
@NamedQuery(
name = "findCategoryByName",
query = "SELECT c FROM Category c
WHERE c.categoryName LIKE
:categoryName
order by c.categoryId"
),
INCO - Facultad de Ingeniería – Montevideo, Uruguay 122
Named Queries
@NamedQuery(
name = "findCategoryByUser",
query = "SELECT c FROM Category c
JOIN c.user u
WHERE u.userId = ?1“
)
})
@Table(name = "CATEGORIES")
public class Category implements Serializable
INCO - Facultad de Ingeniería – Montevideo, Uruguay 123
Creando una instancia de la
Query
public Query createQuery(String qlString);
public Query createNamedQuery(String name);
public Query createNativeQuery(String,
sqlString);
INCO - Facultad de Ingeniería – Montevideo, Uruguay 124
Creando una instancia de la
Query
public Query createNativeQuery(String
sqlString,Class result-class);
public Query createNativeQuery(String
sqlString,String result-setMapping);
INCO - Facultad de Ingeniería – Montevideo, Uruguay 125
Creando una instancia de la
Query
Algunos ejemplos…
Named
o Query query =
em.createNamedQuery("findAllCategories");
Dynamic
o Query query = em.createQuery("SELECT i
FROM Item i");
INCO - Facultad de Ingeniería – Montevideo, Uruguay 126
Utilizando la interfaz Query
Para ejecutar la consulta…
query = em.createNamedQuery(
"findCategoryByName");
query.setParameter("categoryName",
categoryName);
query.setMaxResults(10);
query.setFirstResult(3);
List categories = query.getResultList();
INCO - Facultad de Ingeniería – Montevideo, Uruguay 127
Parámetros en la Query
En una query, podemos usar una cláusula
WHERE para restringir los valores obtenidos
Por ejemplo, todos los ítems con un precio
determinado, pueden obtenerse así:
SELECT i FROM Item i
WHERE i.initialPrice = ?1
INCO - Facultad de Ingeniería – Montevideo, Uruguay 128
Parámetros en la Query
En el caso anterior, parametrizamos la
consulta utilizando parámetros posicionales
Para establecer el valor del parámetro, basta
con hacer:
query.setParameter(1,100)
INCO - Facultad de Ingeniería – Montevideo, Uruguay 129
Parámetros en la Query
Podemos usar otro tipo de parámetros,
llamados parámetros nombrados (named
parameters)
Son de la forma:
SELECT i FROM Item i
WHERE i.initialPrice = :price
INCO - Facultad de Ingeniería – Montevideo, Uruguay 130
Parámetros en la Query
Estos mejoran muchísima la legibilidad y
búsqueda de errores de una query
Establecer el valor de uno de estos, se
realiza de la siguiente forma:
query.setParameter(“price”,100)
INCO - Facultad de Ingeniería – Montevideo, Uruguay 131
Recuperando una entidad
Si nuestra consulta devuelve una instancia
(tupla) resultado, con el método
getSingleResult podemos obtenerla
Produce error si retorna mas de una tupla
query.setParameter(1,“Categoria”);
Category cat =
(Category)query.getSingleResult();
INCO - Facultad de Ingeniería – Montevideo, Uruguay 132
Recuperando una entidad
try {
...
query.setParameter(1,“Categoria”);
Category cat =
(Category)query.getSingleResult();
...
}catch (NonUniqueResultException ex) {
handleException(ex);
} catch (NoResultException ex) {
handleException(ex);
}
INCO - Facultad de Ingeniería – Montevideo, Uruguay 133
Recuperando una colección
La mayoría de las queries retorna mas de
una tupla resultado
Para esto, podemos usar el método
getResultList()
query.setParameter("lowPrice",
lowPriceValue);
query.setParameter("highPrice",
highPriceValue);
List items = query.getResultList();
INCO - Facultad de Ingeniería – Montevideo, Uruguay 134
Paginado de resultados
setMaxResults permite definir el máximo
numero de entidades que serán traídas en el
result set
setFirstResult permite definir la posición del
primer resultado en el result set
INCO - Facultad de Ingeniería – Montevideo, Uruguay 135
Paginado de resultados
Por ejemplo para traer los próximos 50
resultados, haríamos:
query.setMaxResults(50);
query.setFirstResult(50);
List items = query.getResultList();
INCO - Facultad de Ingeniería – Montevideo, Uruguay 136
JPQL
El procesador de consultas de JPA,
transforma una consulta JPQL en una
consulta SQL
INCO - Facultad de Ingeniería – Montevideo, Uruguay 137
SELECT
Es de la forma:
SELECT c
FROM Category c
WHERE c.categoryName LIKE :categoryName
ORDER BY c.categoryId
INCO - Facultad de Ingeniería – Montevideo, Uruguay 138
SELECT
Una consulta puede tener los siguientes
elementos:
o SELECT
o FROM
o WHERE
o ORDER BY
o GROUP BY
o HAVING
INCO - Facultad de Ingeniería – Montevideo, Uruguay 139
Empaquetado
Se debe definir un descriptor de la unidad de persistencia
o META-INF/persistence.xml
JBoss utiliza Hibernate 3 para implementar JPA
<persistence>
<persistence-unit name=“tsi2_PU">
<jta-data-source>java:myDS</jta-data-source>
<properties>
<property name="hibernate.show_sql" value="false" />
<property name="hibernate.dialect"
value="org.hibernate.dialect.PostgtreSQLDialect" />
<property name="hibernate.hbm2ddl.auto"
value="update" />
</properties>
</persistence-unit>
</persistence>
INCO - Facultad de Ingeniería – Montevideo, Uruguay 140
Empaquetado
Posibles valores de la propiedad
hibernate.hbm2ddl.auto
o validate
o update
o create
o create-drop
INCO - Facultad de Ingeniería – Montevideo, Uruguay 141
Empaquetado
Dos formas de declarar las entidades que
conforman una unidad de persistencia:
o Declarando cada una de sus clases
o Declarando el nombre de un archivo .jar que
contiene las entidades
INCO - Facultad de Ingeniería – Montevideo, Uruguay 142
Empaquetado
<persistence>
<persistence-unit name=“tsi2_PU“>
<jta-data-source>java:myDS</jta-data-source>
…
<class>tsi2.entities.Cliente</class>
<class>tsi2.entities.Empresa</class>
</persistence-unit>
</persistence>
INCO - Facultad de Ingeniería – Montevideo, Uruguay 143
Empaquetado
<persistence>
<persistence-unit name=“tsi2_PU">
<jta-data-source>java:myDS</jta-data-source>
<jar-file>myEntities.jar</jar-file>
</persistence-unit>
</persistence>
INCO - Facultad de Ingeniería – Montevideo, Uruguay 144
Ventajas y Desventajas de JPA
Ventajas
o Simplicidad: una única clase para declarar la
persistencia (con la ayuda de anotaciones)
o Transparencia: las clases a persistir son simples
POJOs
o No hay restricciones con respecto a relaciones entre
objetos (herencia, poliformismo)
Desventajas
o Anotaciones (Descripción de la Base de Datos en el
código) dificultan el mantenimiento.
o Solución: Siempre se puede utilizar un XML