jpa
java	persistence	api
www.argonavis.com.br
introdução	a
Atualizado	em	22/01/2010:	tópicos	de	JPA	2.0
Conteúdo
• 1.	Relacionamento	entre	objetos	(revisão)	
• 2.	Mapeamento	objeto	relacional	
• 3.	Introdução	prática	
• 4.	Mapeamento	básico	de	entidades	
• 5.	Mapeamento	de	associações	
• 6.	Mapeamento	de	componentes	
• 7.	Mapeamento	de	entidades	em	herança	
• 8.	Queries	JPQL	
• 9.	Queries	Criteria	(JPA	2	/	Java	EE	6)	
• 10.	DAO	genérico
1. Relacionamento entre objetos
• Relacionamentos e objetos
• Tipos de relacionamento
• Cardinalidade
• Direção e visibilidade
• Exemplos
Relacionamentos
Produto
Item Pedido Cliente
FachadaLoja FachadaLojaMemoria
Serviços
Entidades
**
Objetos que são coisas: entidades
• Interface para dados: estado
• Classes geralmente possuem várias instâncias,
claramente identificadas
• Business Objects
• Produtos, Itens, Pedidos, Clientes
• Métodos operam sobre seus próprios dados e
sobre objetos dependentes
Objetos que fazem coisas: serviços
• Interface para operações: comportamento
• Classes geralmente representam uma única
instância (singleton)
• Dados (estado) compartilhados
• Application Services
• Fachadas, DAOs, Serviços, Camadas
• Métodos utilizam entidades e outros serviços
para realizar casos de uso
Tipos de relacionamento
• Ligação fraca: uso / associação
– Navio / Porto: porto existe sem navio e navio existe
sem porto e a destruição de um não afeta o outro
– Porto e Navio devem ter interfaces compatíveis (para
permitir que Navio possa atracar)
• Ligação forte: agregação
– Navio / Carga: cada container de carga acrescenta
(agrega) algo ao navio
– Cascade-delete: se navio afundar, a carga vai junto
• Ligação muito forte: composição
– Navio / Casco: o navio não pode ser utilizado
(inicializado) sem que seu casco esteja pronto antes
Em Java: associação
• Associação bidirecional (porto conhece seus navios e cada
navio sabe em que porto está)
class Porto {
private Set navios = new Set();
public Porto() {}
public void addNavio(Navio n) {
navios.add(n);
n.atracar(this);
}
public Set getNavios() {
return navios;
}
}
class Navio {
Porto porto;
public Navio() {}
public void atracar(Porto p) {
porto = p;
}
public boolean atracado() {
return porto != null;
}
}
Em Java: agregação
class Carga {
private double peso;
public Carga(double p) {
peso = p;
}
public double getPeso() {
return peso;
}
public double destruir() {
peso = 0.0;
}
}
class Navio {
private Set<Carga> containers;
private double peso = 100.0;
public Navio() {}
public void carregar(Carga c) {
containers.add(c);
}
public void afundar() {
for(Carga c: carga)
carga.destruir();
}
public double pesar() {
for(Carga c: carga) {
peso += carga.getPeso();
}
}
Agregação unidirecional (navio
conhece suas cargas, mas Carga
desconhece em que navio está)
Em Java: composição
class Estaleiro {
private Navio montar() {
Casco c = new CascoLongo();
Leme m = new LemeHidraulico();
return new Navio(c, m);
}
}
class Navio {
private Casco casco;
private Leme leme;
public Navio(Casco c, Leme m) {
casco = c;
leme = m;
}
public void virarDireita() {
leme.virarEsquerda();
}
public void virarEsquerda() {
leme.virarDireita();
}
}
class CascoLongo implements Casco {
int comprimento = 100;
int largura = 10;
}
abstract class Leme {
abstract void virarEsquerda();
abstract void virarDireita();
}
. . .
Cardinalidade
• Um para muitos, bidirecional
• Um para um, bidirecional
• Muitos para muitos, bidirecional
class Produto {
Item item;
}
class Item {
Produto produto;
}
class Pedido {
Set<Item> itens;
}
class Item {
Pedido pedido;
}
class Aluno {
Set<Turma> turmas;
}
class Turma {
Set<Aluno> alunos;
}
Os atributos
representam estados
visíveis (métodos get/
set)
Direção e visibilidade
• Um	para	muitos,	unidirecional	
• Muitos	para	um,	unidirecional	
• Um	para	um,	unidirecional
class Produto {
}
class Item {
Produto produto;
}
class Pedido {
Set<Item> itens;
}
class Item {
}
class Pedido {
}
class Item {
Pedido pedido;
}
equivalentes
2. Introdução ao mapeamento objeto
relacional (ORM)
• O que é ORM e como funciona?
• Dificuldades da ORM: incompatibilidades
• Usando uma camada de persistência JDBC
• Exemplo: tabelas e objetos + DAO
O que é ORM
• Object Relational Mapping
• Mapeamento de classes a esquemas de
bancos de dados relacionais
– Em tempo de configuração
• Utilização de uma API de persistência
– Em tempo de desenvolvimento
• Persistência transparente de objetos como
registros de um banco de dados
– Em tempo de execução
Por que usar ORM?
• Facilitar o desenvolvimento
– Simplificar, facilitar manutenção
– Separar responsabilidades
• Unir os benefícios de dois mundos
– Preservar as vantagens do paradigma relacional
(robustez, maturidade, facilidade de pesquisa, etc.)
para a camada de persistência
– Preservar as vantagens do paradigma orientado a
objetos (reuso, modularidade, herança,
polimorfismo, etc.) para a camada de negócios
Como funciona?
• Tempo de configuração
– Classes mapeadas a tabelas (esquemas)
• Tempo de execução
– Instâncias (objetos) automaticamente mapeadas a registros
conta correntista saldo
1 Gargantua 1370
2 Pantagruel 3450
3 Gargamel 800
4 Morticia 8200
Classe Conta
String codigo
String nome
double saldo
instância:Conta
codigo="4"
nome="Morticia"
saldo=8200
Tabela Conta
Banco	de	Dados	Relacional
Mas...
• Nem sempre o modelo relacional é equivalente
ao modelo de objetos
– O modelo normalizado mais eficiente geralmente tem
menos tabelas que os objetos do modelo de objetos
mais bem projetado
– Há objetos dependentes que são parte de um objeto
maior (colunas de uma tabela)
– Há objetos que são apenas visões de dados (dados de
várias tabelas)
• Uma boa ferramenta de ORM permite configurar
essas incompatibilidades
Mapeamento ideal
• Neste exemplo, o descasamento entre o
paradigma objeto e relacional não aparece
public class Cliente {
private String userid;
private String nome;
private String endereco;
private Set contas;
// (get/set), etc. ...
}
public class Conta {
private String numero;
private String nome;
private String tipo;
private Cliente usuario;
// métodos, get/set...
}
create table CLIENTE (
USERID VARCHAR(15) NOT NULL PRIMARY KEY,
NOME VARCHAR(50) NOT NULL,
ENDERECO VARCHAR(100)
)
create table CONTA (
NUMERO VARCHAR(10) NOT NULL PRIMARY Key,
NOME VARCHAR(50) NOT NULL,
TIPO VARCHAR(2) NOT NULL,
USUARIO VARCHAR(15) FOREIGN KEY REFERENCES CLIENTE
)
Foreign key USUARIO realiza o
relacionamento
Problema: granularidade
• Vários níveis são possíveis no modelo de objetos
– Baixa: Cliente com endereco (String)
– Mais alta: Endereco é objeto com propriedades: como cep,
cidade, rua, país, etc.
– Ainda mais alta: Rua é objeto com propriedades numero, etc.
• Há dois níveis apenas no modelo relacional
– Tabela (CLIENTE) e coluna (USERID, ENDERECO, etc.)
• Solução: múltiplos objetos mapeados a uma tabela
create table CLIENTE (
USERID VARCHAR(15) NOT NULL PRIMARY KEY,
NOME VARCHAR(50) NOT NULL,
ENDERECO_RUA VARCHAR(50),
ENDERECO_CIDADE VARCHAR(15),
ENDERECO_ESTADO VARCHAR(15),
ENDERECO_CEP VARCHAR(8),
ENDERECO_PAIS VARCHAR(15)
)
Cliente
Endereco
Problema: tipos e subtipos
• Modelo relacional não suporta herança nem
polimorfismo
– Queremos escrever queries que referem-se à classe
Conta e retornar instâncias concretas dessa classe!
• Requer implementação bem mais complexa
Associação
polimórfica!
Cliente Conta
ContaCredito ContaDebito
*
Problema: identidade
• No mundo relacional, existe um critério de igualdade:
– Chave-primária
• No mundo Java há dois
– Igualdade de referência (testado com ==)
– Equivalência (testado com equals())
• Além disso, mapeamento pode associar vários objetos a
uma mesma tabela!
• Complicações adicionais e problemas
– Chaves naturais
– Chaves compostas
– Ausência de chave
– Chaves que podem ser modificadas
problema de design:
deve ser corrigido
devem ser evitadas
em sistemas novos
Problema: associações
• Java representa associações como referências
(ou coleções de) referências para objetos
– São inerentemente direcionais
– Para implementar associações bidirecionais, é preciso
criar referências dos dois lados da associação
– Referências duplas podem ser associações M-N
• No mundo relacional, associações são
representadas por chaves estrangeiras
– Não são inerentemente direcionais
– Pode-se criar associações com projeção e joins
– Associações M-N requerem tabela extra
Problema: navegação em grafos
• Navegação em objetos
– Pula-se de um objeto para outro: obj.getA().getB()
sem que haja um caminho previamente definido
– O equivalente em SQL seria fazer um query para cada
pulo (nó do grafo)
– Portanto, a forma mais natural de navegar entre
objetos em OO é a forma menos eficiente de
recuperar dados em SQL
• Joins podem minimizar queries
– Mas perde-se a flexibilidade da definição dinâmica do
caminho de navegação
Solução
• Usar uma camada de persistência
para lidar com incompatibilidades
entre os paradigmas
– Usar uma arquitetura com separação
em camadas
– Cada camada concentra-se em um
interesse predominante
– Uma das camadas cuida da persistência
• Como implementar
– Escrever uma camada de persistência
(ex: DAO JDBC)
– Usar uma solução como ORM 

(ex: Hibernate)
Camada	de	Apresentação
Camada	de	Negócios
Camada	de	Persistência
3. Introdução prática: Hello World
• Passo-a-passo na construção de uma
aplicação JPA simples
– Criação de um projeto
– Criação dos objetos e das tabelas
– Definição dos mapeamentos
– Configuração do ambiente
– Implementação da persistência
• Siga os passos na sua máquina
Criação do projeto
• Crie um novo projeto no NetBeans
– Pacote raiz: jpaloja
• Dependências
– Inclua todos os JARs do diretório lib/ da distribuição
do Hibernate
– Inclua o driver JDBC do banco de dados
• Crie uma base de dados “aula” no MySQL
– Anote também o nome de usuário e senha para
acesso ao banco de dados
Próximos passos
• Criar tabela no banco
– Opcional: nós vamos gerar a tabela a partir do
próprio objeto Java anotado
• Criar o objeto (POJO)
• Criar as anotações de mapeamento entre o
POJO e a tabela (três anotações)
• Configuração
– Criar arquivo de configuração da persistência
(persistence.xml)
• Utilização
– Implementar classe de testes e usar a API
Regras para construção de POJOs
• Regras para construção de JavaBeans
– Construtor sem argumentos com visibilidade mínima de pacote
– Expor estado usando métodos get/set
• Exemplo: para propriedade do tipo String “texto” use
– String getTexto() e
– void setTexto(String texto)
• Métodos get/set devem seguir as convenções JavaBean
mas não precisam ser públicos
– O JPA enxerga os métodos private
• Métodos get/set a outras entidades determinam
associações e permitem navegação no grafo de objetos
Identidade
• O objeto que será mapeado via JPA deve
ter um campo que possa ser usado como
identificador
– Independente do objeto já ter algum atributo
unívoco (como userid)
• Deve ser um campo inteiro numérico (int,
Integer, long, Long)
– Será usado pelo JPA para controlar a
persistência
POJO: classe Produto
package jpaloja.pojos;
public class Produto {
private Long codigo;
private String nome;
private double preco;
public Produto() { } // construtor vazio (necessário)
public Produto(String nome, double preco) {
this.nome = nome;
this.preco = preco;
}
public Long getCodigo() {
return codigo;
}
private void setCodigo(Long codigo) {
this.codigo = codigo;
}
// outros métodos get/set (...)
}
Crie o POJO no pacote
jpaloja.pojos
O Netbeans guardará na pasta src
do projeto
O Netbeans gera
automaticamente o construtor
utilitário (com argumentos) e os
métodos get/set
Tabela
• Iremos mapear o Produto à seguinte tabela
• Não precisa criar a tabela neste momento pois
iremos gerá-la
CREATE TABLE produto
(
codigo int8 NOT NULL,
preco float8,
nome varchar(255),
CONSTRAINT produto_pkey PRIMARY KEY (codigo)
)
Mapeamento
• Acrescente as seguintes anotações de mapeamento no
arquivo Produto.java
package jpaloja.pojos;
import javax.persistence.*;
@Entity
public class Produto {
@Id
@GeneratedValue (strategy=GenerationType.AUTO)
private Long codigo;
...
}
Mapeamento: tabelas e classes
• O mapeamento da classe à tabela é realizada através da
anotação @Entity
– Se o nome da tabela não for informado, ela terá o mesmo nome
que a classe
package jpaloja.pojos;
import javax.persistence.*;
@Entity
@Table(name = “PRODUTO”)
public class Produto {
...
}
Mapeamento: identificador
• O identificador é mapeado através da anotação @Id à chave
primária da tabela
• A anotação @GeneratedValue informa como a chave será
incrementada pelo provedor de persistência
package jpaloja.pojos;
import javax.persistence.*;
@Entity
public class Produto {
@Id
@GeneratedValue (strategy=GenerationType.AUTO)
private Long codigo;
}
Mapeamento: propriedades
• As propriedades escalares são mapeadas através da anotação
@Column
– Se ela for omitida, todos os métodos automaticamente serão
considerados parte da interface de mapeamento
@Entity
@Table(name = “PRODUTO”)
public class Produto {
@Column(name = “CODIGO”)
private Long codigo;
@Column(name = “NOME”)
private String nome;
@Column(name=”PRECO”)
private double preco;
}
Configuração da persistência
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.0" ... >
<persistence-unit name="LojaVirtual">
<provider>org.hibernate.ejb.HibernatePersistence</provider>
<!-- <jta-data-source>java:/LojaVirtualDS</jta-data-source> -->
<class>lojavirtual.Produto</class>
<properties>
<property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect"/>
<property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver"/>
<property name="hibernate.connection.username" value="root"/>
<property name="hibernate.connection.password" value=""/>
<property name="hibernate.connection.url" value="jdbc:mysql://localhost:3306/test"/>
<property name="hibernate.transaction.manager_lookup_class" 

value="org.hibernate.transaction.JBossTransactionManagerLookup"/>
<property name="hibernate.show_sql" value="true"/>
<!-- <property name="hibernate.hbm2ddl.auto" value="create"/> -->
</properties>
</persistence-unit>
</persistence>
Descomente na primeira
execução para gerar as
tabelas, depois comente
de novo.
Guarde em src/META-INF com
o nome persistence.xml
Utilização da persistência
• Para usar o mecanismo de persistência do JPA, é
preciso inicializar uma sessão do EntityManager
– O EntityManager oferece uma API de operações de
persistência (gravação, leitura, transações)
– Cada sessão ocupa um thread e é obtida a partir de
um EntityManagerFactory ou via injeção de
dependências (em EJB 3)
• No nosso exemplo usaremos EJB 3
– Será preciso criar um EJB (Session Bean) para
gerenciar a persistência, e disponibilizá-lo no JBoss
Principais interfaces
• Todas do pacote javax.persistence
• Persistence
– Oferece um factory method para criar EMF
• EntityManagerFactory
– Equivalente a SessionFactory do Hibernate
• EntityManager
– Equivalente a Session do Hibernate
• Query
– Equivalente a Query do Hibernate
• EntityTransaction
– Equivalente a Transaction do Hibernate
Alguns métodos de EntityManager
• void	persist(E	objeto)	
– Insere	objeto	na	camada	de	persistência	
• E	find(E.class,	Object	id)	
– Localiza	objeto	pelo	ID	
• E	merge(E	objeto)	
– Atualiza	objeto	(e	cascade,	se	houver)	
• Query	createQuery(String	jpql)	
– Cria	um	query	
• Outros:		
– remove(E	objeto),	flush(),	close(),	getTransaction()
Inserir
package loja;
import jpaloja.pojos.Produto;
import javax.persistence.*;
public class Inserir {
public static void main(String[] args) {
EntityManagerFactory emf =
Persistence.createEntityManagerFactory("LojaVirtual");
EntityManager em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin();
Produto p1 = new Produto("Giroscopio", 123.89);
Produto p2 = new Produto("Tesoura", 23.14);
em.persist(p1);
em.persist(p2);
tx.commit();
em.close();
}
}
Listar
package loja;
public class Listar {
public static void main(String[] args) {
EntityManagerFactory emf =
Persistence.createEntityManagerFactory("LojaVirtual");
EntityManager em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin();
Query q = em.createQuery("select p from Produto p”);
List produtos = q.getResultList();
System.out.println( produtos.size() + “ produtos encontrados!”);
for (Object o: produtos.getResultList()) {
Produto p = (Produto) o;
System.out.println( p.getNome() + “ $” + p.getPreco() );
}
tx.commit();
em.close();
}
}
SessionContext do EJB
• Para obter, use injeção de recursos
@Resource

SessionContext ctx;
• A partir do contexto, pode-se localizar objetos e recursos via
JNDI
DataSource ds = ctx.lookup("java:/DefaultDS");
EntityManagerFactory emf = ctx.lookup("emf/loja");
Queue fila = ctx.lookup("jms/Queue");
• É melhor obter um EntityManager usando injeção de recursos
com @PersistenceContext
@PersistenceContext
private EntityManager em;
EJB usando persistência
@Stateless
public class ProdutoFacadeBean implements ProdutoFacadeBeanRemote {
@PersistenceContext(unitName="LojaVirtual")
private EntityManager em;
public List<Produto> retrieveAll() {
Query query = em.createQuery("select p from Produto p");
List<Produto> produtos = query.getResultList();
return produtos;
}
public Produto insert(Produto p) {
em.persist(p);
return em.merge(p);
}
...
Execução
• Isto é um cliente EJB remoto
– Sua execução requer a configuração de um cliente Java EE (contendo JARs /
client do JBoss + jndi.properties informando a localização do servidor)
public class ProdutoTest {
public static void main(String[] args) throws NamingException {
ProdutoFacadeBeanRemote facade;
Context jndi = new InitialContext();
Object obj = jndi.lookup("ProdutoFacadeBean/remote");
facade = (ProdutoFacadeBeanRemote) obj;
Produto p1 = new Produto();
p1.setNome("Produto 1");
p1.setPreco(30.00);
Produto p2 = new Produto();
p2.setNome("Produto 2");
p2.setPreco(50.00);
facade.insert(p1);
facade.insert(p2);
...
JP-QL
• JP Query Language é um dialeto orientado a
objetos do SQL
– Não é uma linguagem de manipulação de dados
(como SQL)
– Não serve para inserir, remover, atualizar (tem como
fazer, mas não se recomenda)
– É usada apenas para recuperação de objetos
• Exemplo
Query q = 

session.createQuery("select u from User u where u.firstname = :fname");
q.setString("fname", "Max");
List result = q.getResultList();
4. Mapeamento de entidades
• A classe deve ser descrita como entidade
– anotada com @Entity (ou declarada como <entity> no
deployment descriptor orm.xml)
– ter um campo @Id (a menos que participe como subclasse de
uma hierarquia mapeada em JPA)
• Deve ter construtor sem argumentos
• Não pode
– ser interface ou um enum ou classe final
– ter variáveis de instância ou métodos finais
• Deve implementar java.io.Serializable se precisar ser
passada por valor
– Ex: se objeto for usado por um cliente remoto, como em EJBs
que têm interface @Remote
Entidades
• Suportam herança, associações polimórficas,
queries polimórficos
– Podem estender classes comuns e vice-versa
– Somente entidades podem ser usadas em queries JPA
• Seu estado persistente é representado pelas
suas variáveis de instância
– acessado via propriedades (métodos get/set) ou
através de suas variáveis de instância
– variáveis de instância não declaradas transient e que
não tenham a anotação @Transient são consideradas
persistentes.
Entidades
• Assinaturas válidas para propriedades:
– Propriedades escalares (value-types) ou lado unitário de
associações com entidades (@Column):

T getProperty() e void setProperty(T t)
– Coleções de escalares (value-types) ou lado múltiplo de
associações com entidades (@JoinColumn)

Set<T> getProperty() e void setProperty(Set<T>) 

(ou Collection, List ou Map)
• Tipos permitidos:
– Value-types: primitivos, String, BigInteger, BigDecimal, Date,
Calendar, Time, Timestamp, byte[], Byte[], char, Character[],
enums e coleções desses valores
– Tipos serializáveis e coleções de tipos serializáveis
– Entidades e coleções de entidades
Exemplo de mapeamento
@Entity
public class Cliente implements Serializable {
@Id
private Long id;
private String nome;
private Endereco endereco;
@OneToMany
private Set<Pedido> pedidos = new HashSet();
@ManyToMany
private Set<Pagamento> formasPagamento = new HashSet();
public Cliente() {}
public Long getId() { return id; }
public void setId(Long id) { this.id = id; }
...
public Collection<Order> getPedidos() { return pedidos; }
public void setPedidos(Collection<Pedido> pedidos) { this.pedidos = pedidos; }
public Set<Pagamento> getFormasPagamento() { return formasPagamento; }
...
}
Usando o mínimo de anotações!
Anotações ausentes (ex:
@Column, @Table, etc.) resultam
em comportamento default (ex:
tabela com mesmo nome que
classe)
As anotações também possuem
muitas propriedades que podem
ser configuradas; se omitidas, são
usadas as propriedades default
Ciclo de vida de uma entidade: 

breve resumo
• A operação new cria uma instância no estado transiente
– Entidade transiente = new Entidade()
• Para tornar a instância persistente é preciso utilizar a
API do EntityManager
– entityManager.persist(transiente);
– Entidade persistente = entityManager.merge(transiente);
• Toda entidade tem uma chave primária.
– Indicada pela anotação @Id (pode ser na superclasse) e
geralmente definida pelo serviço de persistência
– Aplicação nunca deve mudar valor de chave primária.
• Fora do escopo do EntityManager, objeto que já foi
persistente é considerado desconectado (detached)
– Pode ser re-ligado com um merge:

Entidade persistente = entityManager.merge(detached);
5. Mapeamento de associações
• Associações no JPA funcionam da mesma maneira que
associações de objetos em Java
– Associações de objetos em JPA são naturalmente unidirecionais
e não são gerenciadas pelo container (como em EJB 2.1)
• Associações são sempre relacionamentos entre
entidades (diretamente ou via coleções)
• Três tipos
– @OneToOne
– @ManyToOne
– @ManyToMany
• Duas possibilidades para cada tipo
– Unidirecional
– Bidirecional
Associações
• @ManyToOne é a associação mais comum
– O modelo relacional é naturalmente um-para-muitos
– Uma referência simples de objeto é um-para-muitos
– Em associações bidirecionais, do outro lado deve haver @OneToMany
• @OneToOne requer constraints (que são gerados) nas tabelas para
garantir consistência da associação
• @ManyToMany mapeia três tabelas a dois objetos
• Em associações bidirecionais, há anotações de ambos os lados
– Atributo mappedBy é usado em associações bidirecionais para
informar o nome do atributo da outra classe que faz a associação
– @OneToOne CPF cpf; 

à @OneToOne(mappedBy="cpf") Cliente cliente;
– @ManyToMany(mappedBy="alunos") Set<Turma> turmas; 

à @ManyToMany(mappedBy="turmas") Set<Aluno> alunos;
– @ManyToOne(mappedBy="item") Set<Produto> produtos; 

à @OneToMany Item item;
@ManyToOne
• Pode-se mapear tudo com @ManyToOne
• Associações @OneToOne são raras
– Muitas vezes representam composições que devem ser
preferivelmente implementadas usando @Embedded /
@Embeddable (veremos na parte 3, adiante)
• Associações @ManyToMany podem ser implementadas
com três objetos e duas associações @ManyToOne
– As vezes isto é mais simples e adequado, quando se precisa de
um objeto mapeando a associação (join-table)
• Várias anotações e atributos permitem configurar
ajustes finos dos mapeamentos
• Escolha a solução mais simples e adequada ao seu
projeto
ManyToOne unidirecional
@Entity	
public	class	Produto	{	
				@Id	@GeneratedValue	
				int	codigo;	
				String	nome;	
				double	preco;	
				public	int	getCodigo()	{	
								return	codigo;	
				}	
				public	void	setCodigo(int	codigo)	{	
								this.codigo	=	codigo;	
				}	
				public	String	getNome()	{	
								return	nome;	
				}	
				public	void	setNome(String	nome)	{	
								this.nome	=	nome;	
				}	
...
@Entity
public class Item {
@ManyToOne
private Produto produto;
public Produto getProduto() {
return produto;
}
public void setProduto(Produto produto) {
this.produto = produto;
}
public double subtotal() {
return this.produto.getPreco() * this.quantidade;
}
...
Classe Produto não
sabe da existência da
associação*
Método de negócio que utiliza-se da
associação para realizar uma operação
* Esses dados são insuficientes para a geração automática do esquema (as tabelas devem existir antes)
ManyToOne bidirecional
@Entity	
public	class	Pedido	{	
				@OneToMany(mappedBy="pedido")	
				private	Set<Item>	itens	=		new	HashSet<Item>();	
				public	Set<Item>	getItens()	{	
								return	itens;	
				}	
				public	void	setItens(Set<Item>	itens)	{	
								this.itens	=	itens;	
				}	
				public	void	addItem(Item	item)	{	
								itens.add(item);	
								item.setPedido(this);	
				}	
				public	double	subtotal()	{	
								double	subtotal	=	0;	
								for	(Item	item	:	itens)	{	
												subtotal	+=	item.subtotal();	
								}	
								return	subtotal;	
				}	
...
@Entity	
public	class	Item	{	
				@ManyToOne	
				private	Pedido		pedido;	
				public	Pedido	getPedido()	{	
								return	pedido;	
				}	
				public	void	setPedido(Pedido	pedido)	{	
								this.pedido	=	pedido;	
				}		
					
				public	double	subtotal()	{	...	}	
...
Utilitário para facilitar a adiçção de
itens na associação (atualiza os dois
lados da associação)
Método de negócio que utiliza-se da
associação para realizar uma operação
@ManyToMany
• Default: @ManyToMany nos Set de cada lado da
associação, informando o campo de mapeamento
(mappedBy)
– Em associações bidirecionais, é preciso atualizar os dois lados
– Usando-se Set e mappedBy, garante-se a não duplicação de
dados quando objeto é adicionado duas vezes na coleção
• Muitos ajustes possíveis
– Uso de List ou Collection (com ou sem @CollectionID) ou Map
(com @MapKey)
– Configuração de @JoinTable, @JoinColumn, @SecondaryTable
• Essas configurações avançadas não serão abordadas
neste curso
ManyToMany bidirecional
@Entity	
public	class	Aluno	{	
				@Id	@GeneratedValue	
				private	int	id;	
				@ManyToMany(mappedBy="alunos")	
				private	Set<Turma>	turmas;	
				public	Set<Turma>	getTurmas()	{	
								return	turmas;	
				}	
				public	void	setTurmas(Set<Turma>	turmas)	{	
								this.turmas	=	turmas;	
				}	
				public	void	matricular(Turma	turma)	{	
								turmas.add(turma);	
								turma.addAluno(this);	
				}	
...	
}
@Entity	
public	class	Turma	{	
				@Id	@GeneratedValue	
				private	int	id;	
				@ManyToMany(mappedBy="turmas")	
				private	Set<Aluno>	alunos;	
				public	Set<Aluno>	getAlunos()	{	
								return	alunos;	
				}	
				public	void	setAlunos(Set<Turma>	turmas)	{	
								this.alunos	=	alunos;	
				}	
				public	void	addAluno(Aluno	aluno)	{	
								alunos.add(aluno);	
								aluno.matricular(this);	
				}	
...	
}
Métodos utilitários para adicionar alunos e turmas
(não há duplicação porque é um Set)
@OneToOne
• Muitas vezes é desnecessário -relacionamento pode ser
representado de outras formas
– Pode ser @ManyToOne unidirecional
– Pode ser implementado com o componente na mesma tabela
(@Embedded)
• Duas formas de mapeamento @OneToOne
– Associação de chave estrangeira (default)
– Associação de chave primária (não pode definir um
@JoinColumn, mas é anotado com @PrimaryKeyJoinColumn
• Neste curso utilizaremos apenas o mapeamento default
OneToOne bidirecional
@Entity	
public	class	Cliente	{	
				@OneToOne(mappedBy="cliente")	
				private	CPF	cpf;	
				public	CPF	getCPF()	{	
								return	cpf;	
				}	
				public	void	setCPF(CPF	cpf)	{	
								this.cpf	=	cpf;	
				}		
...
@Entity	
public	class	CPF	{	
				@OneToOne	
				private	Cliente	cliente;	
				public	Cliente	getCliente()	{	
								return	cliente;	
				}	
				public	void	setCliente(Cliente	cliente)	{	
								this.cliente	=	cliente;	
				}		
...
Só é necessário informar o
mappedBy em um dos lados
da associação
Cascades: persistência transitiva
• Para acrescentar um item em um pedido, é preciso atualizar dois
objetos
Pedido p = new Pedido();
Item i = new Item();
p.addItem(i); // atualiza dois objetos
• Para persistir essa alteração, também é preciso sincronizar os dois
objetos
em.persist(p);
em.persist(i);
• O ideal é fazer isto automaticamente: cascade
@OneToMany(cascade={CascadeType.PERSIST},	

											mappedBy="item"	)

private	Set<Item>	itens	=	new	HashSet<Item>();
– Quando um Pedido for persistido no banco, quaisquer itens que
estiverem na sua hierarquia de objetos também serão persistidos
CascadeType
• O atributo cascade recebe um array {} de opções
• Há várias opções para CascadeType. Algumas das mais
importantes são
– PERSIST
– MERGE
– REMOVE
• Normalmente, usa-se PERSIST com MERGE (inserts e
updates feitos automaticamente)
@OneToMany(cascade={CascadeType.PERSIST, CascadeType.MERGE})
• Pode-se usar CascadeType.ALL para que todas as
operações sejam transitivas
Recuperação de dados: lazy
• Se você usar um cliente externo que não mantém aberta
a sessão do EntityManager, poderá ter exceções de
inicialização lazy (inicialização preguiçosa) quando for
acessar objetos dentro de coleções
– O query, por default, só retorna a coleção com os ponteiros
para os objetos, e eles só podem ser recuperados do banco se
houver uma sessão aberta
– Como lidar com isto será tratado mais adiante
• Uma forma rápida de resolver o problema (por
enquanto) é declarar nas associações o atributo
fetch=FetchType da forma
@OneToMany(mappedBy="pedido",	fetch=FetchType.EAGER)	
private	Set<Item>	itens	=	new	HashSet<Item>();
Outras anotações de associações
• @JoinColumn(name="coluna", ...)
– Propriedades que não são associações informam a
coluna da tabela a qual estão mapeadas com
@Column
– Associações informam a coluna da associação (foreign
key) usando @JoinColumn
– Se não informada, o sistema assume que a coluna
tem o mesmo nome que o atributo
• Consulte a especificação para maiores detalhes
sobre as outras anotações e seus atributos
6. Mapeamento de composição
• Em ORM, objetos que formam uma composição
compartilham a mesma tabela
– Em JPA, classes que são componentes são mapeadas como
@Embeddable (e não como @Entity) e suas propriedades
anotadas como @Embedded na entidade que as contém
Cliente	
nome	
email	
cartao
Endereco
Rua
CEP
Cidade
enderecoEntrega	
enderecoCobranca
nome email cartao ent_rua ent_cep ent_cidade cob_rua cob_cep cob_cidade
											:Ciente		 			enderecoEntrega:Endereco			 enderecoCobranca:Endereco
<<Entidade>> <<Componente>>
@Entity @Embeddable
@Embedded
Composições (@Embedded)
• O objeto embutido (componente) na entidade é a parte
dependente da relação de composição
– Uma composição ocorre quando uma entidade, que tem
identidade na tabela, está composta por objetos que não têm
identidade na tabela (seus dados são parte da tabela)
– A remoção do registro no banco remove a entidade e seus
objetos componentes (não confunda com cascade-delete)
• O objeto embutido é propriedade da entidade
– Só existem como objetos, mas não como tabelas
• Muitas associações 1-1 podem ser implementados como
objetos embutidos
– Ex: a associação Cliente-CPF mostrada anteriormente
Exemplo com @Embedded
@Entity
@Table(name="CLIENTE")
public class Cliente {
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
private Long codigo;
private String nome;
...
@Embedded
private Endereco enderecoCobranca;
@Embedded
@AttributeOverrides({
@AttributeOverride(name="rua", column=@Column(name="ENT_RUA")),
@AttributeOverride(name="cep", column=@Column(name="ENT_CEP")),
@AttributeOverride(name="cidade", column=@Column(name="ENT_CIDADE")),
})
private Endereco enderecoEntrega;
...
@Embeddable
public class Endereco {
@Column(name="COB_RUA")
private String rua;
@Column(name="COB_CEP")
private String cep;
@Column(name="COB_CIDADE")
private String cidade;
...
}
reusa mesma classe Endereco, mas
redefine mapeamentos
• Herança é o descasamento mais visível entre os mundos
relacional e orientado a objetos
– Mundo OO possui relacionamento “é um” e “tem um”
– Mundo relacional apenas possui relacionamento “tem um”
• Há várias estratégias [Ambler 2002]*
– Uma tabela por classe concreta: modelo relacional ignora
herança e polimorfismo (polimorfismo implícito)
– Uma tabela por hierarquia de classes: permite polimorfismo
com tabelas não normalizadas mais uma coluna extra contendo
informação de tipo
– Uma tabela por subclasse: representa relacionamentos “é um”
através de relacionamentos “tem um” (chave estrangeira)
7. Mapeamento de herança
a. Tabela por classe concreta
• Mapeia classes concretas a tabelas
@Entity	
@Inheritance(strategy=InheritanceType.TABLE_PER_CLASS)		
public	abstract	class	Pagamento	{	
					@Id	@GeneratedValue	private	long	id;	
}
Pagamento	
id	
valor
Credito	
numero	
validade
ID VALOR NUMERO VALIDADE
5
<<Entidade>>
@Entity
Debito	
banco	
conta
<<Entidade>>
@Entity
ID VALOR BANCO CONTA
5
CREDITO
DEBITO
@Entity	
public	class	Debito	extends	Pagamento	{...}
@Id declarado apenas na
superclasse
Tabela por classe concreta
• Vantagens
– Mapeamento direto entre classe e tabela normalizada
• Desvantagens
– Queries mais complexos e ineficientes
• O query polimórfico
select p from Pagamento p where p.valor > 1000
gera um SQL (conceitual) com subquery que concatena
queries nas tabelas com union:
– select ID, VALOR, NUMERO, VALIDADE, BANCO, CONTA from (

select ID, VALOR, NUMERO, VALIDADE, 

null as BANCO, null as CONTA from CREDITO 

union
select ID, VALOR, null as NUMERO, null as VALIDADE, 

BANCO, CONTA from DEBITO 

) where VALOR > 1000
b. Tabela por hierarquia de classes
@Entity	
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)	
@DiscriminatorColumn(name="TIPO")	
public	abstract	class	Pagamento	{	
					@Id	@GeneratedValue	private	long	id;	
}
Pagamento	
id	
valor
Credito	
numero	
validade
ID TIPO VALOR NUMERO VALIDADE BANCO CONTA
5 crd 100.0 23459403 12/15 null null
6 deb 100.0 null null 1234-5 993423-3
<<Entidade>>
@Entity
Debito	
banco	
conta
<<Entidade>>
@Entity
PAGAMENTO
@Entity	
@DiscriminatorValue("deb")	
public	class	Debito	extends	Pagamento	{...}
Coluna (DiscriminatorColumn)
presente na tabela mas sem
mapeamento na classe
b. Tabela por hierarquia de classes
• Mapeia-se a hierarquia inteira a uma única tabela
– Tabela inclui coluna (não mapeada) para identificar a classe
– Há colunas para todas as propriedades de todas as classes
• Vantagens
– Forma mais eficiente de implementar polimorfismo.
– Query polimórfico:
select ID, VALOR, BANCO, CONTA, NUMERO, VALIDADE from
PAGAMENTO where VALOR > 1000
– Query em classe concreta:
select ID, VALOR, BANCO, CONTA, NUMERO, VALIDADE from
PAGAMENTO where TIPO = 'deb' and VALOR > 1000
• Desvantagens
– Tabelas não normalizadas
– Colunas de propriedades declaradas em subclasses precisam
aceitar valores nulos (pode ser ruim para grandes hierarquias)
c. Tabela por subclasse
• Mapeia classes a tabelas
@Entity	
@Inheritance(strategy=InheritanceType.JOINED)		
public	abstract	class	Pagamento	{	
					@Id	@GeneratedValue	private	long	id;	
}
Pagamento	
id	
valor
Credito	
id	
numero	
validade
ID NUMERO VALIDADE
9
<<Entidade>>
@Entity
Debito	
id	
banco	
conta
<<Entidade>>
@Entity
ID BANCO CONTA
5
CREDITO
DEBITO
@Entity	
public	class	Debito	extends	Pagamento	{...}
ID VALOR
5
PAGAMENTO
ID é PK e FK
Uma tabela por subclasse
• Herança como relacionamentos de chave estrangeira
– Cada subclasse tem sua própria tabela
– Cada tabela possui colunas apenas para campos não-herdados, e
chave primária que é chave estrangeira da superclasse
– Recuperação de dados através de um join das tabelas
• Vantagens
– Modelo relacional normalizado
– Evolução e restrições de integridade simples
– Classes/tabelas criadas sem afetar classes/tabelas existentes
• Desvantagens
– Performance baixa em hierarquias complexas
– Difícil de codificar a mão (ruim para integrar com JDBC legado)
• Queries
– Outer join para pesquisas polimórficas, inner join para queries
em classes concretas
Qual estratégia usar?
• Se não houver necessidade de queries polimórficos ou
associações
– Tabela por Classe Concreta (TABLE_PER_CLASS)
• Se houver necessidade de associações polimórficas, e
hierarquia for simples
– Tabela por Hierarquia (SINGLE_TABLE)
• Se houver necessidade de associações polimórficas
mas hierarquia grande (ou não puder usar tabelas não
normalizadas)
– Tabela por Subclasse (JOINED)
8. Queries JPQL
• Toda pesquisa no banco é feita através de Java
Persistence Query Language (JPQL)
– Linguagem de recuperação de dados similar a outras
linguagens de query de objetos (HQL, EJB-QL, etc.)
– Parece com SQL, mas é diferente: opera sobre objetos e não
tabelas – é mais simples
• Queries são objetos da classe Query
– Podem ser criados através métodos de EntityManager
– Instruções do query podem ser passadas diretamente na
criação do query ou declarados em anotações @NamedQuery
– Queries podem ser parametrizados
• Após sua execução, os dados podem ser recuperados
através de métodos da classe Query.
API essencial para Queries JPQL
• EntityManager
– Query createQuery("query jpql");
– Query createNamedQuery("nome de query");
• Query
– List<Tipo> getResultList();
– Object getSingleResult();
– Query setParameter(String var, Object obj);

Query setParameter(int pos, Object obj);
– int executeUpdate();
Named Queries
@Entity	
@NamedQueries({	
				@NamedQuery(name="produtoMaisBarato",	
								query="SELECT	x	FROM	Produto	x	WHERE	x.preco	>	?1"),	
				@NamedQuery(name="produtoPorNome",	
								query="SELECT	x	FROM	Produto	x	WHERE	x.nome	=	:nomeParam")	
})	
public	class	Produto	{	
				...	
}
EntityManager	em	=	...	
Query	q1	=	em.createNamedQuery("produtoMaisBarato");	
q1.setParameter(1,	10.0);	
List<Produto>	resultado1	=	q1.getResultList();		
Query	q2	=	em.createNamedQuery("produtoPorNome");	
q2.setParameter("nomeParam",	10.0);	
List<Produto>	resultado2	=	q2.getResultList();
Declarações (sintaxe)
• SELECT
cláusula_select cláusula_from

[cláusula_where] [cláusula_group_by]
[cláusula_having] [cláusula_order_by]
• UPDATE
cláusula_update
• DELETE
cláusula_delete

Sintaxe elementar
SELECT p.nome
FROM Produto AS p
WHERE p.codigo = '123'
Declara variável p como
sendo um Produto
O que vai ser
selecionado
Parâmetro
SELECT OBJECT (p) 

FROM Produto p 

WHERE p.nome = :n
AS é
opcional
Parâmetro do
método
Objeto (bean) sendo
selecionado
Palavras-chave JPQL
• Usadas na cláusula SELECT
– DISTINCT, OBJECT, AVG, MAX, MIN, SUM, COUNT
• Usadas na cláusula FROM
– IN, AS
• Usadas na cláusula WHERE
– FROM, WHERE, UPDATE, DELETE, JOIN, OUTER, INNER, LEFT,
GROUP, BY, HAVING, FETCH, OBJECT, NULL, TRUE, FALSE,
NOT, AND, OR, BETWEEN, LIKE, IN, AS, UNKNOWN, EMPTY,
MEMBER, OF, IS, ORDER, BY, ASC, DESC, MOD, UPPER,
LOWER, TRIM, POSITION, CHARACTER_LENGTH,
CHAR_LENGTH, BIT_LENGTH, CURRENT_TIME,
CURRENT_DATE, CURRENT_TIMESTAMP, NEW, EXISTS, ALL,
ANY, SOME
Cláusula FROM
• A cláusula FROM é quem informa o objeto
que está sendo pesquisado, e declara
variáveis usados no resto do query
– Cada variável tem um identificador e um tipo
– O identificador é qualquer palavra não-reservada
– O tipo é a classe do objeto marcado como @Entity
– A palavra-chave AS conecta o tipo ao identificador,
mas é opcional
FROM Produto AS p
Tipo Identificador
Cláusula SELECT
• A cláusula SELECT informa o que se deseja obter com
a pesquisa. Pode retornar
– Objetos (interfaces locais ou remotas)
– Atributos dos objetos
• A palavra SELECT pode ser seguida de DISTINCT para
eliminar valores duplicados nos resultados
• SELECT utiliza uma variável declarada na cláusula
FROM (opcionalmente pode usar OBJECT(p))
• Exemplos
SELECT p FROM Produto p
SELECT DISTINCT p FROM Produto p
SELECT p.codigo FROM Produto p
SELECT DISTINCT p.codigo FROM Produto p
Retorna
objetos
Retorna
campos
Cláusula WHERE
• A cláusula WHERE é opcional e restringe os resultados
da pesquisa com base em uma ou mais expressões
condicionais concatenadas
• As expressões podem usar
– Literais (strings, booleanos ou números)
– Identificadores (declarados no FROM)
– Operadores
– Funções
– Parâmetros do método que utiliza a pesquisa (?1, ?
2, :nome, ...)
• Literais
– Strings são representados entre apóstrofes: 'nome'
– Números têm mesmas regras de literais Java long e double
– Booleanos são TRUE e FALSE (case-insensitive)
Operadores
• Expressões matemáticas
– +, -, *, /
• Expressões de comparação
– =, >, >=, <, <=, <>
• Operadores lógicos
– NOT, AND, OR
• Outros operadores
– BETWEEN, NOT BETWEEN
– IN, NOT IN
– LIKE, NOT LIKE
– NULL, NOT NULL
– IS EMPTY, IS NOT EMPTY
– MEMBER, NOT MEMBER
• Operadores do LIKE
– _ representa um único caractere
– % representa uma seqüência de zero ou mais caracteres
–  caractere de escape (necessário para usar _ ou %) literalmente
Algumas funções
• Manipulação de strings (usados em WHERE)
– CONCAT, SUBSTRING, TRIM, LOWER, UPPER
– LENGTH, LOCATE
• Funções aritméticas (usados em WHERE)
– ABS, SQRT, MOD, SIZE
• Data e hora (usados em WHERE)
– CURRENT_DATE, CURRENT_TIME,
CURRENT_TIMESTAMP
• Funções de agregação (usados em SELECT)
– COUNT, MAX, MIN, AVG, SUM
Exemplos
• Encontre todos os produtos que são chips e cuja margem de
lucro é positiva
– SELECT p 

FROM Produto p 

WHERE (p.descricao = 'chip' 

AND (p.preco - p.custo > 0)
• Encontre todos os produtos cujo preço é pelo menos 1000 e no
máximo 2000
– SELECT p

FROM Produto p 

WHERE p.preco BETWEEN 1000 AND 2000
• Encontre todos os produtos cujo fabricante é Sun ou Intel
– SELECT p

FROM Produto p 

WHERE p.fabricante IN ('Intel', 'Sun')
Exemplos de JPA-QL (2)
• Encontre todos os produtos com IDs que começam com 12 e
terminam em 3
– SELECT p

FROM Produto p 

WHERE p.id LIKE '12%3'
• Encontre todos os produtos que têm descrições null
– SELECT p

FROM Produto p 

WHERE p.descricao IS NULL
• Encontre todos os pedidos que não têm itens (coleção)
– SELECT pedido FROM Pedido pedido WHERE pedido.itens
IS EMPTY
• Encontre todos os itens ligados a pedidos em coleção
– SELECT item

FROM Pedido pedido, Item item 

WHERE item IS MEMBER pedido.itens
9. Queries dinâmicos (JPA 2.0)
• Novidade	do	Java	EE	6	
– API	que	permite	a	construção	de	queries	usando	
objetos	
– Inspirado	em	Criteria	do	Hibernate	e	JDO	
– Pode-se	descobrir	erros	nos	queries	em	tempo	de	
compilação	
• Queries	são	mais	longos	e	podem	ser	mais	complexos,	mas	
podem	ser	alterados	dinamicamente	
• Ideal	para	formulários	de	pesquisa	onde	queries	são	
montados	de	acordo	com	preferências	do	usuário
Queries	dinâmicos	(JPA	2.0)
• Pode-se	montar	o	query	JPQL	
• usando	queries	dinâmicos,	da	seguinte	forma:
CriteriaBuilder qb =
em.getCriteriaBuilder();
CriteriaQuery<Produto> cq =
qb.createQuery(Produto.class);
Root<Produto> raiz = cq.from(Produto.class)
Predicate condicao =
qb.lt(raiz.get(Produto_.preco), 50.0);
cq.where(condicao);
TypedQuery<Person> query = em.createQuery(cq);
List<Produto> resultado = query.getResultList();
select p from Produto p where p.preco < 50.0
10. DAO para JPA em EJB 3
• JPA	não	precisa	de	DAO	quando	usado	em	EJB	3,	que	
cuida	dos	contextos	transacionais	
• Mas	um	DAO	ainda	é	importante	
– Camada	de	persistência	não	precisa	ser	JPA	(pode	
ser	JDBC	direto	ou	usar	bancos	não	relacionais	
como	Redis)	
– Permite	isolar	queries	(dinâmicos	do	JPA	2	ou	JPQL)	
• Usando	Generics	pode-se	criar	uma	interface	abstrata	
reusável
DAO	abstrato
public abstract class AbstractFacade<T> {
private Class<T> entityClass;
protected abstract EntityManager getEntityManager();
public AbstractFacade(Class<T> entityClass) {
this.entityClass = entityClass;
}
public void create(T entity) {
getEntityManager().persist(entity);
}
public void edit(T entity) {
getEntityManager().merge(entity);
}
public void remove(T entity) {
getEntityManager().remove(getEntityManager().merge(entity));
}
public T find(Object id) {
return getEntityManager().find(entityClass, id);
}
}
DAO	concreto
• Precisa	apenas	estender	DAO	abstrato	para	cada	entidade	que	
se	deseja	usar	
– Métodos	herdados	disponíveis	para	uso	pelos	clientes	(ex:	EJBs)
@Stateless
public class ProdutoFacade extends AbstractFacade<Produto> {
@PersistenceContext(unitName = "LojaVirtual")
private EntityManager em;
protected EntityManager getEntityManager() {
return em;
}
public ProdutoFacade() {
super(Produto.class);
}
}
Referências
• Material	consultado	na	elaboração	deste	capítulo	
– Oracle.	Especificação	JPA	2.0:	https://jcp.org/aboutJava/
communityprocess/final/jsr317/	e	Especificação	JPA	1.0	
– Apache	OpenJPA:	https://openjpa.apache.org/	
– JBoss.org.	Hibernate	Entity	Manager	User	Guide	http://
docs.jboss.org/hibernate/entitymanager	
– Christian	Bauer	e	Gavin	King.	Java	Persistence	with	Hibernate.	
Manning,	2007	e	edições	anteriores.	
– Oracle,	Eric	Jendrock	et	al.	Java	EE	6	Tutorial.	http://
docs.oracle.com/javaee/6/tutorial/doc/	e	edições	anteriores	
– Versões	anteriores	deste	curso

Introdução a JPA (2010)

  • 1.
  • 2.
    Conteúdo • 1. Relacionamento entre objetos (revisão) • 2. Mapeamento objeto relacional •3. Introdução prática • 4. Mapeamento básico de entidades • 5. Mapeamento de associações • 6. Mapeamento de componentes • 7. Mapeamento de entidades em herança • 8. Queries JPQL • 9. Queries Criteria (JPA 2 / Java EE 6) • 10. DAO genérico
  • 3.
    1. Relacionamento entreobjetos • Relacionamentos e objetos • Tipos de relacionamento • Cardinalidade • Direção e visibilidade • Exemplos
  • 4.
    Relacionamentos Produto Item Pedido Cliente FachadaLojaFachadaLojaMemoria Serviços Entidades **
  • 5.
    Objetos que sãocoisas: entidades • Interface para dados: estado • Classes geralmente possuem várias instâncias, claramente identificadas • Business Objects • Produtos, Itens, Pedidos, Clientes • Métodos operam sobre seus próprios dados e sobre objetos dependentes
  • 6.
    Objetos que fazemcoisas: serviços • Interface para operações: comportamento • Classes geralmente representam uma única instância (singleton) • Dados (estado) compartilhados • Application Services • Fachadas, DAOs, Serviços, Camadas • Métodos utilizam entidades e outros serviços para realizar casos de uso
  • 7.
    Tipos de relacionamento •Ligação fraca: uso / associação – Navio / Porto: porto existe sem navio e navio existe sem porto e a destruição de um não afeta o outro – Porto e Navio devem ter interfaces compatíveis (para permitir que Navio possa atracar) • Ligação forte: agregação – Navio / Carga: cada container de carga acrescenta (agrega) algo ao navio – Cascade-delete: se navio afundar, a carga vai junto • Ligação muito forte: composição – Navio / Casco: o navio não pode ser utilizado (inicializado) sem que seu casco esteja pronto antes
  • 8.
    Em Java: associação •Associação bidirecional (porto conhece seus navios e cada navio sabe em que porto está) class Porto { private Set navios = new Set(); public Porto() {} public void addNavio(Navio n) { navios.add(n); n.atracar(this); } public Set getNavios() { return navios; } } class Navio { Porto porto; public Navio() {} public void atracar(Porto p) { porto = p; } public boolean atracado() { return porto != null; } }
  • 9.
    Em Java: agregação classCarga { private double peso; public Carga(double p) { peso = p; } public double getPeso() { return peso; } public double destruir() { peso = 0.0; } } class Navio { private Set<Carga> containers; private double peso = 100.0; public Navio() {} public void carregar(Carga c) { containers.add(c); } public void afundar() { for(Carga c: carga) carga.destruir(); } public double pesar() { for(Carga c: carga) { peso += carga.getPeso(); } } Agregação unidirecional (navio conhece suas cargas, mas Carga desconhece em que navio está)
  • 10.
    Em Java: composição classEstaleiro { private Navio montar() { Casco c = new CascoLongo(); Leme m = new LemeHidraulico(); return new Navio(c, m); } } class Navio { private Casco casco; private Leme leme; public Navio(Casco c, Leme m) { casco = c; leme = m; } public void virarDireita() { leme.virarEsquerda(); } public void virarEsquerda() { leme.virarDireita(); } } class CascoLongo implements Casco { int comprimento = 100; int largura = 10; } abstract class Leme { abstract void virarEsquerda(); abstract void virarDireita(); } . . .
  • 11.
    Cardinalidade • Um paramuitos, bidirecional • Um para um, bidirecional • Muitos para muitos, bidirecional class Produto { Item item; } class Item { Produto produto; } class Pedido { Set<Item> itens; } class Item { Pedido pedido; } class Aluno { Set<Turma> turmas; } class Turma { Set<Aluno> alunos; } Os atributos representam estados visíveis (métodos get/ set)
  • 12.
    Direção e visibilidade •Um para muitos, unidirecional • Muitos para um, unidirecional • Um para um, unidirecional class Produto { } class Item { Produto produto; } class Pedido { Set<Item> itens; } class Item { } class Pedido { } class Item { Pedido pedido; } equivalentes
  • 13.
    2. Introdução aomapeamento objeto relacional (ORM) • O que é ORM e como funciona? • Dificuldades da ORM: incompatibilidades • Usando uma camada de persistência JDBC • Exemplo: tabelas e objetos + DAO
  • 14.
    O que éORM • Object Relational Mapping • Mapeamento de classes a esquemas de bancos de dados relacionais – Em tempo de configuração • Utilização de uma API de persistência – Em tempo de desenvolvimento • Persistência transparente de objetos como registros de um banco de dados – Em tempo de execução
  • 15.
    Por que usarORM? • Facilitar o desenvolvimento – Simplificar, facilitar manutenção – Separar responsabilidades • Unir os benefícios de dois mundos – Preservar as vantagens do paradigma relacional (robustez, maturidade, facilidade de pesquisa, etc.) para a camada de persistência – Preservar as vantagens do paradigma orientado a objetos (reuso, modularidade, herança, polimorfismo, etc.) para a camada de negócios
  • 16.
    Como funciona? • Tempode configuração – Classes mapeadas a tabelas (esquemas) • Tempo de execução – Instâncias (objetos) automaticamente mapeadas a registros conta correntista saldo 1 Gargantua 1370 2 Pantagruel 3450 3 Gargamel 800 4 Morticia 8200 Classe Conta String codigo String nome double saldo instância:Conta codigo="4" nome="Morticia" saldo=8200 Tabela Conta Banco de Dados Relacional
  • 17.
    Mas... • Nem sempreo modelo relacional é equivalente ao modelo de objetos – O modelo normalizado mais eficiente geralmente tem menos tabelas que os objetos do modelo de objetos mais bem projetado – Há objetos dependentes que são parte de um objeto maior (colunas de uma tabela) – Há objetos que são apenas visões de dados (dados de várias tabelas) • Uma boa ferramenta de ORM permite configurar essas incompatibilidades
  • 18.
    Mapeamento ideal • Nesteexemplo, o descasamento entre o paradigma objeto e relacional não aparece public class Cliente { private String userid; private String nome; private String endereco; private Set contas; // (get/set), etc. ... } public class Conta { private String numero; private String nome; private String tipo; private Cliente usuario; // métodos, get/set... } create table CLIENTE ( USERID VARCHAR(15) NOT NULL PRIMARY KEY, NOME VARCHAR(50) NOT NULL, ENDERECO VARCHAR(100) ) create table CONTA ( NUMERO VARCHAR(10) NOT NULL PRIMARY Key, NOME VARCHAR(50) NOT NULL, TIPO VARCHAR(2) NOT NULL, USUARIO VARCHAR(15) FOREIGN KEY REFERENCES CLIENTE ) Foreign key USUARIO realiza o relacionamento
  • 19.
    Problema: granularidade • Váriosníveis são possíveis no modelo de objetos – Baixa: Cliente com endereco (String) – Mais alta: Endereco é objeto com propriedades: como cep, cidade, rua, país, etc. – Ainda mais alta: Rua é objeto com propriedades numero, etc. • Há dois níveis apenas no modelo relacional – Tabela (CLIENTE) e coluna (USERID, ENDERECO, etc.) • Solução: múltiplos objetos mapeados a uma tabela create table CLIENTE ( USERID VARCHAR(15) NOT NULL PRIMARY KEY, NOME VARCHAR(50) NOT NULL, ENDERECO_RUA VARCHAR(50), ENDERECO_CIDADE VARCHAR(15), ENDERECO_ESTADO VARCHAR(15), ENDERECO_CEP VARCHAR(8), ENDERECO_PAIS VARCHAR(15) ) Cliente Endereco
  • 20.
    Problema: tipos esubtipos • Modelo relacional não suporta herança nem polimorfismo – Queremos escrever queries que referem-se à classe Conta e retornar instâncias concretas dessa classe! • Requer implementação bem mais complexa Associação polimórfica! Cliente Conta ContaCredito ContaDebito *
  • 21.
    Problema: identidade • Nomundo relacional, existe um critério de igualdade: – Chave-primária • No mundo Java há dois – Igualdade de referência (testado com ==) – Equivalência (testado com equals()) • Além disso, mapeamento pode associar vários objetos a uma mesma tabela! • Complicações adicionais e problemas – Chaves naturais – Chaves compostas – Ausência de chave – Chaves que podem ser modificadas problema de design: deve ser corrigido devem ser evitadas em sistemas novos
  • 22.
    Problema: associações • Javarepresenta associações como referências (ou coleções de) referências para objetos – São inerentemente direcionais – Para implementar associações bidirecionais, é preciso criar referências dos dois lados da associação – Referências duplas podem ser associações M-N • No mundo relacional, associações são representadas por chaves estrangeiras – Não são inerentemente direcionais – Pode-se criar associações com projeção e joins – Associações M-N requerem tabela extra
  • 23.
    Problema: navegação emgrafos • Navegação em objetos – Pula-se de um objeto para outro: obj.getA().getB() sem que haja um caminho previamente definido – O equivalente em SQL seria fazer um query para cada pulo (nó do grafo) – Portanto, a forma mais natural de navegar entre objetos em OO é a forma menos eficiente de recuperar dados em SQL • Joins podem minimizar queries – Mas perde-se a flexibilidade da definição dinâmica do caminho de navegação
  • 24.
    Solução • Usar umacamada de persistência para lidar com incompatibilidades entre os paradigmas – Usar uma arquitetura com separação em camadas – Cada camada concentra-se em um interesse predominante – Uma das camadas cuida da persistência • Como implementar – Escrever uma camada de persistência (ex: DAO JDBC) – Usar uma solução como ORM 
 (ex: Hibernate) Camada de Apresentação Camada de Negócios Camada de Persistência
  • 25.
    3. Introdução prática:Hello World • Passo-a-passo na construção de uma aplicação JPA simples – Criação de um projeto – Criação dos objetos e das tabelas – Definição dos mapeamentos – Configuração do ambiente – Implementação da persistência • Siga os passos na sua máquina
  • 26.
    Criação do projeto •Crie um novo projeto no NetBeans – Pacote raiz: jpaloja • Dependências – Inclua todos os JARs do diretório lib/ da distribuição do Hibernate – Inclua o driver JDBC do banco de dados • Crie uma base de dados “aula” no MySQL – Anote também o nome de usuário e senha para acesso ao banco de dados
  • 27.
    Próximos passos • Criartabela no banco – Opcional: nós vamos gerar a tabela a partir do próprio objeto Java anotado • Criar o objeto (POJO) • Criar as anotações de mapeamento entre o POJO e a tabela (três anotações) • Configuração – Criar arquivo de configuração da persistência (persistence.xml) • Utilização – Implementar classe de testes e usar a API
  • 28.
    Regras para construçãode POJOs • Regras para construção de JavaBeans – Construtor sem argumentos com visibilidade mínima de pacote – Expor estado usando métodos get/set • Exemplo: para propriedade do tipo String “texto” use – String getTexto() e – void setTexto(String texto) • Métodos get/set devem seguir as convenções JavaBean mas não precisam ser públicos – O JPA enxerga os métodos private • Métodos get/set a outras entidades determinam associações e permitem navegação no grafo de objetos
  • 29.
    Identidade • O objetoque será mapeado via JPA deve ter um campo que possa ser usado como identificador – Independente do objeto já ter algum atributo unívoco (como userid) • Deve ser um campo inteiro numérico (int, Integer, long, Long) – Será usado pelo JPA para controlar a persistência
  • 30.
    POJO: classe Produto packagejpaloja.pojos; public class Produto { private Long codigo; private String nome; private double preco; public Produto() { } // construtor vazio (necessário) public Produto(String nome, double preco) { this.nome = nome; this.preco = preco; } public Long getCodigo() { return codigo; } private void setCodigo(Long codigo) { this.codigo = codigo; } // outros métodos get/set (...) } Crie o POJO no pacote jpaloja.pojos O Netbeans guardará na pasta src do projeto O Netbeans gera automaticamente o construtor utilitário (com argumentos) e os métodos get/set
  • 31.
    Tabela • Iremos mapearo Produto à seguinte tabela • Não precisa criar a tabela neste momento pois iremos gerá-la CREATE TABLE produto ( codigo int8 NOT NULL, preco float8, nome varchar(255), CONSTRAINT produto_pkey PRIMARY KEY (codigo) )
  • 32.
    Mapeamento • Acrescente asseguintes anotações de mapeamento no arquivo Produto.java package jpaloja.pojos; import javax.persistence.*; @Entity public class Produto { @Id @GeneratedValue (strategy=GenerationType.AUTO) private Long codigo; ... }
  • 33.
    Mapeamento: tabelas eclasses • O mapeamento da classe à tabela é realizada através da anotação @Entity – Se o nome da tabela não for informado, ela terá o mesmo nome que a classe package jpaloja.pojos; import javax.persistence.*; @Entity @Table(name = “PRODUTO”) public class Produto { ... }
  • 34.
    Mapeamento: identificador • Oidentificador é mapeado através da anotação @Id à chave primária da tabela • A anotação @GeneratedValue informa como a chave será incrementada pelo provedor de persistência package jpaloja.pojos; import javax.persistence.*; @Entity public class Produto { @Id @GeneratedValue (strategy=GenerationType.AUTO) private Long codigo; }
  • 35.
    Mapeamento: propriedades • Aspropriedades escalares são mapeadas através da anotação @Column – Se ela for omitida, todos os métodos automaticamente serão considerados parte da interface de mapeamento @Entity @Table(name = “PRODUTO”) public class Produto { @Column(name = “CODIGO”) private Long codigo; @Column(name = “NOME”) private String nome; @Column(name=”PRECO”) private double preco; }
  • 36.
    Configuração da persistência <?xmlversion="1.0" encoding="UTF-8"?> <persistence version="2.0" ... > <persistence-unit name="LojaVirtual"> <provider>org.hibernate.ejb.HibernatePersistence</provider> <!-- <jta-data-source>java:/LojaVirtualDS</jta-data-source> --> <class>lojavirtual.Produto</class> <properties> <property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect"/> <property name="hibernate.connection.driver_class" value="com.mysql.jdbc.Driver"/> <property name="hibernate.connection.username" value="root"/> <property name="hibernate.connection.password" value=""/> <property name="hibernate.connection.url" value="jdbc:mysql://localhost:3306/test"/> <property name="hibernate.transaction.manager_lookup_class" 
 value="org.hibernate.transaction.JBossTransactionManagerLookup"/> <property name="hibernate.show_sql" value="true"/> <!-- <property name="hibernate.hbm2ddl.auto" value="create"/> --> </properties> </persistence-unit> </persistence> Descomente na primeira execução para gerar as tabelas, depois comente de novo. Guarde em src/META-INF com o nome persistence.xml
  • 37.
    Utilização da persistência •Para usar o mecanismo de persistência do JPA, é preciso inicializar uma sessão do EntityManager – O EntityManager oferece uma API de operações de persistência (gravação, leitura, transações) – Cada sessão ocupa um thread e é obtida a partir de um EntityManagerFactory ou via injeção de dependências (em EJB 3) • No nosso exemplo usaremos EJB 3 – Será preciso criar um EJB (Session Bean) para gerenciar a persistência, e disponibilizá-lo no JBoss
  • 38.
    Principais interfaces • Todasdo pacote javax.persistence • Persistence – Oferece um factory method para criar EMF • EntityManagerFactory – Equivalente a SessionFactory do Hibernate • EntityManager – Equivalente a Session do Hibernate • Query – Equivalente a Query do Hibernate • EntityTransaction – Equivalente a Transaction do Hibernate
  • 39.
    Alguns métodos deEntityManager • void persist(E objeto) – Insere objeto na camada de persistência • E find(E.class, Object id) – Localiza objeto pelo ID • E merge(E objeto) – Atualiza objeto (e cascade, se houver) • Query createQuery(String jpql) – Cria um query • Outros: – remove(E objeto), flush(), close(), getTransaction()
  • 40.
    Inserir package loja; import jpaloja.pojos.Produto; importjavax.persistence.*; public class Inserir { public static void main(String[] args) { EntityManagerFactory emf = Persistence.createEntityManagerFactory("LojaVirtual"); EntityManager em = emf.createEntityManager(); EntityTransaction tx = em.getTransaction(); tx.begin(); Produto p1 = new Produto("Giroscopio", 123.89); Produto p2 = new Produto("Tesoura", 23.14); em.persist(p1); em.persist(p2); tx.commit(); em.close(); } }
  • 41.
    Listar package loja; public classListar { public static void main(String[] args) { EntityManagerFactory emf = Persistence.createEntityManagerFactory("LojaVirtual"); EntityManager em = emf.createEntityManager(); EntityTransaction tx = em.getTransaction(); tx.begin(); Query q = em.createQuery("select p from Produto p”); List produtos = q.getResultList(); System.out.println( produtos.size() + “ produtos encontrados!”); for (Object o: produtos.getResultList()) { Produto p = (Produto) o; System.out.println( p.getNome() + “ $” + p.getPreco() ); } tx.commit(); em.close(); } }
  • 42.
    SessionContext do EJB •Para obter, use injeção de recursos @Resource
 SessionContext ctx; • A partir do contexto, pode-se localizar objetos e recursos via JNDI DataSource ds = ctx.lookup("java:/DefaultDS"); EntityManagerFactory emf = ctx.lookup("emf/loja"); Queue fila = ctx.lookup("jms/Queue"); • É melhor obter um EntityManager usando injeção de recursos com @PersistenceContext @PersistenceContext private EntityManager em;
  • 43.
    EJB usando persistência @Stateless publicclass ProdutoFacadeBean implements ProdutoFacadeBeanRemote { @PersistenceContext(unitName="LojaVirtual") private EntityManager em; public List<Produto> retrieveAll() { Query query = em.createQuery("select p from Produto p"); List<Produto> produtos = query.getResultList(); return produtos; } public Produto insert(Produto p) { em.persist(p); return em.merge(p); } ...
  • 44.
    Execução • Isto éum cliente EJB remoto – Sua execução requer a configuração de um cliente Java EE (contendo JARs / client do JBoss + jndi.properties informando a localização do servidor) public class ProdutoTest { public static void main(String[] args) throws NamingException { ProdutoFacadeBeanRemote facade; Context jndi = new InitialContext(); Object obj = jndi.lookup("ProdutoFacadeBean/remote"); facade = (ProdutoFacadeBeanRemote) obj; Produto p1 = new Produto(); p1.setNome("Produto 1"); p1.setPreco(30.00); Produto p2 = new Produto(); p2.setNome("Produto 2"); p2.setPreco(50.00); facade.insert(p1); facade.insert(p2); ...
  • 45.
    JP-QL • JP QueryLanguage é um dialeto orientado a objetos do SQL – Não é uma linguagem de manipulação de dados (como SQL) – Não serve para inserir, remover, atualizar (tem como fazer, mas não se recomenda) – É usada apenas para recuperação de objetos • Exemplo Query q = 
 session.createQuery("select u from User u where u.firstname = :fname"); q.setString("fname", "Max"); List result = q.getResultList();
  • 46.
    4. Mapeamento deentidades • A classe deve ser descrita como entidade – anotada com @Entity (ou declarada como <entity> no deployment descriptor orm.xml) – ter um campo @Id (a menos que participe como subclasse de uma hierarquia mapeada em JPA) • Deve ter construtor sem argumentos • Não pode – ser interface ou um enum ou classe final – ter variáveis de instância ou métodos finais • Deve implementar java.io.Serializable se precisar ser passada por valor – Ex: se objeto for usado por um cliente remoto, como em EJBs que têm interface @Remote
  • 47.
    Entidades • Suportam herança,associações polimórficas, queries polimórficos – Podem estender classes comuns e vice-versa – Somente entidades podem ser usadas em queries JPA • Seu estado persistente é representado pelas suas variáveis de instância – acessado via propriedades (métodos get/set) ou através de suas variáveis de instância – variáveis de instância não declaradas transient e que não tenham a anotação @Transient são consideradas persistentes.
  • 48.
    Entidades • Assinaturas válidaspara propriedades: – Propriedades escalares (value-types) ou lado unitário de associações com entidades (@Column):
 T getProperty() e void setProperty(T t) – Coleções de escalares (value-types) ou lado múltiplo de associações com entidades (@JoinColumn)
 Set<T> getProperty() e void setProperty(Set<T>) 
 (ou Collection, List ou Map) • Tipos permitidos: – Value-types: primitivos, String, BigInteger, BigDecimal, Date, Calendar, Time, Timestamp, byte[], Byte[], char, Character[], enums e coleções desses valores – Tipos serializáveis e coleções de tipos serializáveis – Entidades e coleções de entidades
  • 49.
    Exemplo de mapeamento @Entity publicclass Cliente implements Serializable { @Id private Long id; private String nome; private Endereco endereco; @OneToMany private Set<Pedido> pedidos = new HashSet(); @ManyToMany private Set<Pagamento> formasPagamento = new HashSet(); public Cliente() {} public Long getId() { return id; } public void setId(Long id) { this.id = id; } ... public Collection<Order> getPedidos() { return pedidos; } public void setPedidos(Collection<Pedido> pedidos) { this.pedidos = pedidos; } public Set<Pagamento> getFormasPagamento() { return formasPagamento; } ... } Usando o mínimo de anotações! Anotações ausentes (ex: @Column, @Table, etc.) resultam em comportamento default (ex: tabela com mesmo nome que classe) As anotações também possuem muitas propriedades que podem ser configuradas; se omitidas, são usadas as propriedades default
  • 50.
    Ciclo de vidade uma entidade: 
 breve resumo • A operação new cria uma instância no estado transiente – Entidade transiente = new Entidade() • Para tornar a instância persistente é preciso utilizar a API do EntityManager – entityManager.persist(transiente); – Entidade persistente = entityManager.merge(transiente); • Toda entidade tem uma chave primária. – Indicada pela anotação @Id (pode ser na superclasse) e geralmente definida pelo serviço de persistência – Aplicação nunca deve mudar valor de chave primária. • Fora do escopo do EntityManager, objeto que já foi persistente é considerado desconectado (detached) – Pode ser re-ligado com um merge:
 Entidade persistente = entityManager.merge(detached);
  • 51.
    5. Mapeamento deassociações • Associações no JPA funcionam da mesma maneira que associações de objetos em Java – Associações de objetos em JPA são naturalmente unidirecionais e não são gerenciadas pelo container (como em EJB 2.1) • Associações são sempre relacionamentos entre entidades (diretamente ou via coleções) • Três tipos – @OneToOne – @ManyToOne – @ManyToMany • Duas possibilidades para cada tipo – Unidirecional – Bidirecional
  • 52.
    Associações • @ManyToOne éa associação mais comum – O modelo relacional é naturalmente um-para-muitos – Uma referência simples de objeto é um-para-muitos – Em associações bidirecionais, do outro lado deve haver @OneToMany • @OneToOne requer constraints (que são gerados) nas tabelas para garantir consistência da associação • @ManyToMany mapeia três tabelas a dois objetos • Em associações bidirecionais, há anotações de ambos os lados – Atributo mappedBy é usado em associações bidirecionais para informar o nome do atributo da outra classe que faz a associação – @OneToOne CPF cpf; 
 à @OneToOne(mappedBy="cpf") Cliente cliente; – @ManyToMany(mappedBy="alunos") Set<Turma> turmas; 
 à @ManyToMany(mappedBy="turmas") Set<Aluno> alunos; – @ManyToOne(mappedBy="item") Set<Produto> produtos; 
 à @OneToMany Item item;
  • 53.
    @ManyToOne • Pode-se mapeartudo com @ManyToOne • Associações @OneToOne são raras – Muitas vezes representam composições que devem ser preferivelmente implementadas usando @Embedded / @Embeddable (veremos na parte 3, adiante) • Associações @ManyToMany podem ser implementadas com três objetos e duas associações @ManyToOne – As vezes isto é mais simples e adequado, quando se precisa de um objeto mapeando a associação (join-table) • Várias anotações e atributos permitem configurar ajustes finos dos mapeamentos • Escolha a solução mais simples e adequada ao seu projeto
  • 54.
    ManyToOne unidirecional @Entity public class Produto { @Id @GeneratedValue int codigo; String nome; double preco; public int getCodigo() { return codigo; } public void setCodigo(int codigo) { this.codigo = codigo; } public String getNome() { return nome; } public void setNome(String nome) { this.nome = nome; } ... @Entity public classItem { @ManyToOne private Produto produto; public Produto getProduto() { return produto; } public void setProduto(Produto produto) { this.produto = produto; } public double subtotal() { return this.produto.getPreco() * this.quantidade; } ... Classe Produto não sabe da existência da associação* Método de negócio que utiliza-se da associação para realizar uma operação * Esses dados são insuficientes para a geração automática do esquema (as tabelas devem existir antes)
  • 55.
    ManyToOne bidirecional @Entity public class Pedido { @OneToMany(mappedBy="pedido") private Set<Item> itens = new HashSet<Item>(); public Set<Item> getItens() { return itens; } public void setItens(Set<Item> itens) { this.itens = itens; } public void addItem(Item item) { itens.add(item); item.setPedido(this); } public double subtotal() { double subtotal = 0; for (Item item : itens) { subtotal += item.subtotal(); } return subtotal; } ... @Entity public class Item { @ManyToOne private Pedido pedido; public Pedido getPedido() { return pedido; } public void setPedido(Pedido pedido) { this.pedido = pedido; } public double subtotal() { ... } ... Utilitário parafacilitar a adiçção de itens na associação (atualiza os dois lados da associação) Método de negócio que utiliza-se da associação para realizar uma operação
  • 56.
    @ManyToMany • Default: @ManyToManynos Set de cada lado da associação, informando o campo de mapeamento (mappedBy) – Em associações bidirecionais, é preciso atualizar os dois lados – Usando-se Set e mappedBy, garante-se a não duplicação de dados quando objeto é adicionado duas vezes na coleção • Muitos ajustes possíveis – Uso de List ou Collection (com ou sem @CollectionID) ou Map (com @MapKey) – Configuração de @JoinTable, @JoinColumn, @SecondaryTable • Essas configurações avançadas não serão abordadas neste curso
  • 57.
  • 58.
    @OneToOne • Muitas vezesé desnecessário -relacionamento pode ser representado de outras formas – Pode ser @ManyToOne unidirecional – Pode ser implementado com o componente na mesma tabela (@Embedded) • Duas formas de mapeamento @OneToOne – Associação de chave estrangeira (default) – Associação de chave primária (não pode definir um @JoinColumn, mas é anotado com @PrimaryKeyJoinColumn • Neste curso utilizaremos apenas o mapeamento default
  • 59.
  • 60.
    Cascades: persistência transitiva •Para acrescentar um item em um pedido, é preciso atualizar dois objetos Pedido p = new Pedido(); Item i = new Item(); p.addItem(i); // atualiza dois objetos • Para persistir essa alteração, também é preciso sincronizar os dois objetos em.persist(p); em.persist(i); • O ideal é fazer isto automaticamente: cascade @OneToMany(cascade={CascadeType.PERSIST}, 
 mappedBy="item" )
 private Set<Item> itens = new HashSet<Item>(); – Quando um Pedido for persistido no banco, quaisquer itens que estiverem na sua hierarquia de objetos também serão persistidos
  • 61.
    CascadeType • O atributocascade recebe um array {} de opções • Há várias opções para CascadeType. Algumas das mais importantes são – PERSIST – MERGE – REMOVE • Normalmente, usa-se PERSIST com MERGE (inserts e updates feitos automaticamente) @OneToMany(cascade={CascadeType.PERSIST, CascadeType.MERGE}) • Pode-se usar CascadeType.ALL para que todas as operações sejam transitivas
  • 62.
    Recuperação de dados:lazy • Se você usar um cliente externo que não mantém aberta a sessão do EntityManager, poderá ter exceções de inicialização lazy (inicialização preguiçosa) quando for acessar objetos dentro de coleções – O query, por default, só retorna a coleção com os ponteiros para os objetos, e eles só podem ser recuperados do banco se houver uma sessão aberta – Como lidar com isto será tratado mais adiante • Uma forma rápida de resolver o problema (por enquanto) é declarar nas associações o atributo fetch=FetchType da forma @OneToMany(mappedBy="pedido", fetch=FetchType.EAGER) private Set<Item> itens = new HashSet<Item>();
  • 63.
    Outras anotações deassociações • @JoinColumn(name="coluna", ...) – Propriedades que não são associações informam a coluna da tabela a qual estão mapeadas com @Column – Associações informam a coluna da associação (foreign key) usando @JoinColumn – Se não informada, o sistema assume que a coluna tem o mesmo nome que o atributo • Consulte a especificação para maiores detalhes sobre as outras anotações e seus atributos
  • 64.
    6. Mapeamento decomposição • Em ORM, objetos que formam uma composição compartilham a mesma tabela – Em JPA, classes que são componentes são mapeadas como @Embeddable (e não como @Entity) e suas propriedades anotadas como @Embedded na entidade que as contém Cliente nome email cartao Endereco Rua CEP Cidade enderecoEntrega enderecoCobranca nome email cartao ent_rua ent_cep ent_cidade cob_rua cob_cep cob_cidade :Ciente enderecoEntrega:Endereco enderecoCobranca:Endereco <<Entidade>> <<Componente>> @Entity @Embeddable @Embedded
  • 65.
    Composições (@Embedded) • Oobjeto embutido (componente) na entidade é a parte dependente da relação de composição – Uma composição ocorre quando uma entidade, que tem identidade na tabela, está composta por objetos que não têm identidade na tabela (seus dados são parte da tabela) – A remoção do registro no banco remove a entidade e seus objetos componentes (não confunda com cascade-delete) • O objeto embutido é propriedade da entidade – Só existem como objetos, mas não como tabelas • Muitas associações 1-1 podem ser implementados como objetos embutidos – Ex: a associação Cliente-CPF mostrada anteriormente
  • 66.
    Exemplo com @Embedded @Entity @Table(name="CLIENTE") publicclass Cliente { @Id @GeneratedValue(strategy=GenerationType.AUTO) private Long codigo; private String nome; ... @Embedded private Endereco enderecoCobranca; @Embedded @AttributeOverrides({ @AttributeOverride(name="rua", column=@Column(name="ENT_RUA")), @AttributeOverride(name="cep", column=@Column(name="ENT_CEP")), @AttributeOverride(name="cidade", column=@Column(name="ENT_CIDADE")), }) private Endereco enderecoEntrega; ... @Embeddable public class Endereco { @Column(name="COB_RUA") private String rua; @Column(name="COB_CEP") private String cep; @Column(name="COB_CIDADE") private String cidade; ... } reusa mesma classe Endereco, mas redefine mapeamentos
  • 67.
    • Herança éo descasamento mais visível entre os mundos relacional e orientado a objetos – Mundo OO possui relacionamento “é um” e “tem um” – Mundo relacional apenas possui relacionamento “tem um” • Há várias estratégias [Ambler 2002]* – Uma tabela por classe concreta: modelo relacional ignora herança e polimorfismo (polimorfismo implícito) – Uma tabela por hierarquia de classes: permite polimorfismo com tabelas não normalizadas mais uma coluna extra contendo informação de tipo – Uma tabela por subclasse: representa relacionamentos “é um” através de relacionamentos “tem um” (chave estrangeira) 7. Mapeamento de herança
  • 68.
    a. Tabela porclasse concreta • Mapeia classes concretas a tabelas @Entity @Inheritance(strategy=InheritanceType.TABLE_PER_CLASS) public abstract class Pagamento { @Id @GeneratedValue private long id; } Pagamento id valor Credito numero validade ID VALOR NUMERO VALIDADE 5 <<Entidade>> @Entity Debito banco conta <<Entidade>> @Entity ID VALOR BANCO CONTA 5 CREDITO DEBITO @Entity public class Debito extends Pagamento {...} @Id declarado apenas na superclasse
  • 69.
    Tabela por classeconcreta • Vantagens – Mapeamento direto entre classe e tabela normalizada • Desvantagens – Queries mais complexos e ineficientes • O query polimórfico select p from Pagamento p where p.valor > 1000 gera um SQL (conceitual) com subquery que concatena queries nas tabelas com union: – select ID, VALOR, NUMERO, VALIDADE, BANCO, CONTA from (
 select ID, VALOR, NUMERO, VALIDADE, 
 null as BANCO, null as CONTA from CREDITO 
 union select ID, VALOR, null as NUMERO, null as VALIDADE, 
 BANCO, CONTA from DEBITO 
 ) where VALOR > 1000
  • 70.
    b. Tabela porhierarquia de classes @Entity @Inheritance(strategy=InheritanceType.SINGLE_TABLE) @DiscriminatorColumn(name="TIPO") public abstract class Pagamento { @Id @GeneratedValue private long id; } Pagamento id valor Credito numero validade ID TIPO VALOR NUMERO VALIDADE BANCO CONTA 5 crd 100.0 23459403 12/15 null null 6 deb 100.0 null null 1234-5 993423-3 <<Entidade>> @Entity Debito banco conta <<Entidade>> @Entity PAGAMENTO @Entity @DiscriminatorValue("deb") public class Debito extends Pagamento {...} Coluna (DiscriminatorColumn) presente na tabela mas sem mapeamento na classe
  • 71.
    b. Tabela porhierarquia de classes • Mapeia-se a hierarquia inteira a uma única tabela – Tabela inclui coluna (não mapeada) para identificar a classe – Há colunas para todas as propriedades de todas as classes • Vantagens – Forma mais eficiente de implementar polimorfismo. – Query polimórfico: select ID, VALOR, BANCO, CONTA, NUMERO, VALIDADE from PAGAMENTO where VALOR > 1000 – Query em classe concreta: select ID, VALOR, BANCO, CONTA, NUMERO, VALIDADE from PAGAMENTO where TIPO = 'deb' and VALOR > 1000 • Desvantagens – Tabelas não normalizadas – Colunas de propriedades declaradas em subclasses precisam aceitar valores nulos (pode ser ruim para grandes hierarquias)
  • 72.
    c. Tabela porsubclasse • Mapeia classes a tabelas @Entity @Inheritance(strategy=InheritanceType.JOINED) public abstract class Pagamento { @Id @GeneratedValue private long id; } Pagamento id valor Credito id numero validade ID NUMERO VALIDADE 9 <<Entidade>> @Entity Debito id banco conta <<Entidade>> @Entity ID BANCO CONTA 5 CREDITO DEBITO @Entity public class Debito extends Pagamento {...} ID VALOR 5 PAGAMENTO ID é PK e FK
  • 73.
    Uma tabela porsubclasse • Herança como relacionamentos de chave estrangeira – Cada subclasse tem sua própria tabela – Cada tabela possui colunas apenas para campos não-herdados, e chave primária que é chave estrangeira da superclasse – Recuperação de dados através de um join das tabelas • Vantagens – Modelo relacional normalizado – Evolução e restrições de integridade simples – Classes/tabelas criadas sem afetar classes/tabelas existentes • Desvantagens – Performance baixa em hierarquias complexas – Difícil de codificar a mão (ruim para integrar com JDBC legado) • Queries – Outer join para pesquisas polimórficas, inner join para queries em classes concretas
  • 74.
    Qual estratégia usar? •Se não houver necessidade de queries polimórficos ou associações – Tabela por Classe Concreta (TABLE_PER_CLASS) • Se houver necessidade de associações polimórficas, e hierarquia for simples – Tabela por Hierarquia (SINGLE_TABLE) • Se houver necessidade de associações polimórficas mas hierarquia grande (ou não puder usar tabelas não normalizadas) – Tabela por Subclasse (JOINED)
  • 75.
    8. Queries JPQL •Toda pesquisa no banco é feita através de Java Persistence Query Language (JPQL) – Linguagem de recuperação de dados similar a outras linguagens de query de objetos (HQL, EJB-QL, etc.) – Parece com SQL, mas é diferente: opera sobre objetos e não tabelas – é mais simples • Queries são objetos da classe Query – Podem ser criados através métodos de EntityManager – Instruções do query podem ser passadas diretamente na criação do query ou declarados em anotações @NamedQuery – Queries podem ser parametrizados • Após sua execução, os dados podem ser recuperados através de métodos da classe Query.
  • 76.
    API essencial paraQueries JPQL • EntityManager – Query createQuery("query jpql"); – Query createNamedQuery("nome de query"); • Query – List<Tipo> getResultList(); – Object getSingleResult(); – Query setParameter(String var, Object obj);
 Query setParameter(int pos, Object obj); – int executeUpdate();
  • 77.
  • 78.
    Declarações (sintaxe) • SELECT cláusula_selectcláusula_from
 [cláusula_where] [cláusula_group_by] [cláusula_having] [cláusula_order_by] • UPDATE cláusula_update • DELETE cláusula_delete

  • 79.
    Sintaxe elementar SELECT p.nome FROMProduto AS p WHERE p.codigo = '123' Declara variável p como sendo um Produto O que vai ser selecionado Parâmetro SELECT OBJECT (p) 
 FROM Produto p 
 WHERE p.nome = :n AS é opcional Parâmetro do método Objeto (bean) sendo selecionado
  • 80.
    Palavras-chave JPQL • Usadasna cláusula SELECT – DISTINCT, OBJECT, AVG, MAX, MIN, SUM, COUNT • Usadas na cláusula FROM – IN, AS • Usadas na cláusula WHERE – FROM, WHERE, UPDATE, DELETE, JOIN, OUTER, INNER, LEFT, GROUP, BY, HAVING, FETCH, OBJECT, NULL, TRUE, FALSE, NOT, AND, OR, BETWEEN, LIKE, IN, AS, UNKNOWN, EMPTY, MEMBER, OF, IS, ORDER, BY, ASC, DESC, MOD, UPPER, LOWER, TRIM, POSITION, CHARACTER_LENGTH, CHAR_LENGTH, BIT_LENGTH, CURRENT_TIME, CURRENT_DATE, CURRENT_TIMESTAMP, NEW, EXISTS, ALL, ANY, SOME
  • 81.
    Cláusula FROM • Acláusula FROM é quem informa o objeto que está sendo pesquisado, e declara variáveis usados no resto do query – Cada variável tem um identificador e um tipo – O identificador é qualquer palavra não-reservada – O tipo é a classe do objeto marcado como @Entity – A palavra-chave AS conecta o tipo ao identificador, mas é opcional FROM Produto AS p Tipo Identificador
  • 82.
    Cláusula SELECT • Acláusula SELECT informa o que se deseja obter com a pesquisa. Pode retornar – Objetos (interfaces locais ou remotas) – Atributos dos objetos • A palavra SELECT pode ser seguida de DISTINCT para eliminar valores duplicados nos resultados • SELECT utiliza uma variável declarada na cláusula FROM (opcionalmente pode usar OBJECT(p)) • Exemplos SELECT p FROM Produto p SELECT DISTINCT p FROM Produto p SELECT p.codigo FROM Produto p SELECT DISTINCT p.codigo FROM Produto p Retorna objetos Retorna campos
  • 83.
    Cláusula WHERE • Acláusula WHERE é opcional e restringe os resultados da pesquisa com base em uma ou mais expressões condicionais concatenadas • As expressões podem usar – Literais (strings, booleanos ou números) – Identificadores (declarados no FROM) – Operadores – Funções – Parâmetros do método que utiliza a pesquisa (?1, ? 2, :nome, ...) • Literais – Strings são representados entre apóstrofes: 'nome' – Números têm mesmas regras de literais Java long e double – Booleanos são TRUE e FALSE (case-insensitive)
  • 84.
    Operadores • Expressões matemáticas –+, -, *, / • Expressões de comparação – =, >, >=, <, <=, <> • Operadores lógicos – NOT, AND, OR • Outros operadores – BETWEEN, NOT BETWEEN – IN, NOT IN – LIKE, NOT LIKE – NULL, NOT NULL – IS EMPTY, IS NOT EMPTY – MEMBER, NOT MEMBER • Operadores do LIKE – _ representa um único caractere – % representa uma seqüência de zero ou mais caracteres – caractere de escape (necessário para usar _ ou %) literalmente
  • 85.
    Algumas funções • Manipulaçãode strings (usados em WHERE) – CONCAT, SUBSTRING, TRIM, LOWER, UPPER – LENGTH, LOCATE • Funções aritméticas (usados em WHERE) – ABS, SQRT, MOD, SIZE • Data e hora (usados em WHERE) – CURRENT_DATE, CURRENT_TIME, CURRENT_TIMESTAMP • Funções de agregação (usados em SELECT) – COUNT, MAX, MIN, AVG, SUM
  • 86.
    Exemplos • Encontre todosos produtos que são chips e cuja margem de lucro é positiva – SELECT p 
 FROM Produto p 
 WHERE (p.descricao = 'chip' 
 AND (p.preco - p.custo > 0) • Encontre todos os produtos cujo preço é pelo menos 1000 e no máximo 2000 – SELECT p
 FROM Produto p 
 WHERE p.preco BETWEEN 1000 AND 2000 • Encontre todos os produtos cujo fabricante é Sun ou Intel – SELECT p
 FROM Produto p 
 WHERE p.fabricante IN ('Intel', 'Sun')
  • 87.
    Exemplos de JPA-QL(2) • Encontre todos os produtos com IDs que começam com 12 e terminam em 3 – SELECT p
 FROM Produto p 
 WHERE p.id LIKE '12%3' • Encontre todos os produtos que têm descrições null – SELECT p
 FROM Produto p 
 WHERE p.descricao IS NULL • Encontre todos os pedidos que não têm itens (coleção) – SELECT pedido FROM Pedido pedido WHERE pedido.itens IS EMPTY • Encontre todos os itens ligados a pedidos em coleção – SELECT item
 FROM Pedido pedido, Item item 
 WHERE item IS MEMBER pedido.itens
  • 88.
    9. Queries dinâmicos(JPA 2.0) • Novidade do Java EE 6 – API que permite a construção de queries usando objetos – Inspirado em Criteria do Hibernate e JDO – Pode-se descobrir erros nos queries em tempo de compilação • Queries são mais longos e podem ser mais complexos, mas podem ser alterados dinamicamente • Ideal para formulários de pesquisa onde queries são montados de acordo com preferências do usuário
  • 89.
    Queries dinâmicos (JPA 2.0) • Pode-se montar o query JPQL • usando queries dinâmicos, da seguinte forma: CriteriaBuilderqb = em.getCriteriaBuilder(); CriteriaQuery<Produto> cq = qb.createQuery(Produto.class); Root<Produto> raiz = cq.from(Produto.class) Predicate condicao = qb.lt(raiz.get(Produto_.preco), 50.0); cq.where(condicao); TypedQuery<Person> query = em.createQuery(cq); List<Produto> resultado = query.getResultList(); select p from Produto p where p.preco < 50.0
  • 90.
    10. DAO paraJPA em EJB 3 • JPA não precisa de DAO quando usado em EJB 3, que cuida dos contextos transacionais • Mas um DAO ainda é importante – Camada de persistência não precisa ser JPA (pode ser JDBC direto ou usar bancos não relacionais como Redis) – Permite isolar queries (dinâmicos do JPA 2 ou JPQL) • Usando Generics pode-se criar uma interface abstrata reusável
  • 91.
    DAO abstrato public abstract classAbstractFacade<T> { private Class<T> entityClass; protected abstract EntityManager getEntityManager(); public AbstractFacade(Class<T> entityClass) { this.entityClass = entityClass; } public void create(T entity) { getEntityManager().persist(entity); } public void edit(T entity) { getEntityManager().merge(entity); } public void remove(T entity) { getEntityManager().remove(getEntityManager().merge(entity)); } public T find(Object id) { return getEntityManager().find(entityClass, id); } }
  • 92.
    DAO concreto • Precisa apenas estender DAO abstrato para cada entidade que se deseja usar – Métodos herdados disponíveis para uso pelos clientes (ex: EJBs) @Stateless publicclass ProdutoFacade extends AbstractFacade<Produto> { @PersistenceContext(unitName = "LojaVirtual") private EntityManager em; protected EntityManager getEntityManager() { return em; } public ProdutoFacade() { super(Produto.class); } }
  • 93.
    Referências • Material consultado na elaboração deste capítulo – Oracle. Especificação JPA 2.0: https://jcp.org/aboutJava/ communityprocess/final/jsr317/ e Especificação JPA 1.0 –Apache OpenJPA: https://openjpa.apache.org/ – JBoss.org. Hibernate Entity Manager User Guide http:// docs.jboss.org/hibernate/entitymanager – Christian Bauer e Gavin King. Java Persistence with Hibernate. Manning, 2007 e edições anteriores. – Oracle, Eric Jendrock et al. Java EE 6 Tutorial. http:// docs.oracle.com/javaee/6/tutorial/doc/ e edições anteriores – Versões anteriores deste curso