Este documento fornece uma introdução à Java Persistence API (JPA), abordando tópicos como: 1) relacionamentos entre objetos; 2) mapeamento objeto-relacional; 3) introdução prática com um exemplo "Hello World" utilizando JPA.
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;
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
@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
@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
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();
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
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);
}
}