Está en la página 1de 16

ejecutndose en una

aplicacin Java SE.




En este articulo , mo-
delare un simple libro
de direcciones
(Address book ) para
una compaa de msi-
ca ficticia llamada Wa-
termelon , para guardar
las direcciones de los
clientes en la base de
datos . Watermelon
vende y distribuye art-
culos de msica as
como instrumentos ,
amplificadores y li-
bros . Voy a usar una
incremental e iterativa
aproximacin para des-
arrollar y persistir el
modelo del negocio.

Mapeo Objeto Relacio-
nal (ORM) ,en otras
palabras persistir los
objetos Java en una
base de datos relacio-
nal - ha tenido su ma-
yor cambio reciente-
mente, gracias, en par-
te a la proliferacin de
mtodos avanzados
que intentan hacer esta
tarea mas fcil .

Entre estas tecnologas
estn los Entity Beans
2.x , TopLink , Hiber-
nate , JDO , y tambin
JDBC con DAO . Con
muchas alternativas
incompatibles , el gru-
po Java EE experto
toma inspiracin de
estos frameworks po-
pulares y creo el api de
persistencia de Java
(JPA) , el cual se puede
usar desde aplicaciones
Java EE o SE.

En pocas palabras
JPA , usa el modelo de
programacin POJO
para la persistencia. A
pesar de que este mo-
delo esta incluido en la
especificacin EJB 3 ,
JPA puede ser usado
fuera de un contenedor
EJB , y esta es la forma
que ser usada en este
articulo . Plain Old
Java Objects ( POJO )
Que es ORM ?
CURSO JAVA DEVELOPER - INSTRUCTOR : LEONARDO TORRES ALTEZ
Java Persistence Api
LINKS DE INTERES :
! EJB3 : http://www.jcp.org/
en/jsr/detail?id=220
! JPA API : http://
java.sun.com/javaee/5/
docs/api/javax/
persistence/package-
summary.html
! DAO: http://java.sun.com/
blueprints/
corej2eepatterns/Patterns/
DataAccessObject.html

Como trabaja JPA ?






Inspirado en los frame-
works como Hiberna-
te , JPA usa anotacio-
nes para mapear obje-
tos a la base de datos
relacional. Estos obje-
tos , usualmente llama-
dos entidades, no tie-
nen nada en comn
con los Entity Beans
2.x . Las entidades JPA
son clases POJOs, no
extienden de ninguna
clase y no implemen-
tan ninguna interface.
Usted no necesita ar-
chivos descriptores
XML para hacer los
mapeos . Si uno se fija
en el API ( java doc )
uno observara que esta
compuesto de pocas
clases e interfaces.

La mayora del conteni-
do de el paquete ja-
vax.persitence son anota-
ciones. Con esto expli-
cado , veremos el si-
guiente ejemplo de
cdigo :
@Entity
public class Customer {

@Id
private Long id;
private String firstname;
private String lastname;
private String telephone;
private String email;
private Integer age;
// constuctors, getters,
setters
}
JPA
JPA

especifica unidad de persistencia ( watermelonPU en este
caso ) . Una unidad de persistencia es declarada en el ar-
chivo persistence.xml y contiene informacin como la
base de datos a usar y el driver JDBC .


<persistence version="1.0" xmlns="http://java.sun.com/xml/ns/persistence">

<persistence-unit name="watermelonPU" transaction-type="RESOURCE_LOCAL">
<provider>
oracle.toplink.essentials.ejb.cmp3.EntityManagerFactoryProvider
</provider>
<class>entity.Customer</class>
<properties>
<property name="toplink.jdbc.url"
value="jdbc:mysql://localhost:3306/watermelonDB"/>
<property name="toplink.jdbc.user" value="root"/>
update , y remove
son llamados entre
transacion.begin() y
transaction.commit
(). Vea los mtodos
CRUD

Que base de datos
usamos ? , La res-
puesta esta en Enti-
tyManagerFactory,
Esta toma un par-
metro que se refiere a una
Lo mnimo necesario ...
Persistence.xml
Customer ( usando el
operador new como cual-
quier otro objeto JAVA ) y
le pasare algo de data co-
mo el "id" , "last name" ,
"email" , etc. Usare el mto-
do EntityManager.persist()
para insertar este objeto en
la base de datos. Yo puedo
luego buscar este objeto
por su identificador usando
el mtodo EntityMan-
ger.find() y actualizar el
mail usando los mtodos
"set" .

La interface EntityManger
no tiene un mtodo upda-
te . Los updates se hacen a
travs de las propiedades
"setters" . Luego borrare el
objeto usando EntityMana-
ger.remove() , notar que
este cdigo usa transaccio-
nes explicitas . Es por eso
que los mtodos persist ,
EntityManager ...
puede ser visto co-
mo una clase DAO
que nos provee un
set de mtodos cl-
sicos ( persist , re-
move ) y buscado-
res ( find ).
Despus de crear el
EntityManager
usando un factory
( EntityManagerFac-
tory ) , instanciare
mi objeto

Esta parte de cdi-
go que vimos
( constructores ,
getter y setter no
son mostrados para
hacer esto mas fcil
de leer ) muestra
una clase Customer sim-
ple . Esta tiene un identifi-
cador (id) , un nombre
( firstname) , apellido ( last-
name) un numero de tel-
fono ( telephone ) , mail
( email ) y edad del cliente
( age ) . Para ser persistente
esta clase tiene que seguir
algunos reglas JPA simples :

# La clase tiene que ser identifi-
cada como una entidad usan-
do la anotacin
@javax.persistence.Entity

# Una propiedad de la clase
tiene que tener un identifica-
dor anotado con
@javax.persistence.Id

# Tiene que haber un construc-
tor sin argumentos


El cdigo que sigue mues-
tra lo mnimo requerido
para definir un "persistence
object" . Ahora vamos a
manipular este objeto,
deseo persistir mi objeto
customer , actualizar algu-
na de sus propiedades y
borrarlo de la base de da-
tos. Estas operaciones sern
echas a travs de la interfa-
ce
javax.persistence.EntityManager de
JPA.

Para esto, quienes estn
familiarizados con el patrn
DAO , el EntityManager
Page 2 JAVA PERSISTENCE API
@Entity
public class Customer {

@Id
private Long id;
private String firstname;
private String lastname;
private String telephone;
private String email;
private Integer age;
// constuctors,
//getters, setters
}

// mtodos CRUD

public void createCustomer() {
// Gets an entity manager
EntityManagerFactory emf = Persisten-
ce.createEntityManagerFactory("watermelonPU");
EntityManager em = emf.createEntityManager();
EntityTransaction trans = em.getTransaction
();

// Instantiates a customer object
Customer customer = new Customer(1L, "John",
"Lennon", "441909", "john@lenon.com", 66);

// Persists the customer
trans.begin();
em.persist(customer);
trans.commit();

// Finds the customer by primary key
customer = em.find(Customer.class, 1L);
System.out.println(customer.getEmail());

// Updates the customer email address
trans.begin();
customer.setEmail("john@beatles.co.uk");
trans.commit();

// Deletes the customer
trans.begin();
em.remove(customer);
trans.commit();

// Closes the entity manager and the factory
em.close();
emf.close();
}
<property name="toplink.jdbc.driver"
value="com.mysql.jdbc.Driver"/>
<property na-
me="toplink.jdbc.password" value=""/>
<property name="toplink.target-
database" value="MySQL4"/>
<property name="toplink.ddl-
generation" value="create-tables"/>
</properties>
</persistence-unit>
</persistence>

En el cdigo arriba , hay
solo una unidad de persis-
tencia , llamada waterme-
lonPU ( el archivo persis-
tence.xml puede contener
muchas unidades de persis-
tencia ) . Usted puede pen-
sar en una unidad de per-
sistencia como un conjunto
de entidades ( el elemento
class ) que comparten pro-
piedades comunes . En este
caso , estas propiedades
son : url de la base de da-
tos , driver JDBC , creden-
ciales. Bajo el elemento
"properties" usted encontra-
ra propiedades especificas
para Top-link por ejemplo
toplink.ddl-generation . Esta
propiedad es usada por
TopLink para generar las
tablas automticamente si
estas no existen aun . Esto
significa que una vez ejecu-
tado el cdigo TopLink a
creado una tabla para guar-
dar la informacin de
customers. la tabla 1
muestra la informacin DDL
( data definition languaje )
de la tabla customer.

Este es el DDL que JPA
gene-
ra
auto-
mticamente de la clase
anotada Customer . Gra-
cias a la codificacin por
defecto que gua JPA ( y
en general Java EE 5 ) No
primary Key en cuatro posi-
bles modos:

# AUTO (default) permite al
proveedor de persistencia
(TopLink en mi caso)
decidir cual de las tres
posibilidades usar.
# SEQUENCE usar un SQL
sequence para obtener el
prximo primary key
# TABLE requiere una tabla
con dos columnas : el
nombre de la secuencia y
su valor ( esta es la estra-
tegia por defecto de To-
pLink )
# IDENTITY usa un
En este punto yo quisiera
mejorar algunas cosas. Pri-
mero que todo, yo no quie-
ro setear un identificador
(primary key)del objeto
pero en lugar de esto quie-
ro que JPA lo incremente
automticamente. Gracias a
las anotaciones , esto es
fcil de hacer.

Solo necesito anotar mi
atributo identificador
@javax.persitence.GeneratedValue
.
Esta anotacin genera un
"identity generator" ,
ej :una columna definida
como auto_increment en
MySQL.

Ahora quiero mejorar mi
mapeo . Primero cambiar el
nombre de la tabla a
"t_customer" en lugar de
"customer". Luego hare el
nombre ( first name ) y el
apellido ( last name ) obli-
gatorios. El mximo largo
de un numero de telfono
(telephone) tiene que ser
15 caracteres y la columna
Unidad de Persistencia
Aadiendo funcionalidades y customizando el mapeo
lumna tiene
el mismo
nombre de
las propie-
dades . Los
tipos de
datos son
tambin
mapeados
por defecto
( ejemplo
String es mapeado a var-
char(255) ).
Customizando
Usted solo necesita aadir
cdigo customizado cuando
el cdigo por defecto es
inadecuado . En mi caso,
porque yo nunca especifico
el nombre de la tabla o
columnas en la clase
Customer JPA asume que
el nombre de la tablas es
igual al nombre de la clase
y que el nombre de la co-
Page 3 JAVA PERSISTENCE API
una entidad es cargada ,
persistida , actualizada o
removida . Una aplicacin
puede ser notificada antes o
despus de ocurridos estos
eventos usando anotacio-
nes . JPA tiene un conjunto
de "callback annotatios" que
pueden ser usadas en mto-
dos y permiten al desarrolla-
dor aadir cualquier regla
de negocios que desee . JPA
llamara al mtodo anotado
antes o despus de estos
eventos . La tabla 4 muestra
las "callback anotations"
Como uso las callback an-
Ahora con el mapeo entre la
clase Customer y la tabla
t_customer quedo mejor
gracias a que las anotacio-
nes @Column y @Table tie-
nen muchos atributos.
Hay otras dos cosas que
quisiera hacer . Primero ase-
gurarme
que todo
telfono es
ingresado
usando
cdigos
internacio-
nales . co-
menzando
con el sm-
bolo '+' .
Segundo , calcular la edad
del customer a partir de
la fecha de nacimiento .
Tengo muchas alternativas
de como hacer estas tareas ,
pero voy a usar "callback
annotations"
Durante su ciclo de vida ,
notatios para mis necesida-
des ? , Primero me encarga-
re del formato del numero
de telfono . Quiero verifi-
car que el primer carcter
del telfono es "+" , Yo pue-
do hacer esto antes que la
entidad sea persistida o ac-
tualizada . solo tengo que
crear un mtodo ( validateP-
honeNumber en mi ejem-
plo , pero el nombre es irre-
levante ) con algo de lgica
de negocios y con las anota-
ciones @PrePersist y
@PreUpdate, JPA hace el
resto.
El cdigo de ejemplo en la
Anotaciones Callback
email tiene que ser renombrada a e_mail con un "underscore" .

Todos estos pequeos cambios pueden ser hechos con las anotaciones. Para cambiar el
nombre ( name ) de la tabla anote la clase con @javax.persistence.Table . La anotacin
@javax.persistence.Column es usada para definir las columnas y tienen una serie de
Una aplicacin
puede ser
notificada antes
o despus de
ocurridos estos
eventos JPA
usando
"callback
annotations"
Page 4 JAVA PERSISTENCE API
siguiente pagina.

Para la edad del cliente ,
hare algo similar, calculare la
edad del cliente antes que la
fecha de nacimiento sea in-
sertada ( @PostPersist ) o
actualizada ( @PostUpdate ) ,
y claro cada vez que el clien-
te es cargado de la base de
datos ( @PostLoad ).

TAMP ) . Entonces estoy en
la capacidad de calcular la
edad del cliente pero yo
necesito persistir esa infor-
macin ? , NO , conociendo
que el valor cambia todos
los aos . Para hacer que
esta propiedad (age) edad
no sea persistente , usare la
anotacin @Transient ( La
Para hacer que esto funcio-
ne . necesito aadir un nue-
vo atributo a la clase Custo-
mer : date of birth . Para
notificar a JPA que mapee
este atributo a una fecha ,
uso la anotacin @Temporal
con el atributo TemporalTy-
pe.DATE ( las opciones son
DATE , TIME , TIMES-
tabla no tendr una colum-
na edad mas ) ver tabla 5.


Anotaciones Callback .. aadir anotaciones
@PostLoad
@PostPersist
@PostUpdate
public void calculateAge() {
Calendar birth = new GregorianCalendar();
birth.setTime(dateOfBirth);
Calendar now = new GregorianCalendar();
now.setTime(new Date());
int adjust = 0;
if (now.get(Calendar.DAY_OF_YEAR) - birth.get(Calendar.DAY_OF_YEAR) < 0)
{
adjust = -1;
}
age = now.get(Calendar.YEAR) - birth.get(Calendar.YEAR) + adjust;
}
@PrePersist
@PreUpdate
private void validatePhoneNumber() {
if (telephone.charAt(0) != '+')
throw new IllegalArgumentException
("Invalid phone number");
}
}
Page 5
el customer tambin remue-
vo el address.
Pero persistiendo y remo-
viendo ambos objetos pare-
ce que se hiciera mas traba-
jo que el que necesito. Se-
ria mejor si yo pudiera per-
sistir o remover justo el
objeto raz ( el Customer ) y
permitir las dependencias
que se persistan o remue-
van automticamente ? ,
TopLink y la codificacin
Como este cdigo muestra ,
usted tiene primero que
instanciar un objeto Custo-
mer y un Adress , Para lin-
kear los dos ,uso un mto-
do setter ( set HomeAd-
dress ) y luego persistido
cada objeto , cada uno en
la misma transaccin. Por-
que no tiene sentido tener
un adress en el sistema que
no este linkeado a un cus-
tomer , cuando yo remuevo
por defecto har las asocia-
ciones opcionales y basa-
das en mis requerimientos,
es decir al persistir o remo-
ver customer tambin se
hace con su address.

Quiero que un Customer
tenga exactamente un Ad-
dress , significa que un va-
lor null no es permitido .
Puedo lograr todo eso
usando la anotacin
One to One Relationship
One to One Relationship
"customer's" uso el cdigo
que sigue :


One to One Relationship
Como tu pueden ver en la
tabla 6 , la clase Address
usa la anotacin @Entity
para notificar a JPA que es
una clase persistente y
@Column para customizar
el mapeo. Creando la rela-
cin entre Customer y Ad-
dress es simple . Yo simple-
mente aado una propie-
dad Address en la clase
Customer . Para persistir la
direccin de los
Ahora que tengo mapeada
mi clase Customer y tengo
anotaciones callback para
validar y calcular data , ne-
cesito aadir una direccin.
Un Customer tiene una y
solo una
address (direccin) enton-
ces Watermelon pueden
enviar al cliente un regalo
por su cumpleaos . Lo
representare como una cla-
se separada, clase Address
con un id , una calle
(street) , una ciudad (city) ,
un
c-
Page 6 JAVA PERSISTENCE API
al persistir o
remover
customer
tambin se hace
con su address
public void createCustomerWithAddress() {
// Instantiates a Customer and an Address objecy
Customer customer = new Customer("John", "Lennon",
"+441909", "john@lenon.com", dateOfBirth);
Address homeAddress = new Address("Abbey Road",
"London", "SW14", "UK");
customer.setHomeAddress(homeAddress);

// Persists the customer with its address
trans.begin();
em.persist(homeAddress);
em.persist(customer);
trans.commit();

// Deletes the customer and the address
trans.begin();
em.remove(customer);
em.remove(homeAddress);
trans.commit();
}

@OneToOne es usada para
anotar una relacin . Este
tiene muchas propiedades
incluyendo un cascade
usado para "cascading" de
cualquier tipo de accin. En
este ejemplo , quiero
"cascade" la accin de per-
sistir y remover. De esta
forma , cuando hago remo-
ve o persist de un objeto
customer este automtica-
mente lleva acabo esta ac-
cin para el "address" . El
atributo fetch dice a JPA
que poltica usar cuando
cargamos una relacin.
Esta puede ser una asocia-
cin de carga tarda ( lazy
loading LAZY) , o
"eagerly" (EAGER) porque
quiero cargar la direccin
de la casa "homeAddress"
tan pronto como el objeto
Customer es cargado.
La anotacin @JoinColumn
tiene los mismos atributos
como @Column , excepto
que es usado para asociar
atributos , En este ejemplo ,
Yo renombro la llave for-
nea en un address_fk y no
permito ningn valor null
( nullable=false)

JPA entonces creara los
siguientes DDLs con una
constraint de integri-
dad ,para la relacin entre
tablas t_customer y t_adress
( ver tabla 7 )
One to One Relationship




Page 7 JAVA PERSISTENCE API
El atributo
fetch dice a JPA
que poltica usar
cuando
cargamos una
relacin
@Entity
@Table(name = "t_customer")
public class Customer {

@Id
@GeneratedValue
private Long id;
(...)
@Transient
private Integer age;

@OneToOne(fetch = FetchType.EAGER, cascade =
{CascadeType.PERSIST, CascadeType.REMOVE})
@JoinColumn(name = "address_fk", nullable = false)
private Address homeAddress;

// constuctors, getters, setters
}
objeto customer y el
c.firstname es la primera
propiedad del objeto
customer . Si ustedes
quieren buscar todos los
customers que viven en
U.S. , ustedes pueden usar
esta notacin , para obtener
al atributo country del obje-
Como usted puede ver en
este query JPQL usa la no-
tacin objeto . Usted tiene
que hacer query no sobre
una tabla, mas bien sobre
un objeto. El carcter
c ( el nombre es irrele-
vante ) es el alias de un
to address. SELECT c FROM
Customer c WHERE
c.homeAddress.country='US';
Ac hay un conjunto de
querys que nosotros pode-
mos hacer con JPQL . Ver
tabla 8
Querying Objects
JPQL Queries, ejemplos ...
dos formas . De cualquiera
de las dos formas el string
"John" es buscado : puede
ser parte del query JPQL o
puede ser pasado como
parmetro , en este ultimo
caso necesito usar el mto-
do setParameter.
Querying Objects, sobre objetos ...
Para hacer querys sobre los
objetos se necesita Entity-
Manager para crear un ob-
jeto Query . Luego tengo el
resultado del query llaman-
do el getResultList o gen-
SingleResult cuando hay
solo un objeto retornado .
En el ejemplo que sigue ,
quiero buscar todos los
Customers quienes tienen
el primer nombre "John" ,
Yo puedo hacer esto de
Hasta ahora yo estoy usan-
do JPA para mapear mis
objetos a una base de datos
relacional y usar el entity
manager para hacer algunas
operaciones CRUD (Create,
read, update and delete ) ,
Pero JPA tambin
permite que hagas
querys sobre los
objetos. Esto usa
"Java Persistence
Query Langua-
ge" ( JPQL) , el
cual es similar a
SQL y es tambin
independiente de
la base de datos ,
Este es un lenguaje
rico que nos per-
mite hacer querys comple-
jos sobre objetos ( asocia-
ciones , herencia , clases
abstractas )
Los querys usan las pala-
bras SELECT , FROM y
WHERE , mas un conjunto
de operadores para filtrar la
data ( IN , NOT IN , EXIST , LIKE , IS
NULL , IS NOT NULL ) o para con-
trolar las colecciones ( IS
EMPTY , IS NOT EMPTY , MEMBER
OF ) , Tambin hay funcio-
nes para manejar Strings
( LOWER , UPPER , TRIM , CONCAT ,
LENGTH , SUBS-
TRING ) , n-
meros ( ABS ,
SQRT , MOD ) , o
colecciones
( COUNT , MIN ,
MAX , SUM ). Co-
mo SQL , tu
tambin pue-
des ordenar
los resultados
( ORDER BY) o
agruparlos
(GROUP BY)
Page 8 JAVA PERSISTENCE API
// Finds the customers who are called John

Query query = em.createQuery("SELECT c
FROM Customer c WHERE
c.firstname='John'");
List<Customer> customers = que-
ry.getResultList();

// Same query but using a parameter
//Query query = em.createQuery("SELECT c FROM
//Customer c WHERE c.firstname=:param");
//query.setParameter(":param", "John");
Usted tiene que
hacer querys no
sobre una tabla,
mas bien sobre
un objeto.

También podría gustarte