195
J A V A E E 7 JPA java persistence api Helder da Rocha ([email protected]) Atualizado em setembro de 2016

JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

  • Upload
    lyduong

  • View
    270

  • Download
    0

Embed Size (px)

Citation preview

Page 1: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V

A

E

E

7

JPAjava persistence api

Helder da Rocha ([email protected])Atualizado em setembro de 2016

Page 2: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Sobre este tutorialEste é um tutorial sobre tecnologia JPA (de acordo com a especificação Java EE 7) criado para cursos presenciais e práticos de programação por Helder da Rocha.

Este curso aborda os conhecimentos essenciais para usar JPA na prática usando Hibernate ou EclipseLink como provedor (consulte a documentação oficial para detalhes).

Este material poderá ser usado de acordo com os termos da licença Creative Commons BY-SA (Attribution-ShareAlike) descrita em http://creativecommons.org/licenses/by-sa/3.0/br/legalcode.

O código dos exemplos está disponível em repositório público no GitHub e é software livre sob os termos da licença Apache 2.0.

Page 3: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Conteúdo

1. Introdução 2. Configuração do ambiente 3. Persistência 4. Mapeamento de entidades 5. Mapeamento de relacionamentos 6. Mapeamento de herança 7. Queries JPQL 8. Queries Criteria 9. Tuning: transações, cache e locks

Page 4: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7 JPA

java persistence api1

introdução

Page 5: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

O que é JPA?•Java Persistence API: especificação Java EE que define um mapeamento

entre uma estrutura relacional e um modelo de objetos em Java

•Pode ser também usado de forma standalone, em aplicações Java SE, utilizando um provedor de persistência independente

•Java EE 7 adota a especificação JPA 2.1 (JSR 338).

•JPA permite a criação de entidades persistentes - objetos gerenciados que retém seu estado além do tempo em que estão na memória

•Oferece uma camada de persistência (CRUD de objetos) e um mecanismo de mapeamento objeto-relacional (ORM) declarativo.

Page 6: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Object-Relational Mapping (ORM)•Tempo de configuração • Classes mapeadas a tabelas (esquemas)

•Tempo de execução • Instâncias (objetos) automaticamente sincronizadas com 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

Page 7: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Camada de persistência

•JPA oferece uma API para interagir com objetos persistentes mapeados através de ORM

•A API é proporcionada pela interface EntityManager e contém

•Métodos para gravar objetos em meio persistente (persist), remover (remove) e atualizar (update)

•Métodos para construir e processar consultas usando scripts (JPA Query Language) ou objetos (Criteria)

•Métodos para configurar o comportamento do cache de objetos (que cuida da sincronização do estado de objetos e transações)

Page 8: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Configuração de JPA

•Para configurar JPA em uma aplicação é necessário que essa aplicação tenha acesso, através do seu Classpath, aos seguintes componentes:

•Módulo contendo a API do JPA (as classes, interfaces, métodos, anotações do pacote javax.persistence)

•Um provedor de persistência JPA (ex: Hibernate, EclipseLink) que implementa as interfaces da API

•Drivers necessários para configuração do acesso aos datasources usados (e pools de conexão, se houver)

•Um arquivo persistence.xml para configurar a camada de persistência.

Page 9: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Unidade de persistência•O contexto de persistência, usado para sincronizar as instâncias

persistentes com o banco de dados é chamado de Entity Manager

•Controla o ciclo de vida das instâncias

•Pode ser instanciado pela própria aplicação (em aplicações standalone), obtido via JNDI ou injeção de dependências (padrão em Java EE)

•O conjunto de entity managers e as entidades que eles gerenciam configura uma unidade de persistência (Persistence Unit).

•Declarada no arquivo persistence.xml

•Referenciada em classes que usam objetos persistentes (DAOs, fachadas, beans, servlets)

Page 10: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

persistence.xml mínimo•Deve estar no Classpath acessível pelas classes Java usadas na aplicação em

/META-INF/persistence.xml, e possui a seguinte configuração mínima:

•Este exemplo é utilizável em servidor Java EE que tenha sido configurado para oferecer um datasource default (java:comp/DefaultDataSource).

•Normalmente aplicações usam datasources selecionadas de forma explícita.

<?xml version="1.0" encoding="UTF-8"?> <persistence version="2.1" xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">

<persistence-unit name="MyPU" transaction-type="JTA"> </persistence-unit>

</persistence>

Page 11: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

DataSource com JTA•Este persistence.xml típico de uma aplicação JPA simples rodando em

um servidor Java EE 7 declara o nome da unidade de persistência e:

•o modelo de transações utilizada (JTA – gerenciada pelo container), •o nome JNDI de um datasource específico (previamente configurado) •uma única entidade mapeada •uma única propriedade de configuração específica do provedor usado

<persistence version="2.1" …> <persistence-unit name="com.empresa.biblioteca.PU" transaction-type="JTA">

<jta-data-source>jdbc/Biblioteca</jta-data-source> <class>br.empresa.biblioteca.entity.Livro</class> <properties> <property name="eclipselink.deploy-on-startup" value="true" /> </properties>

</persistence-unit> </persistence>

Os detalhes de conexão com o banco de dados precisam ser configurados no servidor de aplicações

Page 12: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

EclipseLink e PostgreSQL•Exemplo de persistence.xml usado para acessar mesmos dados via

camada de persistência configurada localmente (transações gerenciadas pela aplicação), usando provedor EclipseLink e banco PostgreSQL

<persistence version="2.1" … > <persistence-unit name="com.empresa.biblioteca.PU" transaction-type="RESOURCE_LOCAL">

<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider> <class>br.empresa.biblioteca.entity.Livro</class> <properties> <property name="javax.persistence.jdbc.driver" value="org.postgresql.Driver" /> <property name="javax.persistence.jdbc.url" value="jdbc:postgresql://localhost:5432/postgres" /> <property name="javax.persistence.jdbc.user" value="postgres" /> <property name="javax.persistence.jdbc.password" value="admin" /> </properties> </persistence-unit> </persistence>

Page 13: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Hibernate e MySQL•Este persistence.xml configura unidade de persistência com transações locais

e provedor Hibernate acessando localmente um banco de dados MySQL

<persistence … > <persistence-unit name="LojaVirtual" transaction-type="RESOURCE_LOCAL">

<provider>org.hibernate.ejb.HibernatePersistence</provider> <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"/> </properties> </persistence-unit> </persistence>

Page 14: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Entidades e mapeamento

•A arquitetura do JPA baseia-se no mapeamento de tabelas a classes, colunas a atributos

•O objetivo do mapeamento é construir uma hierarquia de entidades

•Entidade (Entity) é um objeto persistente. Em JPA é um JavaBean (POJO) mapeado a uma tabela

•Uma entidade JPA pode ser mapeada a uma tabela de duas formas:

•Através de elementos XML no arquivo orm.xml

•Através de anotações em classes, métodos, atributos, construtores

Page 15: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Mapeamento em orm.xml•Os únicos tags obrigatórios são <entity> e <id>, e os atributos name.

Pode-se ter mais detalhamento (ex: tipos, constraints) ou menos (ex: omitir tags com nomes de tabela e colunas, se forem iguais).

<entity-mappings xmlns="http://xmlns.jcp.org/xml/ns/persistence/orm" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence/orm http://xmlns.jcp.org/xml/ns/persistence/orm/orm_2_1.xsd" version="2.1"> <entity name="Livro" class="br.com.argonavis.Livro" access="FIELD"> <table name="LIVRO"/> <attributes> <id name="id"> <column name="ID"/> <generated-value strategy="TABLE" generator="LIVRO_SEQ"/> </id> <basic name="titulo"> <column name="TITULO"/> </basic> <basic name="paginas"> <column name="PAGINAS"/> </basic> </attributes> </entity> </entity-mappings> Se existir, deve estar localizado em META-INF/orm.xml

Page 16: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Mapeamento com anotações•Para declarar uma entidade com anotações JPA é necessário no mínimo

anotar a classe com @Entity e anotar pelo menos um atributo (ou método) com @Id, indicando sua chave primária

•Atributos expostos via getters/setters são mapeados por default a colunas de mesmo nome@Entity public class Livro implements Serializable { @Id private Long id; private String titulo; private int paginas;

public Long getId() { return id;} public void setId(Long id) { this.id = id;} public String getTitulo() { return this.titulo;} public void setTitulo(String titulo) { this.titulo = titulo;} public int getPaginas() { return this.paginas;} public void setPaginas(int paginas) { this.paginas = paginas;} }

É preciso também determinar como o Id será atribuído (se gerado pelo banco ou fornecido)

Page 17: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Mapeamento com anotações•Pode-se mudar os defaults e realizar configurações adicionais é

usando anotações como @Table, @Column, @CollectionTable, @JoinTable, @JoinColumn, etc.

@Entity @Table(name="BOOK") public class Livro implements Serializable {

@Id private Long id;

@Column(name="TITLE") private String titulo;

@Column(name="PAGES") private int paginas; … }

Page 18: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Exercícios: configuração

•Configuração do ambiente para realizar os exercícios

•Pode ser necessário adaptar os exercícios ao ambiente usado (banco de dados, provedor de persistência, IDE, ambiente Java EE ou standalone, duração do treinamento)

•Alguns exercícios usam arquivos disponíveis no repositório GitHub

•Scripts SQL 99 e aplicações JDBC em Java podem ser usados para criar tabelas usadas em exercícios (é necessário configurá-los)

•As hierarquias de classes e diagramas de entidades a seguir poderão ser usados nos exercícios (que irão fazer referência a eles)

Page 19: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Exercícios: Hierarquia e SQL 1

CREATE TABLE Livro( id INTEGER PRIMARY KEY, isbn VARCHAR(13) UNIQUE, titulo VARCHAR(256), idioma CHAR(2) )

Livroid: int titulo: String isbn: String idioma: String

Page 20: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Exercícios: Hierarquia e SQL 2

Movie

id: int title: String imdb: String director: Director year: int duration: int

Director

id: int name: String

CREATE TABLE Diretor ( id INTEGER PRIMARY KEY, nome VARCHAR(256), )

CREATE TABLE Filme ( id INTEGER PRIMARY KEY, imdb CHAR(9) NOT NULL, titulo VARCHAR(256), diretor INTEGER, ano INTEGER, duracao INTEGER, constraint fk_diretor foreign key (diretor) references Diretor(id) )

*

Page 21: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Exercícios: Hierarquia 3

1

1..*

1

1*

PK FK

Cliente

nome email pedidos cartao

Usuario

id senha userid

Produto

id nome preco

Pedido

id cliente status

Item

id pedido produto quantidade

Operador

codigo versao

Page 22: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Exercícios: SQL 1create table produtos ( produto_id integer primary key, nome_prod varchar(64), preco numeric(10,2), );

create table usuarios ( usuario_id varchar(8) primary key, senha varchar(16), userid varchar(16) );

create table clientes ( cliente_id varchar(8) primary key, nome varchar(512), email varchar(256), usuario_fk integer, cartao varchar(16), constraint fk_usuario foreign key (usuario_fk) references usuarios(usuario_id) );

Page 23: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Exercícios: SQL 2create table operadores ( operador_id varchar(8) primary key, codigo varchar(8), versao integer, usuario_fk integer, constraint fk_usuario foreign key (usuario_fk) references usuarios(usuario_id) ); create table pedidos ( pedido_id integer primary key, cliente_fk integer, status varchar(16), constraint fk_cliente foreign key (cliente_fk) references clientes(cliente_id) ); create table itens ( item_id integer primary key, pedido_fk integer, produto_fk integer, qte integer, constraint fk_pedido foreign key (pedido_fk) references pedidos(pedido_id), constraint fk_produto foreign key (produto_fk) references produtos(produto_id) );

Page 24: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Exercícios: Hierarquia 4Corrida

Etapa

Participante Ingressoingresso

participante

Localidade

participantes

etapas

origem

destino

valor status

nome

nome

nome

nome

*

*

1

1

1

*

etapas

1

1

Page 25: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Exercícios:Hierarquia 5

Livroid: int titulo: String isbn: String idioma: String

Autorid: int nome: String

Editoraid: int nome: String

Assunto

id: AssuntoPK descricao: String

Exemplar

id: int disponivel: boolean

ExemplarEletronico

id: int tamanho: long

ExemplarImpresso

id: int paginas: int

Usuarioid: int nome: String

emprestimos

usuario

livro

assunto

editora

autores

obras

titulos

contexto

assuntos 10

0..1

*1

*

*

1

*

1

*1

*

Page 26: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7 JPA

java persistence api2

configuração do ambiente

Page 27: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Configuração standalone•Usada em projetos Java EE para rodar testes de integração com o banco ou em

aplicações JPA standalone

•É preciso incluir explicitamente no Classpath os JARs da API, do provedor JPA e driver do banco de dados (e pool de conexões se houver)

<dependencies> <dependency> <groupId>org.eclipse.persistence</groupId> <artifactId>javax.persistence</artifactId> <version>2.1.0</version> </dependency> <dependency> <groupId>org.eclipse.persistence</groupId> <artifactId>eclipselink</artifactId> <version>2.5.0</version> </dependency> <dependency> <groupId>org.postgresql</groupId> <artifactId>postgresql</artifactId> <version>9.4.1208</version> <scope>runtime</scope> </dependency> </dependencies>

Configuração das dependências Maven para

para acesso JPA usando EclipseLink 2.5 e banco de

dados PostgreSQL

Page 28: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Configuração standalone•Como as transações serão controladas pela aplicação e serão locais, a unidade

de persistência declara o tipo de transações como RESOURCE_LOCAL:

<persistence version="2.1"…> <persistence-unit name="tutorial-jpa" transaction-type="RESOURCE_LOCAL">

<provider>org.eclipse.persistence.jpa.PersistenceProvider</provider> <class>br.com.argonavis.javaee7.jpa.intro.Livro</class> <properties> … <property name="eclipselink.ddl-generation" value="drop-and-create-tables" /> </properties>

</persistence-unit> </persistence>

Entidade a ser configurada

Configuração do EclipseLink para gerar tabelas automaticamente

(o Hibernate suporta uma equivalente)

Page 29: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Criação do EntityManager (standalone)

•A fábrica que cria o EntityManager pode ser obtida via consulta JNDI global a um servidor (se houver container cliente configurado), ou criada localmente com um objeto Persistence. import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; import javax.persistence.Persistence;

public class LivroTest { @Test public void testPersist() throws Exception { EntityManagerFactory factory = Persistence.createEntityManagerFactory("tutorial-jpa"); EntityManager em = factory.createEntityManager();

... em.close(); } }

Criação local do EntityManager

Configuração para usar a unidade de persistência

declarada no persistence.xml

Page 30: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Criação da entidade

•A entidade a ser sincronizada com a tabela é instanciada e configurada normalmente em Java puro

public class LivroTest {

@Test public void testPersist() throws Exception { ... Livro livro = new Livro(); livro.setTitulo("Meu Livro"); livro.setPaginas(100); ... } }

Page 31: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Uso da persistência (standalone)•Padrão básico: obter o contexto de persistência (createEntityManager)

seguido do contexto transacional (begin), realizar as operações envolvendo persistência, e fechar o contexto transacional (commit se sucesso ou rollback se falha, fechando o contexto de persistência (close) no final da operação.

public class LivroTest { @Test public void testPersist() throws Exception { ... try { em.getTransaction().begin(); em.persist(livro); // cria um registro novo no commit() em.getTransaction().commit(); } catch (Exception e) { em.getTransaction().rollback(); } finally { em.close(); } } } // detalhes do teste (asserts) omitidos

É preciso obter o contexto transacional

do EntityManager:

persist() precisa ser chamada dentro de um

contexto transacional

Page 32: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Configuração em Java EE

•Em Java EE o suporte a JPA é nativo, e o acesso ao banco de dados deve ocorrer através de um datasource previamente configurado no servidor, acessível dentro de um contexto JTA

<dependencies> <dependency> <groupId>javax</groupId> <artifactId>javaee-api</artifactId> <version>7.0</version> <scope>provided</scope> </dependency> ... </dependencies>

Dependências em um projeto Maven não são incluídas no

componente (JAR): o driver do banco, pool e provedor JPA

fazem parte do servidor

Page 33: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Configuração em Java EE

•O arquivo persistence.xml declara estratégia transacional JTA (gerenciada pelo container) e em vez de dados para acesso ao banco, informa o caminho JNDI para o datasource correspondente

<persistence version="2.1" …> <persistence-unit name="tutorial-jpa" transaction-type="JTA">

<jta-data-source>jdbc/TutorialJPA</jta-data-source> <class>br.com.argonavis.javaee7.jpa.intro.ejb.Livro</class> </persistence-unit>

</persistence>

Page 34: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Acesso via WebServlet•Em Java EE o EntityManager poderá ser obtido via JNDI injeção de dependências

com de @PersistenceContext (ou via CDI, se previamente configurado)

@WebServlet("/Livro") public class LivroTestServlet extends HttpServlet { @PersistenceContext(unitName="tutorial-jpa") EntityManager em; @Resource UserTransaction ut;

protected void doGet(HttpServletRequest rq, HttpServletResponse rs) throws ServletException, IOException { Writer out = rs.getWriter(); try { ut.begin(); List<Livro> livros = em.createQuery("select livro from Livro livro").getResultList(); for(Livro livro : livros) out.write("<p>"+livro.getTitulo()+ "</p>"); ut.commit(); } catch (…) {…} // rollback e finalização }

UserTransaction é necessário para delimitar o contexto transacional

Page 35: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7 @Stateless

public class LivroDAOSessionBean { @PersistenceContext EntityManager em;

public Livro findByID(Long id) { Query query = em.createNamedQuery("selectById"); query.setParameter("id", id); return (Livro)query.getSingleResult(); } public List<Livro> findAll() { return (List<Livro>)em.createNamedQuery("selectAll") .getResultList(); } public void delete(Livro livro) { em.remove(livro); } public void update(Livro livro) { em.merge(livro); } public Livro insert(Livro livro) { return em.merge(livro); } }

Acesso via EJB

Se houver apenas uma unidade de persistência, o nome dela não

precisa ser informado

Os métodos de um Session Bean são transacionais por default. Haverá

rollback se houver exceção

Page 36: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Named queries•Um @NamedQuery contém JPQL associado a um nome que

pode ser usado pelos clientes para obter referência a um query:

•Exemplo:

@Entity @NamedQueries({ @NamedQuery(name="selectAll", query="SELECT livro FROM Livro livro"), @NamedQuery(name="selectById", query="SELECT livro FROM Livro livro WHERE livro.id=:id") }) public class Livro { ... }

TypedQuery<Livro> query = em.createNamedQuery("selectById", Livro.class);

Page 37: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Acesso via CDI•Métodos não são transacionais por default. O contexto transacional pode

ser obtido de duas formas: •UserTransaction (como no WebServlet) •Anotação @Transactional (comportamento igual ao EJB)

@Named public class LivroDAOManagedBean { @Inject EntityManager em; public Livro findByID(Long id) { TypedQuery<Livro> query = em.createNamedQuery("selectById", Livro.class); query.setParameter("id", id); return query.getSingleResult(); } public List<Livro> findAll() { return em.createNamedQuery("selectAll", Livro.class) .getResultList(); } @Transactional public void delete(Livro livro) { em.remove(livro); } @Transactional public void update(Livro livro) { em.merge(livro); } @Transactional public Livro insert(Livro livro) { return em.merge(livro); } }

Page 38: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Passo-a-passo JPA: configuração•Crie um projeto (Maven, Eclipse, NetBeans, etc)

•Configure dependências necessárias para compilar JPA (e executar se standalone)

•Configure um banco de dados no seu projeto (se standalone) ou no servidor de aplicações (se Java EE) e use as propriedades para configurar o persistence.xml

•Inclua dados de configuração em META-INF/persistence.xml definindo um nome para a unidade de persistência, e tipo RESOURCE_LOCAL, se standalone, e JTA, se Java EE

<persistence version="2.1" ... > <persistence-unit name="biblioteca-PU" transaction-type="JTA"> <jta-data-source>jdbc/sample</jta-data-source> <class>biblioteca.Livro</class> <properties> <property name="javax.persistence.schema-generation.database.action" value="drop-and-create"/> </properties> </persistence-unit> </persistence> Use para gerar as tabelas

automaticamente

Entidade mapeada

Page 39: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Passo-a-passo JPA: mapeamento•Crie um POJO (classe Java com atributos privativos acessíveis via getters e setters) •Declare @Entity, @Id e uma estratégia de geração do ID (depende do banco de dados) • Inclua uma referência à entidade no persistence.xml (veja slide anterior)

@Entity public class Livro { @Id @GeneratedValue(strategy = GenerationType.AUTO) private int id; private String titulo; private String isbn; private String idioma;

public int getId() {return id;} public void setId(int id) {this.id = id;} public String getTitulo() {return titulo;} ... }

Gera ID automaticamente (depende do banco usado)

Page 40: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Passo-a-passo JPA: persistência•Crie um cliente Java. Em Java EE use um WebServlet, ManagedBean

(exemplo abaixo) ou Session Bean •Obtenha uma referência para o EntityManager da unidade de persistência

•Chame os métodos de EntityManager dentro de contexto transacional (automático em Session Beans)@Named @RequestScoped public class LivroBean { @PersistenceContext(unitName="biblioteca-PU") EntityManager em;

@Override @Transactional public Collection<Livro> getLivros() { String query = "select livro from Livro livro"; return em.createQuery(query, Livro.class).getResultList(); } @Override @Transactional public int insert(Livro livro) { em.persist(livro); return em.merge(livro).getId(); } ...

<h:dataTable value="#{livroBean.livros}" var="livro"> <h:column>#{livro.isbn}</h:column> <h:column>#{livro.titulo}</h:column> <h:column>#{livro.idioma}</h:column>

Cliente para o ManagedBean

Page 41: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Exercícios•1. Configure seu ambiente para usar JPA (persistence.xml)

•a. Ambiente standalone: carregue as dependências necessárias no ClassPath, configure um banco de dados e um provedor

•b. Ambiente Java EE: configure um datasource JTA no servidor de aplicações e um provedor de persistência

•2. Construa a entidade da Hierarquia 1 (classe Livro)

•Não crie uma tabela em SQL: configure para que as tabelas do banco sejam geradas automaticamente) e chame métodos para inserir e selecionar objetos

•Depois de configurado, rode a classe PopulateLivros para preencher a tabela com dados que possam ser pesquisados

Page 42: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7 JPA

java persistence api3

persistência

Page 43: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Operações CRUD•Create, Retrieve, Update, Delete (Criar, Recuperar, Atualizar,

Remover) são as principais tarefas da camada de persistência

•Podem envolver uma entidade ou uma rede de entidades interligadas através de relacionamentos

•JPA oferece várias maneiras de realizar operações CRUD:

•Métodos de persistência transitiva: persist, merge, delete, find •Java Persistence Query Language (JPQL) •API Criteria •SQL nativo

Page 44: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Retrieve com JPQL

•A obtenção de uma entidade, o “R” de “Retrieve” do acrônimo CRUD, pode ser feita conhecendo-se sua chave primária através de find:

Livro livro = em.find(Livro.class, 1234);

•Outra alternativa é realizar uma consulta pesquisando o estado da entidade com JPQL através de um Query (ou TypedQuery):

TypedQuery query = em.createQuery("select m from Livro m where m.id=:id", Livro.class); query.setParameter("id", 1234); Livro livro = query.getSingleResult();

Page 45: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Retrieve com Criteria•Criteria é um query construído dinamicamente via relacionamentos entre

objetos. É ideal para pesquisas que são construídas em tempo de execução:

•Para usar a API desta forma, a classe Livro_class foi gerada automaticamente (veja: Criteria Metamodel API) pelas ferramentas da IDE (plug-in Maven)

CriteriaBuilder builder = em.getCriteriaBuilder();

CriteriaQuery<Livro> criteria = builder.createQuery(Livro.class);

Root<Livro> queryRoot = criteria.from(Livro.class);

criteria.where(builder.equal(queryRoot.get(Livro_.id), 1234));

TypedQuery<Livro> q = em.createQuery(criteria);

Livro livro = q.getSingleResult();

Page 46: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Create-Update-Delete com find e JPQL

•Operações que envolvem atualização, “Create”, “Update” e “Delete”, geralmente são executadas através de métodos de persistência transitiva persist, merge e delete

•A mesma alteração também pode ser realizada via JPQL:

Query query = em.createQuery("UPDATE Livro m" + "SET m.titulo = :titulo WHERE m.id = :id"); query.setParameter("titulo", "Novo título"); query.setParameter("id", "1234"); query.executeUpdate();

Livro livro = em.find(Livro.class, 1234); livro.setTitulo("Novo título"); em.merge(livro);

Page 47: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Create-Update-Delete com Criteria

•As mesmas operações podem ser realizadas com a API Criteria

CriteriaBuilder builder = em.getCriteriaBuilder();

CriteriaUpdate updateCriteria = builder.createCriteriaUpdate(Livro.class);

Root<Livro> updateRoot = updateCriteria.from(Livro.class);

updateCriteria.where(builder.equal(updateRoot.get(Livro_.id), "1234"));

updateCriteria.set(updateRoot.get(Livro_.titulo), "Novo título");

Query q = em.createQuery(updateCriteria);

q.executeUpdate();

Page 48: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Operações de persistência•Uma entidade pode estar em quatro estados durante seu ciclo de vida

•transiente (new) - @Id = null •persistente (managed) - @Id != null e sincronizado com tabela •desligado (detached) - @Id != null e não sincronizado (pode estar obsoleto) •removido (removed) - @Id != null mas registro inexistente na tabela

•O estado determina o comportamento do objeto quando são chamadas operações de persistência transitiva sobre ele

•Entidade nova (transiente) ainda não inserida no banco tem ID null

•Quando a entidade torna-se persistente ela recebe um ID. Uma vez atribuído um ID a uma entidade, esse valor não muda mais

Page 49: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Ciclo de vida e operações de persistência

Page 50: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Controle da persistência•void persist(objeto) – Gera SQL INSERT e transforma o objeto em uma entidade

persistente. Causa EntityExistsException se o ID já existir no banco.

•Object merge(objeto) – Gera SQL UPDATE ou INSERT e devolve a entidade construída. O INSERT será gerado se o ID do objeto for null. Caso contrário, o ID será chave primária para realizar UPDATE. Causa IllegalArgumentException se ID não for null e não existir no banco.

•void remove(objeto) – Remove o registro do banco, desligando a entidade permanentemente.

•void detach(objeto) – Separa a instancia do seu registro tornando a entidade desligada (detached). Ocorre em entidades usadas fora do contexto transacional. Um merge() ou refresh() dentro do contexto transacional religa a entidade tornando-a persistente.

•void refresh(objeto) – Sincroniza a entidade com dados obtidos do banco, sobrepondo alterações que tenham sido feitas no estado do objeto.

•void flush() – Sincroniza as entidades do contexto de persistência (oposto de refresh).

Page 51: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Estados da Persistência

Transiente

Desligado

Persistente

Pessoa

nome=Yodaid=0

Pessoa

id nome

Pessoa

nome=Yodaid=1

Pessoa

id nome

1 Yoda

Pessoa

nome=Jabbaid=1

Pessoa

id nome

1 Jabba

Pessoa

nome=Jabbaid=1

Pessoa

id nome

1 Jabba

Pessoa

nome=Lukeid=1

Pessoa

id nome

1 Jabba

Classes Tabelas

Atualização não foi sincronizada no banco

Page 52: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Callbacks•@PostLoad - executado depois que uma entidade foi carregada no contexto

de persistência atual (ou refresh)

•@PrePersist - executado antes da operação persist ser executada (ou cascade - sincronizado com persist se entidade for sincronizada via merge)

•@PostPersist - executado depois que entidade foi persistida (inclusive via cascade)

•@PreUpdate - antes de operação UPDATE

•@PostUpdate - depois de operação UPDATE

•@PreRemove - antes de uma operação de remoção

Page 53: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

EntityListener•Para declarar callbacks em uma classe separada, pode-se usar a anotação

@EntityListener na entidade informando o nome da classe que os contém:

•Neste caso, os métodos devem receber a entidade como parâmetro:

@Entity @EntityListeners(LivroListener.class) public class Livro implements Serializable { … }

public class LivroListener { @PostLoad public void livroLoaded(Livro livro) { ... } ... }

Page 54: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Exercícios•3. Escreva um cliente JPA simples para •a) Inserir uma lista de livros no banco de dados (converta o código de

PopulateLivros.java para JPA) •b) Listar os livros •c) Alterar um dos livros (trocar o título) •d) Remover um dos livros •e) Recuperar um dos livros pela chave primária •f) Listar a coleção de objetos resultante

•4. Execute a classe PopulateFilmes.java (que cria a Hierarquia 2) e escreva um cliente que liste todos os filmes e diretores

Page 55: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7 JPA

java persistence api4

mapeamento de entidades

Page 56: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Mapeamento de entidades•Uma classe que representa uma entidade

• deve ser anotada com @Entity (ou declarada como <entity> no deployment descriptor orm.xml)

• deve ter um campo @Id (a menos que participe como subclasse de uma hierarquia mapeada em JPA)

• se não usar os valores default, deve declarar mapeamentos explícitos para tabelas e colunas (@Table, @Column, @JoinColumn)

•Deve ter um construtor sem argumentos e não pode ser interface ou um enum ou classe final, nem ter variáveis de instância ou métodos finais

Page 57: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Mapeamento de 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

•O estado persistente é representado pelas variáveis de instância

• Acessadas via propriedades (getters/setters)

• Por default, variáveis de instância não declaradas transient e que não tenham a anotação @Transient são consideradas persistentes

Page 58: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Mapeamento de 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>)

•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

Page 59: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Mapeamento com defaults@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)

Anotações também possuem propriedades configuráveis;

se omitidas, são usadas as default

Page 60: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Mapeamento detalhado@Entity @Table(name="CLIENTES", schema="loja") public class Cliente implements Serializable { @Id @GeneratedValue(strategy=SEQUENCE, generator="CLI_SEQ") @Column(name="CUST_ID") private Long id;

@Basic @Column(name="NOME_CL", nullable=false, length=512) private String nome; @Basic @Column(name="END_CL", nullable=false, length=512) private Endereco endereco;

@OneToMany(Cascade={CascadeType.ALL}, mappedBy="cliente", fetch=FetchType.EAGER) @JoinColumn(name="CLIENTE_ID", nullable=false) private Set<Pedido> pedidos = new HashSet(); @ManyToMany(mappedBy="clientes") @OrderBy("valor ASC") @JoinTable(name="CLIENTES_PAGAMENTOS", joinColumns= @JoinColumn(name="CLIENTE_ID", referencedColumnName="ID"), inverseJoinColumns= @JoinColumn(name="PAG_ID", referencedColumnName="ID")) private Set<Pagamento> formasPagamento = new HashSet(); ... }

Anotações detalhando forma como entidade é mapeada às tabelas, e

selecionando configurações default para gravação e recuperação de objetos

Page 61: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7 •5. Configure um mapeamento entre a tabela Livro e a classe Livro

•6. Configure um mapeamento entre a classe Movie e a tabela Filme

Exercícios

CREATE TABLE Livro( id INTEGER PRIMARY KEY, isbn VARCHAR(13) UNIQUE, titulo VARCHAR(256), idioma CHAR(2) )

CREATE TABLE Filme ( id INTEGER PRIMARY KEY, imdb CHAR(9) NOT NULL, titulo VARCHAR(256), diretor VARCHAR(64), ano INTEGER, duracao INTEGER )

Livroid: int titulo: String isbn: String idioma: String

Movie

id: int title: String imdb: String director: Director year: int duration: int

Page 62: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7 JPA

java persistence api5

mapeamento de relacionamentos

Page 63: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Relacionamentos entre entidades•Para mapear relacionamentos, JPA usa informações da estrutura do

código Java e anotações mínimas (serão usados defaults onde possível)

•A cardinalidade define o número de entidades em cada lado. Podem ser mapeados “muitos” e “um” resultando em quatro possibilidades: •Um para muitos •Muitos para um •Um para um •Muitos para muitos.

•As duas primeiras são equivalentes, portanto há três associações: •@ManyToOne / @OneToMany•@OneToOne•@ManyToMany

Page 64: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

@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 produto.getPreco() * 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

* Essas anotações são insuficientes para a geração automática do esquema (as tabelas devem existir antes)

Page 65: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Associações bidirecionais•Se as anotações @OneToOne, @ManyToMany e @ManyToOne forem

usadas em associações bidirecionais é necessário especificar anotações de ambos os lados e utilizar o atributo mappedBy para informar o atributo da outra classe que faz a associação

•O diagrama abaixo ilustra algumas associações bidirecionais.

@OneToOne CPF cpf;

@OneToOne(mappedBy="cpf") Cliente cliente;

@ManyToManySet<Turma> turmas;

@ManyToMany(mappedBy="turmas") Set<Aluno> alunos;

@ManyToOne Item item;

@OneToMany(mappedBy="item")Set<Produto> produtos;

Page 66: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

@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

Page 67: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

@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); if(!turmas.contains(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); if(!alunos.contains(aluno)) aluno.matricular(this); }

...

}Métodos utilitários para adicionar alunos e turmas

Page 68: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Relacionamentos um-para-um•Objetos em um relacionamento com alto grau de dependência. No modelo

relacional isto pode ser implementado de três maneiras:

•Dois objetos, uma única tabela (dados em colunas da mesma tabela) •Um objeto, duas tabelas (dados em colunas de outra tabela) •Dois objetos, duas tabelas unidas por associação

•Em JPA, a terceira estratégia pode ser implementada usando @ManyToOne (unidirecional com @UniqueConstraint) ou mais facilmente usando @OneToOne (via chave estrangeira ou primária).

•As duas primeiras estratégias não são relacionamentos entre entidades, mas associações com instâncias ou coleções. Em JPA, a primeira é implementada usando @Embeddable e a segunda com @SecondaryTable.

Page 69: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

@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

Page 70: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Tipos das Coleções: List ou Set•Relacionamentos @ManyToOne e @ManyToMany envolvem coleções que

normalmente são declarados como Set ou List

•O mapeamento natural para registros em uma tabela é java.util.Set, porque Sets não possuem uma ordem especifica e não podem ser duplicados

•Sets podem ser ordenados no query usando @OrderBy e na instância usando uma implementação ordenada como TreeSet

•Pode-se usar List quando o índice é importante ou para compatibilidade com outros componentes (ex: componentes Primefaces que esperam List)

Page 71: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Mapas•E possível mapear uma coleção a um mapa usando @MapKey e representando

a coleção como um java.util.Map.

•Um Map contem um Set de chaves e uma Collection de valores, e é indicado situações nas quais é mais eficiente recuperar um objeto através de uma chave.

•A chave default é a chave-primária dos objetos da coleção:

@Entity public class LojaVirtual { ... @OneToMany(mappedBy="lojaVirtual") @MapKey // indexado pela chave primaria public Map<Long, Cliente> clientes = new HashMap <>(); ... }

Page 72: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Mapas•Usando o atributo name é possível indexar por outras propriedades dos

objetos da coleção:

•O mapeamento da chave também pode ser feito através das colunas, em vez dos atributos, usando @MapKeyColumn e @MapKeyJoinColumn.

•Existem ainda mais duas anotações para @MapKey

•@MapKeyEnumerated, se a chave for uma enumeração •@MapKeyTemporal, se a chave for uma data ou Timestamp.

@Entity public class LojaVirtual { ... @OneToMany(mappedBy="lojaVirtual") @MapKey(name="cpf") // indexado pelo CPF public Map<String, Cliente> clientes = new HashMap<>(); ... }

Veja mais detalhes na documentação

Page 73: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Componentes @Embeddable•Entidades são objetos persistentes que têm identidade no banco

•Objetos que contém dados persistentes mas não têm identidade unívoca no banco são identificados pelo seu estado, ou valor (value objects).

•Em JPA são anotados como @Embeddable

•No modelo de domínio representam um objeto independente, mas no modelo relacional são apenas algumas colunas de uma tabela.

•São componentes da entidade que possui a tabela e declarados como atributos anotados como @Embedded

•Muitas associações 1-1 podem ser implementadas de maneira mais eficiente como objetos embutidos.

Page 74: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Componentes @Embeddable

Cliente nome email cartao

Endereco Rua CEP Cidade

enderecoEntregaenderecoCobranca

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

•Uma única tabela contém dados dos objetos Cliente e Endereco

•Endereco é um componente de Cliente, e declarado como @Embeddable

•Um Cliente tem dois Enderecos e cada associação é declarada como @Embedded

Page 75: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Componentes @Embeddable@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

Page 76: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

@Embeddable collections•Se uma entidade contém uma coleção de componentes embutidos, ou tipos

básicos (que não são entidades) deve ser anotado com @ElementCollection

•A entidade abaixo contém uma coleção de objetos Endereco, que são @Embeddable, e uma coleção de Strings:

@Entity public class Representantes { ... @ElementCollection private Set<Endereco> enderecos = new HashSet<>(); @ElementCollection private Set<String> emails = new HashSet<>(); ... }

Page 77: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Chaves compostas•@Embeddable pode ser usado na criação de chaves compostas. Por

exemplo, uma chave-primária que consiste de dois campos do tipo String:

•Ela pode ser usada em uma entidade anotada com @EmbeddedId:

•É responsabilidade da aplicação gerenciar o estado da chave composta, para que a persistência transitiva ocorra corretamente.

@Entity @Table(name = "DEPENDENCIA") public class Dependencia { @EmbeddedId private DependenciaId id; // ... }

@Embeddable public class DependenciaId { @Column(name = "APP_ID") private String appID; @Column(name = "GROUP_ID") private String groupID; //... }

Page 78: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Mapeamento de enumerações•Enumerações podem ser persistidas se marcadas com @Enumerated

public enum Regiao { NORTE, NORDESTE, SUL, SUDESTE, CENTRO_OESTE;}

•Exemplo:

@Entitypublic class SalaDeCinema { ... @Enumerated(EnumType.STRING) private Regiao regiao;

•O EnumType default é ORDINAL: grava número no registro da tabela. STRING é não é afetado pela ordem das constantes (grava texto na tabela).

Page 79: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Mapeamento de uma classe a duas tabelas

•Usa-se @SecondaryTable para construir uma entidade que obtém seus dados de duas tabelas.

•No exemplo abaixo a entidade Usuario está mapeado a uma tabela principal (USUARIOS) e uma tabela secundária (IMAGENS)

Page 80: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Mapeamento de uma classe a duas tabelas•@Table é a tabela principal e @SecondaryTable a tabela secundária, que

indica coluna(s) contendo a chave primária usada(s) para realizar a junção.

•@PrimaryKeyJoinColumn contém: chave primária da tabela principal, chave referenciada na tabela secundária (ou apenas o primeiro se forem iguais). O atributo da segunda tabela informa a tabela e coluna a ser mapeada

@Entity @Table(name="USUARIOS") @SecondaryTable(name="IMAGENS", pkJoinColumns = @PrimaryKeyJoinColumn(name="USUARIO_ID", referencedColumnName="IMG_ID")) public class Usuario implements Serializable { ... @Id Column(name="USUARIO_ID") private Long userId;

@Column(table="IMAGENS", name="URL_IMG", nullable=true) private String avatar; ...

Page 81: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Transitividade da persistência•Relacionamentos em JPA são implementados em Java puro, e não são

gerenciados pelo container por default. Alterações precisam ser sincronizadas:

Pedido p = new Pedido();Item i = new Item();p.addItem(i); // atualizando o pedidoitem.setPedido(p); // atualizando o item (se bidirecional)

•As entidades precisam ser persistentes. Tentar adicionar uma entidade transiente a uma entidade persistente causa TransientObjectException.

•persist() ou merge() dentro de um contexto transacional resolve o problema:

em.persist(p); em.persist(i);

Page 82: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Transitividade da persistência

•Pode-se configurar persistência transitiva no JPA usando o atributo cascade das anotações de relacionamentos.

•Para propagar a inserção de entidades use CascadeType.PERSIST:

@OneToMany(cascade={CascadeType.PERSIST}, mappedBy="item" )private Set<Item> itens = new HashSet<Item>();

•Quando um Pedido for persistido no banco, itens que estiverem na hierarquia de objetos também serão persistidos automaticamente.

Page 83: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

CascadeType•O atributo cascade recebe um array de opções CascadeType

•PERSIST – propaga operações persist() e merge() em objetos novos •MERGE – propaga operações merge() •REMOVE – propaga operações remove() •DETACH – propaga operações detach() •REFRESH – propaga operações refresh() •ALL – propaga todas as operações. Declarar cascade=ALL é o mesmo que

declarar cascade={PERSIST, MERGE, REMOVE, REFRESH, DETACH}

•Um uso típico é PERSIST + MERGE, que garante inserts e updates transitivos

@OneToMany(cascade={CascadeType.PERSIST, CascadeType.MERGE})

•Se a remoção de um Pedido exigir a remoção de seus Itens um REMOVE é necessário. Pode-se usar ALL para que todas as operações sejam transitivas

Page 84: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Lazy loading•Lazy loading um padrão de design usado para adiar a inicialização de um

objeto para quando ele for realmente necessário

•ORMs usam estratégias de lazy loading para otimizar pesquisas •Contribui para a eficiência da aplicação se usado corretamente

•Um query, por default, retorna uma coleção de proxies para seus elementos (e não a coleção preenchida pelos próprios elementos)

•Se um cliente fora do contexto transacional tentar acessar um elemento da coleção, haverá uma exceção de inicialização lazy. O comportamento default depende do provedor usado

•Hibernate lança LazyInitializationException.

•EclipseLink captura a exceção e abre nova conexão ao banco para obter os dados

Page 85: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Configuração de lazy loading•É possível controlar o lazy loading configurando a recuperação default

como eager (ansiosa), em vez de lazy (preguiçosa) de duas maneiras:

•Através de mapeamento (estabelece um default para todas as situações) •Através de instruções no query (a cada consulta)

•O atributo fetch=FetchType das anotações de relacionamentos configura o modo eager como default para todas as operações

@OneToMany(mappedBy="pedido", fetch=FetchType.EAGER)private Set<Item> itens = new HashSet<Item>();

•No query, um fetch join devolve a coleção com todos os seus elementos

select p from Pedido p join fetch p.itens

Page 86: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Exercícios•7. Implemente o mapeamento Movie-Director da Hierarquia 2

•8. Implemente os mapeamentos de Cliente-Pedido-Item-Produto na Hierarquia 3

•9. Implemente todos os mapeamentos da Hierarquia 4

•Use @Embedded para o relacionamento Etapa-Localidade

•Use @OneToOne para o relacionamento Participante-Ingresso

•Implemente uma enumeração para guardar o status do ingresso com as constantes PAGO e NAO_PAGO

•O relacionamento Corrida-Etapa é unidirecional

•10. Implemente o relacionamento Assunto-Assunto na Hierarquia 35

Page 87: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7 JPA

java persistence api6

mapeamento de herança

Page 88: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Mapeamento de herança

•Entidades são objetos e suportam herança de classes, associações e queries polimórficos. Podem ser abstratas ou concretas, e podem ser subclasses ou superclasses de classes que não são entidades.

•Mas não existe herança em tabelas. Herança é o descasamento mais visível entre os mundos relacional e orientado a objetos.

•O mundo OO possui relacionamento “é um” e “tem um”, enquanto que o mundo relacional apenas possui relacionamento “tem um”.

•Há três estratégias para lidar com esse problema (sugeridas por Scott Ambler, 2002). Essas estratégias são adotadas na arquitetura do JPA.

Page 89: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

MappedSuperclass•Entidades podem ter superclasses que não são entidades

•Se a superclasse possuir a anotação @MappedSuperclass, seus atributos serão herdados e farão parte do estado persistente das subclasses

•Uma @MappedSuperclass também pode incluir anotações de persistência nos seus atributos, mas não é uma entidade e não pode ser usada com operações de EntityManager ou Query (não está mapeada a uma tabela)

•Apenas as subclasses de entidades concretas são mapeadas a tabelas e podem conter colunas correspondentes aos atributos herdados.

@MappedSuperclass public class Quantia { @Id protected Long id; protected BigDecimal valor; ... }

@Entity public class Pagamento extends Quantia { ... }

@Entity public class Divida extends Quantia { ... }

Page 90: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

@Inheritance e InheritanceType•A anotação javax.persistence.Inheritance é usada para configurar o

mapeamento de herança entre entidades em JPA

•Elas implementam as três estratégias citadas que são selecionadas através das constantes da enumeração InheritanceType:

public enum InheritanceType { SINGLE_TABLE, JOINED, TABLE_PER_CLASS };

•A estratégia default é SINGLE_TABLE, que mapeia todas as classes de uma hierarquia a uma única tabela no banco de dados

•Há muitas possibilidades de configuração (mostraremos as mais simples)

Page 91: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Tabela por Classe Concreta: TABLE_PER_CLASS

Pagamento idvalor

Creditonumero validade

<<Entidade>>

Debitobanco conta

<<Entidade>>

@Id declarado apenas na superclasse

@Entity @Inheritance(strategy=InheritanceType.TABLE_PER_CLASS) public abstract class Pagamento { @Id @GeneratedValue private long id; }

@Entity public class Debito extends Pagamento {...}

ID NUMERO VALIDADE5

ID BANCO CONTA5

CREDITO

DEBITO

<<Entidade>>

Page 92: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Tabela por Classe Concreta: TABLE_PER_CLASS

•Tem como vantagem o mapeamento direto entre classe e tabela normalizada.

•A gravação é realizada via classe concreta, mas a pesquisa pode ser polimórfica, via classe abstrata e com resultado que inclui as subclasses concretas

•Ex: filtrar Pagamentos por valor, sem precisar saber se Crédito ou Débito:

select p from Pagamento p where p.valor > 1000

•A desvantagem dessa estratégia é a complexidade e ineficiência dos queries gerados. Exemplo de SQL gerado no Hibernate:

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

Page 93: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Tabela por hierarquia: SINGLE_TABLE@Entity @Inheritance(strategy=InheritanceType.SINGLE_TABLE) @DiscriminatorColumn(name="TIPO") public abstract class Pagamento { @Id @GeneratedValue private long id; }

ID TIPO VALOR NUMERO VALIDADE BANCO CONTA5 crd 100.0 23459403 12/15 null null

6 deb 100.0 null null 1234-5 993423-3

PAGAMENTO

Coluna (@DiscriminatorColumn) presente na tabela mas sem mapeamento na classe

@Entity @DiscriminatorValue("deb") public class Debito extends Pagamento {...}

Pagamento idvalor

Creditonumero validade

<<Entidade>>

Debitobanco conta

<<Entidade>>

<<Entidade>>

Page 94: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Tabela por hierarquia: SINGLE_TABLE

•Mapeia uma hierarquia de classes inteira a uma tabela

•A tabela precisa ter colunas para todas as propriedades de todas as classes.

•A vantagem são pesquisas polimórficas mais eficientes, já que tudo acontece em uma única tabela. Este é o SQL conceitual para um query polimórfico:

select ID, VALOR, BANCO, CONTA, NUMERO, VALIDADE from PAGAMENTO where VALOR > 1000

•Em query na classe concreta, o provedor de persistência poderá gerar este SQL:

select ID, VALOR, BANCO, CONTA, NUMERO, VALIDADE from PAGAMENTO where TIPO = 'deb' and VALOR > 1000

•A principal desvantagem dessa estratégia é que as tabelas não são normalizadas

Page 95: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Tabela por subclasse: JOINED@Entity @Inheritance(strategy=InheritanceType.JOINED) public abstract class Pagamento { @Id @GeneratedValue private long id; }

Pagamento idvalor

Creditoidnumero validade

ID NUMERO VALIDADE5

<<Entidade>>

Debitoidbanco conta

<<Entidade>>

ID BANCO CONTA5

CREDITO

DEBITO

@Entity public class Debito extends Pagamento {...}

ID VALOR5

PAGAMENTO ID é PK e FK (default)

<<Entidade>>

Page 96: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Tabela por subclasse: JOINED

•Uma Classe abstrata ou concreta = Uma Tabela distinta; relacionamento através de equivalência de chave primária e estrangeira (default)

•Modelo relacional normalizado •Evolução sem efeitos colaterais: novas classes e tabelas podem ser criadas sem

afetar existentes •Aplicação de restrições de integridade mais simples •Performance da pesquisa polimórfica ainda é baixa em hierarquias complexas

(usa dados de todas as tabelas envolvidas)

•Os provedores de persistência* geralmente geram SQL com outer join para pesquisas polimórficas e inner join para pesquisas em classes concretas

*Hibernate e EclipseLink

Page 97: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Qual estratégia?Há necessidade

de consultas polimórficas?

Hierarquia de classes é pequena?

Tabela por Hierarquia InheritanceType.SINGLE_TABLE

Tabela por Subclasse InheritanceType.JOINED

Tabela por Classe Concreta InheritanceType.TABLE_PER_CLASS

Tabelas tem que ser

normalizadas?

NÃO*

* Se houver suporte no provedor (o suporte é opcional)

SIM

SIM

NÃO

NÃO

SIM

(default)

Page 98: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Exercícios

•11. Implemente um mapeamento da hierarquia Usuario-Operador-Cliente (Hierarquia 3) usando qualquer uma das três estratégias

•12. Implemente uma mapeamento da hierarquia Exemplar-Exemplar Eletrônico-Exemplar Impresso (Hierarquia 5) usando uma estratégia diferente

Page 99: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7 JPA

java persistence api7

queries jpql

Page 100: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Consultas (queries)•Consultas podem ser construídas para recuperar entidades a

partir de critérios baseados em seu conteúdo

•JPA possui duas estratégias nativas:

•JPQL – linguagem similar a SQL baseada em comandos de texto

•Criteria – API usada para construir consultas usando objetos.

•JPQL é geralmente mais fácil de aprender, mas Criteria permite a criação de queries com maior potencial de reuso e evolução, além de ser recomendada para queries dinâmicas

Page 101: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Cláusulas•Consultas em bases de objetos têm princípios similares a

consultas em bancos de dados

•A cláusula mais importante é FROM, que declara o escopo da pesquisa. Na API Criteria é representada por um objeto raiz.

•A clausula SELECT indica o que está sendo selecionado dentro do escopo FROM. Em JPA pode-se selecionar entidades, seus atributos, e resultados de operações realizados sobre elas

•A cláusula opcional WHERE declara filtros que restringem os resultados da pesquisa. Sem WHERE todos os elementos do escopo declarado em FROM serão recuperados

Page 102: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Joins•Operação que amplia o domínio da função para incluir objetos

de um relacionamento usadas em JPQL e Criteria

•Consultas que navegam no grafo de objetos usando o operador ponto (ex: cliente.pedido.item) escondem joins implícitos

•Joins em grafos de objetos são similares mas não idênticos a joins no mundo relacional. Há três tipos em JPA. :

•Lazy Inner Joins (default – joins implícitos são sempre inner joins) •Lazy Outer (ou Left) Joins •Eager (ou Fetch) Joins (que podem ser inner ou outer)

Page 103: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Inner Joins e Outer joins

•Inner Joins consideram apenas resultados que contém o relacionamento

•Elementos que não possuem o relacionamento declarado são filtrados

•Exemplo: uma consulta sobre objetos Cliente para obter o total de Pedidos (relacionamento Cliente-Pedido)

•Um inner join não retorna os clientes que não têm pedidos.

•Um outer join retorna tudo, mesmo que o cliente seja null

Page 104: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Lazy Joins e Eager Joins•A inicialização dos elementos de uma coleção é Lazy por default

•Uma coleção obtida em uma consulta pode conter apenas um proxy para cada elemento (é preciso fazer novas consultas para obter cada um)

•O comportamento exato é dependente do contexto transacional e também do provedor de persistência utilizado

•Eager Joins garantem que a coleção seja inicializada antes do uso

•Depois da consulta a coleção está povoada com todos os seus elementos

• Isto pode ser pré-configurado no mapeamento, mas é mais eficiente poder selecionar esse comportamento durante a consulta

Page 105: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

JPQL (JPA Query Language)• Linguagem de recuperação de dados •Similar a linguagens de query de objetos (HQL, EJB-QL, etc.) que a precederam •Parece com SQL mas opera sobre objetos e não tabelas

•Consultas são objetos da classe Query/TypedQuery e podem ser construídas através de métodos de EntityManager

•As instruções do query podem ser passadas diretamente para o método createQuery() como parâmetro do tipo String.

@PersistenceContext EntityManager em; ... TypedQuery query = em.createQuery("SELECT p FROM Produto p", Produto.class);

Page 106: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Named queries•O query pode também ser declarado previamente em anotações

@NamedQuery em cada entidade:

•Associado a um identificador, referenciado em createNamedQuery()

@Entity @NamedQueries({ @NamedQuery(name="selectAllProdutos", query="SELECT p FROM Produto p") }) public class Produto implements Serializable { ... }

TypedQuery query = em.createNamedQuery("selectAllProdutos", Produto.class);

Page 107: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Consultas parametrizadas

•Os parâmetros podem ser declarados em JPQL usando identificadores numéricos ou nomes precedidos por “:”:

•Se houver parâmetros, eles podem ser preenchidos através de um ou mais métodos setParameter() antes de executar o query.

TypedQuery query = em.createQuery("SELECT p FROM Produto p WHERE p.preco > :maximo", Produto.class);

query.setParameter("máximo", 1000);

Page 108: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Métodos que executam queries•Retornam resultados

•Se o resultado for uma coleção, pode-se usar getResultList():

•Se retornar apenas um item (por exemplo, se o produto for selecionado por ID ou um campo unívoco), pode-se usar getSingleResult():

•Há outros métodos de execução não fazem pesquisa mas são usados para remoção ou atualização, como executeUpdate()

List<Produto> resultado = query.getResultList();

Produto produto = query.getSingleResult();

Page 109: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Sintaxe de uma operação SELECT•A principal operação de JPQL é SELECT, que tem a seguinte sintaxe geral cláusula_select cláusula_from [cláusula_where] [cláusula_group_by] [cláusula_having] [cláusula_order_by]

SELECT p.nome FROM Produto AS p WHERE p.codigo = '123'

Define o contexto da pesquisa e declara p como alias da entidade Produto

Seleciona valores no contexto da entidade p

Parâmetro

Restrição da seleção

SELECT p FROM Produto p WHERE p.nome = :n

Alias (AS é opcional)

Parâmetro de query

Seleção de entidades

(cláusulas opcionais)

Page 110: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Cláusula FROM•A cláusula FROM define o escopo informando qual ou quais os objetos

que estão sendo pesquisados, e declara aliases usados no resto do query.

•Cada alias tem um identificador e um tipo.

•O identificador é qualquer palavra não-reservada e o tipo é o nome da entidade identificada como @Entity.

•A palavra-chave AS (opcional) conecta o tipo ao identificador

•A cláusula FROM também pode selecionar múltiplos objetos e atributo e incluir vários conectores de JOIN (inner join, left outer join).

... FROM Produto AS p

Tipo(Entidade) Identificador(alias)

Page 111: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Cláusula SELECT• Informa o que se deseja obter. Pode retornar

•entidades, •atributos dos objetos, • resultados de expressões, • tuplas envolvendo atributos, entidades e resultados de expressões

•Pode ser seguida de DISTINCT para eliminar valores duplicados

•SELECT utiliza o alias declarado na cláusula FROM:

SELECT p FROM Produto p SELECT DISTINCT p FROM Produto p SELECT p.codigo FROM Produto p SELECT DISTINCT p.codigo FROM Produto p

Page 112: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

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 identificados por número (?1, ?2) ou identificador (:nome, :item).

•Os literais usados nas pesquisas podem ser:

•Strings, representados entre apóstrofes: 'nome' •Números, que têm mesmas regras de literais Java long e double •Booleanos, representados por TRUE e FALSE (case-insensitive)

Page 113: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Operadores de WHERE•Navegação .

•Expressões matemáticas +, -, *, /

•Expressões de comparação =, >, >=, <, <=, <>

•Operadores lógicos NOT, AND, OR

•Outros operadores: [NOT] BETWEEN, [NOT] IN, [NOT] LIKE, IS [NOT] NULL, IS [NOT] EMPTY, [NOT] MEMBER

•O operador LIKE possui operadores adicionais:

•_ representa um único caractere •% representa uma seqüência de zero ou mais caracteres •\ caractere de escape (necessário para usar _ ou %) literalmente

Page 114: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Funções

•Funções podem aparecer em cláusulas WHERE ou SELECT:

•Manipulação de strings (WHERE): CONCAT, SUBSTRING, TRIM, LOWER, UPPER, LEADING, TRAILING, BOTH, LENGTH, LOCATE

•Funções aritméticas (WHERE): ABS, SQRT, MOD, SIZE

•Data e hora (WHERE): CURRENT_DATE, CURRENT_TIME, CURRENT_TIMESTAMP

•Funções de agregação (SELECT): COUNT, MAX, MIN, AVG, SUM

Page 115: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

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

Page 116: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Exemplos

•Encontre todos os produtos cujo fabricante é Sun ou Intel

SELECT p FROM Produto p WHERE p.fabricante IN ('Intel', 'Sun')

•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'

Page 117: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Exemplos

•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

Page 118: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Exemplos•Retorne os pedidos que contem um determinado item (passado como

parâmetro)

SELECT pedido FROM Pedido pedido WHERE :item IS MEMBER pedido.itens

•Encontre produtos com preços entre 1000 e 2000 ou que tenham código 1001

SELECT p FROM Produto p WHERE p.preco BETWEEN 1000 AND 2000 OR codigo = 1001

Page 119: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Exemplos com relacionamentos•Selecione todos os clientes com pedidos que tenham total maior que

1000:

SELECT c FROM Cliente c, IN(c.pedidos) p WHERE p.total > 1000

•O mesmo query poderia ser escrito desta forma, expondo o join:

SELECT c FROM Cliente c INNER JOIN c.pedidos AS p WHERE p.total > 1000

Page 120: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Exemplos com relacionamentos•Lances onde o item de categoria iniciando em “Celular” tenha obtido lance >1000:

SELECT lance FROM Lance lance WHERE lance.item.categoria.nome LIKE 'Celular%' AND lance.item.lanceObtido.total > 1000

•Queries equivalentes. O primeiro expõe um dos joins e o segundo expõe todos: SELECT lance FROM Lance lance JOIN lance.item item WHERE item.categoria.nome LIKE 'Celular%' AND item.lanceObtido.total > 1000

SELECT lance FROM Lance AS lance JOIN lance.item AS item JOIN item.categoria AS cat JOIN item.lanceObtido AS lanceVencedor WHERE cat.nome LIKE 'Celular%' AND lanceVencedor.total > 1000

Page 121: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Exemplos usando funções•Encontre a média do total de todos os pedidos:

SELECT AVG(pedido.total) FROM Pedido pedido

•Obtenha a soma dos preços de todos os produtos dos pedidos feitos no bairro de Botafogo:

SELECT SUM(item.produto.preco) FROM Pedido pedido JOIN pedido.itens item JOIN pedido.cliente cliente WHERE cliente.bairro = 'Botafogo' AND cliente.cidade = 'Rio de Janeiro'

Page 122: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Exemplos usando funções•Obtenha a contagem de clientes agrupadas por bairro:

SELECT cliente.bairro, COUNT(cliente) FROM Cliente cliente GROUP BY cliente.bairro

•Obtenha o valor médio dos pedidos, agrupados por pontos, para os clientes que têm entre 1000 e 2000 pontos:

SELECT c.pontos, AVG(pedido.total) FROM Pedido pedido JOIN pedido.cliente c GROUP BY c.pontos HAVING c.pontos BETWEEN 1000 AND 2000

Page 123: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Exemplos com subqueries•É possível usar os resultados de um query como parâmetro de

outro através de subqueries. O query abaixo usa como restrição o resultado de um query que será testado com EXISTS.

•"Obtenha os empregados que são casados com outros empregados"

SELECT DISTINCT emp FROM Empregado emp WHERE EXISTS (SELECT conjuge FROM Empregado conjuge WHERE conjuge = emp. conjuge)

Page 124: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Exemplos com subqueries: All/Any

•ALL e ANY são usados com subqueries

•ALL retorna true se todos os valores retornados forem true •ANY só retorna true se resultado for vazio ou se todos os valores forem false

•"Retorne apenas os produtos cujo preço seja maior que o valor incluído em todos os orçamentos"

SELECT produto FROM Produto p WHERE p.preco > ALL(SELECT o.item.preco FROM Orcamento o WHERE o.item.codigo = p.codigo)

Page 125: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Queries que retornam tuplas•Queries que retornam múltiplos valores têm resultados

armazenados em arrays de objetos

• Cada índice do array corresponde respectivamente ao item selecionado, na ordem em que é expresso em JPQL

•Exemplo: a query abaixo retorna três valores: um Long, um String e um Diretor, que é uma entidade, respectivamente.

@Entity class Filme { @Id private Long id; private String imdb; private String titulo; @ManyToMany private Diretor diretor; ... }

SELECT f.id, f.titulo, d FROM Filme f join f.diretores d WHERE d.nome LIKE ‘%Allen’ @Entity class Diretor {

@Id private Long id; private String nome; ... }

Page 126: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Queries que retornam tuplas•A execução so query irá retornar cada elemento como um array do tipo

Object[] onde cada valor será armazenado em um índice

•Se houver mais de um resultado, o tipo retornado será List<Object[]>

•Para obter os dados da query anterior pode-se usar:

List<Object[]> resultado = (List<Object[]>)query.getResultAsList();

for(Object obj : resultado) { Long id = (Long)obj[0]; String titulo = (String)obj[1]; Diretor diretor = (Diretor)obj[2]; ... }

Page 127: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Tuplas como DataTransferObject (DTO)•Queries que retornam tuplas podem ter o objetivo de gerar

relatórios, ou para coletar dados para uma interface

•Os dados podem ser guardados em um objeto especialmente criado para recebê-los:

package com.acme.filmes; public class DataTransferObject { private Long id; private String titulo; private Diretor diretor; public DataTransferObject(Long id, String titulo, Diretor diretor) { this.id = id; this.titulo = titulo; this.diretor = diretor; } ... }

Page 128: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Tuplas como DataTransferObject (DTO)

•O objeto pode então ser instanciado dentro do loop:

List<Object[]> resultado = (List<Object[]>)query.getResultAsList();

for(Object obj : resultado) { Long id = (Long)obj[0]; String titulo = (String)obj[1]; Diretor diretor = (Diretor)obj[2]; DataTransferObject dto = new DataTransferObject(id, titulo, director); // envia dto para algum lugar }

Page 129: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Tuplas como DataTransferObject (DTO)•Há uma sintaxe de SELECT que elimina a necessidade de escrever todo

esse código, chamando o construtor diretamente dentro do query:

• JPA 2.1 requer que o construtor use o nome qualificado da classe

•O query retorna uma List<DataTransferObject> em vez de List<Object[]>, que pode ser retornada diretamente para o cliente:

SELECT new com.acme.filmes.DataTransferObject(f.id, f.titulo, d) FROM Filme f join f.diretores d WHERE d.nome LIKE ‘%Allen’

@Named public class ManagedBean { public List<DataTransferObject> getDataToPopulateComponent() { ... return query.getResultAsList(); } ... }

Page 130: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Tuplas em JPA Criteria

•CriteriaQuery oferece outra alternativa de solução para este problema com a interface javax.persistence.Tuple

•Os resultados ainda precisam ser extraídos individualmente, mas são retornados em um objeto Tuple (em vez de Object[])

•O conteúdo de Tuple pode ser recuperado como uma List: tupla.get(0), tupla.get(1), etc.

Page 131: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Named Queries•Queries podem ser declarados em anotações e recuperadas pelo nome

• Isto, em geral é uma boa prática porque mantém todos os queries juntos, e pode facilitar a manutenção deles

•Por outro lado, os mantém distante do código que cria os queries e preenche os parâmetros, que pode dificultar o uso.

•Para declarar queries desta forma, use a anotação @NamedQueries:@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 { ... }

Page 132: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Uso de Named Queries•Para usar, chame o query pelo nome quando usar o EntityManager através

do método createNamedQuery(), e preencha seus parâmetros se houver:

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();

Page 133: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Exercícios•13. Escreva os seguintes queries em JPQL usando a Hierarquia 5:

• Todos os livros com idioma = PT ou EN •Livros cujo título tenha a palavra "the" e id entre 2 e 10 •Livros que tenham um autor chamado "John" •Autores que tenham mais de um livro •Editoras que tenham mais de um título em idioma = EN

•14. Escreva os seguintes queries usando a Hierarquia 2:

• Todos os filmes com duração maior que 100 minutos •Filmes produzidos entre 1950 e 1990 •Diretores com mais de 3 filmes

Page 134: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Exercícios•15. Escreva os seguintes queries em JPQL usando a Hierarquia 4:

•Nomes de todos os Participantes da etapa com origem: "Nova York" e destino: "Moscow" que possuem ingresso com status = "Pago"

•16. Escreva os seguintes queries usando a Hierarquia 3:

•Valor total (para cada item: item.quantidade * produto.preco) de cada pedido de status="finalizado" do cliente de userid=Fred

•Soma (sum) e média (avg) dos valores totais de todos os pedidos

Page 135: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7 JPA

java persistence api8

queries criteria

Page 136: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Criteria•Criteria é uma API do JPA que permite a construção de queries

dinâmicos e verificados em tempo de compilação, usando objetos

•Este query JPQL

select p from Produto p where p.preco < 50.0

•Pode ser expresso em Criteria da seguinte forma:

CriteriaBuilder cb = em.getCriteriaBuilder(); CriteriaQuery<Produto> query = cb.createQuery(Produto.class); // tipo do select Root<Produto> raiz = query.from(Produto.class); // tipo do from Predicate condicao = cb.lessThan(raiz.get("preco"), 50.0); // predicado query.where(condicao); // adiciona a clausula where query.select(raiz); // diz o que vai ser selecionado

Page 137: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Construção de um query•Queries de Criteria são um grafo de objetos

•A raiz do grafo é encapsulado no CriteriaQuery

•Um query mínimo requer o uso de três classes do pacote javax.persistence.criteria:

•CriteriaBuilder, que encapsula vários métodos para construir o query,

•CriteriaQuery, que representa a consulta

•Root que é raiz da consulta e representa os objetos selecionados pela cláusula FROM

Page 138: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Construção de um query•1) Criar um CriteriaQuery através da classe CriteriaBuilder:

CriteriaBuilder builder = entityManagerFactory.getCriteriaBuilder();

•2) obter o objeto que irá encapsular o query:

CriteriaQuery<Produto> query = builder.createQuery( Produto.class );

•3) O objeto raiz do grafo é declarado através da interface Root, que constrói a cláusula “from” do query. Isto é equivalente a fazer “from Produto p” em JPQL:

Root<Produto> p = query.from(Produto.class);

•4) Finalmente constrói-se a cláusula “select” do query usando o método select():

query.select(p);

•O query está pronto. Neste momento ele é equivalente ao string JPQL.

Page 139: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Execução de um Query

•Uma vez pronto, pode-se executar um Criteria Query da mesma forma que um JPQL Query

•1) Passe o objeto query como parâmetro de um TypedQuery:

TypedQuery<Produto> query = em.createQuery(query);

•2) Chame um método de execução pára obter os resultados

List<Produto> resultado = query.getResultList();

Page 140: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Consultas que retornam tuplas•Consultas que retornam múltiplos objetos podem ser feitas com

from(), join() ou fetch() e métodos similares

•O query JPQL:

SELECT p1, p2 FROM Produto p1, Produto p2

•Pode ser escrito usando Criteria da seguinte forma:

CriteriaQuery<Tuple> criteria = cb.createQuery(Tuple.class); Root<Produto> p1 = criteria.from(Produto.class); Root<Produto> p2 = criteria.from(Produto.class); criteria.multiselect(p1, p2);

Page 141: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Outer Join (Left Join)

•Um join como na query abaixo:

SELECT item, produto.nome FROM Item item LEFT OUTER JOIN item.produto produto

•Pode ser escrito em Criteria da seguinte forma:

CriteriaQuery<Tuple> criteria = cb.createQuery(Tuple.class); Root<Item> item = criteria.from(Item.class); Join<Item> produto = item.join("produto", JoinType.LEFT); criteria.multiselect(item, produto.get("nome"));

Page 142: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Fetch Join•A interface Join retornada pelo método join() é subinterface da interface

From, portanto pode ser usada em metódos que esperam um From

•Um join usando fetch como este em JPQL:

SELECT item FROM Item item JOIN FETCH item.produto

•Pode ser expresso em Criteria usando a seguinte sintaxe:

CriteriaQuery<Item> criteria = cb.createQuery(Item.class); Root<Item> item = criteria.from(Item.class); Fetch<Item, Produto> produto = item.fetch("produto"); criteria.select(item);

Page 143: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Interfaces Criteria

Expression<X>

TupleElement<X>

Selection<X>

Path<X>

From<Z, X>

Root<Z, X> Join<Z, X>

PluralJoin<Z, C, E>

CollectionJoin<Z, E>

SetJoin<Z, E>

ListJoin<Z, E>

MapJoin<Z, K, V>

Predicate<X>

SubQuery<X>

ParameterExpression<X>

Page 144: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Principais interfaces•Expression – São construídas compondo outras expressões. Retornada em métodos de

CriteriaQuery e CriteriaBuilder (sum(), diff(), equal())

•Predicate – Conjunção (ou disjunção) das restrições de query representado por valor booleano. A cláusula where recebe um Predicate. São construídos compondo outros predicados. Retornado em métodos de CriteriaBuilder (equal(), and(), or(), between())

•Path – Representa caminho de navegação em um grafo. Ex: objeto.referencia.atributo. O método get() de Root acessa atributos de objetos através de expressões de path.

•Join – Representa join para uma @Entity, objeto @Embeddable ou @Basic

•Selection – Qualquer item retornado em um resultado de query, como uma expressão (Expression), subquery (SubQuery), predicado (Predicate), caminho (Path), etc.

•SubQuery – Representa um subquery

Page 145: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Métodos de CriteriaQuery e Subquery•A hierarquia que representa um query em Criteria possui duas classes

•CriteriaQuery (query principal) •Subquery

•Elas têm a superclasse AbstractQuery em comum e métodos que representam cláusulas e outras partes de um query:

•Herdados de AbstractQuery (valem para queries principais e subqueries): distinct(), from(), groupBy(), having(), subQuery(), where() •Definidos em CriteriaQuery (valem apenas para queries principais):

multiselect(), select() •Definidos em Subquery (valem apenas para subqueries):

correlate(), getParent()

Page 146: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

CriteriaBuilder•A classe CriteriaBuilder possui métodos para a construção de

todas as expressões usadas nas cláusulas dos queries e subqueries

•Encapsuladas em instâncias de Expression ou subclasses

•Podem ser criadas chamando os factory methods de CriteriaBuilder

•Envolvem desde a criação de literais até condicionais, expressões boleanas, de comparação, etc.

Expression<Integer> i1 = builder.literal(123); Expression<Integer> i2 = builder.sum(3,4); Predicate p1 = builder.and(true, false); Predicate p2 = builder.not(p1);

Page 147: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Exemplos•Encontre todos os produtos que são chips e cuja margem de lucro é positiva

CriteriaBuilder cb = em.getCriteriaBuilder(); CriteriaQuery<Produto> query = cb.createQuery(Produto.class); Root<Produto> root = query.from(Produto.class); Predicate igual = cb.equal(root.get("descricao"), "chip"); Expression<Double> subtracao = cb.diff(root.get("preco"), root.get("custo")); Predicate maiorQue = cb.greaterThan(subtracao, 0.0); Predicate clausulaWhere = cb.and(igual, maiorQue); query.where(clausulaWhere); query.select(root); TypedQuery<Produto> q = em.createQuery(query);

Page 148: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Exemplos•Encontre todos os produtos cujo preço é pelo menos 1000 e no máximo 2000

CriteriaBuilder cb = em.getCriteriaBuilder(); CriteriaQuery<Produto> query = cb.createQuery(Produto.class); Root<Produto> root = query.from(Produto.class); Predicate between = cb.between(root.get("preco"), 1000.0, 2000.0); query.where(between); query.select(root);

Page 149: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Exemplos

•Encontre todos os produtos cujo fabricante é Sun ou Intel

CriteriaBuilder cb = em.getCriteriaBuilder(); CriteriaQuery<Produto> query = cb.createQuery(Produto.class); Root<Produto> root = query.from(Produto.class); query.where(root.get("fabricante").in("Intel", "Sun")); query.select(root);

Page 150: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Exemplos

•Encontre todos os produtos com IDs que começam com 12 e terminam em 3

CriteriaBuilder cb = em.getCriteriaBuilder(); CriteriaQuery<Produto> query = cb.createQuery(Produto.class); Root<Produto> root = query.from(Produto.class); query.where(cb.like(root.get("id"), "12%3")); query.select(root);

Page 151: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Exemplos

•Encontre todos os produtos que têm descrições null

CriteriaBuilder cb = em.getCriteriaBuilder(); CriteriaQuery<Produto> query = cb.createQuery(Produto.class); Root<Produto> root = query.from(Produto.class); query.where(cb.isNull(root.get("descricao"))); query.select(root);

Page 152: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Exemplos

•Encontre todos os pedidos que não têm itens (coleção)

CriteriaBuilder cb = em.getCriteriaBuilder(); CriteriaQuery<Pedido> query = cb.createQuery(Pedido.class); Root<Pedido> root = query.from(Pedido.class); query.where(cb.isEmpty(root.get("itens"))); query.select(root);

Page 153: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Exemplos•Retorne os pedidos que contem um determinado item (passado

como parâmetro)

Item item = new Item(); // item a ser testado // ... CriteriaBuilder cb = em.getCriteriaBuilder(); CriteriaQuery<Pedido> query = cb.createQuery(Pedido.class); Root<Pedido> root = query.from(Pedido.class); Predicate isMember = cb.isMember(item, root.get("itens")); query.where(isMember); query.select(root);

Page 154: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Exemplos•Encontre produtos com preços entre 1000 e 2000 ou que tenham código 1001

CriteriaBuilder cb = em.getCriteriaBuilder(); CriteriaQuery<Produto> query = cb.createQuery(Produto.class); Root<Produto> root = query.from(Produto.class); Predicate between = cb.between(root.get("preco"), 1000.0, 2000.0); Predicate igual = cb.equal(root.get("codigo"), 1001);

query.where(cb.or(between, igual)); query.select(root);

Page 155: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Exemplos com relacionamentos•Selecione todos os clientes com pedidos com total maior que 1000: CriteriaBuilder cb = em.getCriteriaBuilder(); CriteriaQuery<Cliente> query = cb.createQuery(Cliente.class); Root<Cliente> root = query.from(Cliente.class); Path<Pedido> pedido = root.get("pedidos"); query.where(cb.greaterThan(pedido.get("total"), 1000.0)); query.select(root);

•Mesmo query usando um inner join explícito: CriteriaBuilder cb = em.getCriteriaBuilder(); CriteriaQuery<Cliente> query = cb.createQuery(Cliente.class); Root<Cliente> root = query.from(Cliente.class); Join<Cliente, Pedido> pedido = root.join("pedidos"); query.where(cb.greaterThan(pedido.get("total"), 1000.0)); query.select(root);

Page 156: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Exemplos com relacionamentos•Lances onde o item é de categoria que começa com “Celular” e teve lance > 1000: CriteriaBuilder cb = em.getCriteriaBuilder();CriteriaQuery<Lance> query = cb.createQuery(Lance.class); Root<Lance> root = query.from(Lance.class); query.where(cb.and( cb.like(root.get("item").get("categoria").get("nome"), "Celular%"), cb.greaterThan(root.get("item").get("lanceObtido").get("total")1000.0)));query.select(root);

•Mesmo query usando vários inner joins explícitos: CriteriaBuilder cb = em.getCriteriaBuilder();CriteriaQuery<Lance> query = cb.createQuery(Lance.class); Root<Lance> root = query.from(Lance.class); Join<Lance, Item> item = root.join("item");Join<Item, Categoria> cat = item.join("categoria");Join<Item, Lance> vencedor = item.join("lanceObtido");query.where(cb.and(cb.like(cat.get("nome"), "Celular%"),cb.greaterThan(vencedor.get("total"), 1000.0)));query.select(root);

Page 157: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Exemplos

•Encontre a média do total de todos os pedidos:

CriteriaBuilder cb = em.getCriteriaBuilder(); CriteriaQuery<Double> query = cb.createQuery(Double.class); // avg retorna Double Root<Pedido> root = query.from(Pedido.class); // from Ingresso i Expression<Double> media = cb.avg(root.get("total")); query.select(media);

Page 158: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Exemplos•Obtenha a soma dos preços de todos os produtos dos pedidos feitos

no bairro de Botafogo:CriteriaBuilder cb = em.getCriteriaBuilder(); CriteriaQuery<BigDecimal> query = cb.createQuery(BigDecimal.class); Root<Pedido> root = query.from(Pedido.class);

Join<Pedido, Item> item = root.join("itens"); Join<Pedido, Cliente> cliente = item.join("cliente"); Predicate where = cb.and( cb.equal(cliente.get("bairro"), "Botafogo"), cb.equal(cliente.get("cidade"), "Rio de Janeiro") ); query.where(where); Expression<BigDecimal> total = cb.sum(item.get("produto").get("preco")); query.select(total);

Page 159: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Exemplos

•Obtenha a contagem de clientes agrupadas por bairro:

CriteriaBuilder cb = em.getCriteriaBuilder(); CriteriaQuery<Object[]> query = cb.createQuery(Object[].class); Root<Cliente> root = query.from(Cliente.class);

query.multiselect(root.get("bairro"), cb.count(root)); query.groupBy(root.get("bairro")); TypedQuery<Object[]> q = em.createQuery(query); ...

Page 160: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Exemplos•Obtenha o valor médio dos pedidos, agrupados por pontos, para

os clientes que têm entre 1000 e 2000 pontos:

CriteriaBuilder cb = em.getCriteriaBuilder(); CriteriaQuery<Object[]> query = cb.createQuery(Object[].class); Root<Pedido> root = query.from(Pedido.class); query.multiselect(root.get("pontos"), cb.avg(root.get("total")));

Join<Pedido, Cliente> cliente = root.join("cliente");

query.groupBy(cliente.get("pontos")); query.having(cb.between(cliente.get("pontos"), 1000.0, 2000.0));

Page 161: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Exemplos com subqueries•Obtenha os empregados que são casados com outros empregados:

CriteriaBuilder cb = em.getCriteriaBuilder(); CriteriaQuery<Empregado> query = cb.createQuery(Empregado.class); Root<Empregado> root = query.from(Empregado.class); Subquery<Empregado> subquery = query.subquery(Empregado.class); Root<Empregado> conjuge = subquery.from(Empregado.class); subquery.where(cb.equal(conjuge.get("conjuge "), root.get("conjuge "))); subquery.select(conjuge); query.where(cb.exists(subquery)); query.select(root).distinct(true);

Page 162: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Exemplos com subqueries (All/Any)•Retorne apenas os produtos cujo preço seja maior que o valor incluído

em todos os orçamentos:CriteriaBuilder cb = em.getCriteriaBuilder(); CriteriaQuery<Produto> query = cb.createQuery(Produto.class); Root<Produto> root = query.from(Produto.class); Subquery<Empregado> subquery = query.subquery(Empregado.class); Root<Orcamento> orcamento = subquery.from(Orcamento.class); subquery.where(cb.equal(orcamento.get("item ").get("codigo"), root.get("codigo"))); subquery.select(orcamento.get("item").get("preco")); query.where(cb.greaterThan(root.get("preco"), cb.all(subquery))); query.select(root);

Page 163: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Select com DataStransferObject

•O query usando select com construtor mostrado na seção anterior com JPQL pode ser construído com Criteria da forma abaixo:

CriteriaBuilder cb = em.getCriteriaBuilder(); CriteriaQuery<Lugares> query = cb.createQuery(DataTransferObject.class); Root<Filme> root = query.from(Filme.class); Join<Filme, Diretor> diretor = root.join("etapas"); query.where(cb.like(root.get("nome"), "%Allen")); query.select(cb.construct(Lugares.class, etapa.get("origem").get("nome"), etapa.get("destino").get("nome")) );

Page 164: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Typesafe query•É bem mais fácil encontrar erros em queries Criteria, comparados a JPQL, porque

o compilador ajuda na tarefa e detecta queries incorretos.

•Mas erros de digitação ainda podem acontecer já que a leitura dos campos das entidades feita através de um get() recebe um String.

•Por exemplo, a linha abaixo para ler o campo “preco” não contém erros de compilação:

Predicate condicao = qb.lt(raiz.get("prco"), 50.0);

•Mas se o string estiver errado, o query está incorreto: existem erros de sintaxe em queries Criteria que também não são capturados em tempo de compilação!

Page 165: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Typesafe query•A solução é o o typesafe query:

•O nome do atributo foi informado através de código Java, usando um atributo estático e público da classe Produto_.

•Produto_.class é um metamodelo estático (static metamodel). •Usando atributos através do metamodelo torna os queries typesafe

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);

Page 166: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Geração de metamodels•Metamodelos precisam ser geradas. IDEs que suportam JPA 2 têm

ferramentas para gerá-los. Projetos Maven com EclipseLink podem fazer a geração em uma das fases do POM.xml com um plug-in:

•O plugin precisa ser configurado e usará as classes declaradas no persistence.xml para gerar metamodelos durante a fase de geração de código do build (veja a documentação para mais detalhes)

<dependency> <groupId>org.eclipse.persistence</groupId> <artifactId>org.eclipse.persistence.jpa.modelgen.processor</artifactId> <version>2.5.0</version> </dependency>

Page 167: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Exercícios•17. Implemente um dos queries do exercício 13 usando Criteria

•18. Implemente um dos queries do exercício 14 usando Criteria

•19. Implemente um dos queries do exercício 15 usando Criteria

•20. Implemente um dos queries do exercício 16 usando Criteria

•21. Implemente um bean que realize uma pesquisa dinâmica em Livros, filtrando por autor, isbn e título. Crie um mecanismo que permita construir um query dinâmico:

•Se nenhum campo estiver preenchido, a busca será feita sem filtros

•Se algum campo estiver preenchido, ele deve ser acrescentado na cláusula where da pesquisa

Page 168: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7 JPA

java persistence api9

transações, cache e locks

Page 169: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Transações em JPA•Podem ser

•Distribuídas com 2-phase commit (JTA)

•Configuradas como um recurso local (RESOURCE_LOCAL)

•Apenas transações JTA são gerenciadas pelo container (CMT - Container-Managed Transactions) para configurar suporte transacional de forma transparente e declarativa

•Transações JTA também podem ser controladas programaticamente (BMT - Bean-Managed Transactions) através da API da classe UserTransaction, que pode ser injetada como resource em componentes Java EE

Page 170: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Resource Local•Usada em ambientes Java SE ou onde não há suporte a transações distribuídas •getTransaction() obtém contexto transacional para operações de persistência •Transações são delimitadas pela chamada dos métodos begin() e commit()/rollback():

public class AlunoDAO { private EntityManagerFactory emf; AlunoDAO() { emf = Persistence.createEntityManagerFactory("escola-PU");}

public void addAluno(Aluno aluno) { EntityManager em = emf.getEntityManager(); try em.getTransaction().begin(); em.persist(aluno); em.getTransaction().commit(); } catch(Exception e) { em.rollback(); } finally { em.close(); }

} }

<persistence-unit name="escola-PU" transaction-type="RESOURCE_LOCAL">

Em persistence.xml:

Page 171: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

JTA (Java Transaction API)•Disponível em servidores Java EE e suporta transações distribuídas (2-phase) •Pode ser obtida e injetada como um @Resource em WebServlets, EJBs, e outros

componentes que rodam no container Java EE •Em ambientes CDI também pode ser injetada com @Injectpublic class AlunoDAOBean { @PersistenceContext(unitName="escola-PU") private EntityManager; @Resource UserTransaction ut;

public void addAluno(Aluno aluno) { try ut.begin(); em.persist(aluno); ut.commit(); } catch(Exception e) { ut.rollback(); } finally { em.close(); }

} }

<persistence-unit name="escola-PU" transaction-type="JTA">

Em persistence.xml:

Page 172: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

CMT (JTA) em EJB•Em EJB transações gerenciadas pelo container (CMT), JTA é o

comportamento default e é transparente

•Todos os métodos de um SessionBean são automaticamente incluídos em um contexto transacional@Stateless public class AlunoSessionBean {

@PersistenceContext EntityManager em;

public void addAluno(Aluno aluno) { em.persist(aluno); } }

<persistence-unit name="escola-PU" transaction-type="JTA">

Em persistence.xml:

Page 173: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

CMT (JTA) em CDI

•Em CDI o mesmo comportamento pode ser obtido nos métodos declarados como @Transactional

@Model public class AlunoSessionBean {

@Inject EntityManager em;

@Transactional public void addAluno(Aluno aluno) { em.persist(aluno); } } <persistence-unit

name="escola-PU" transaction-type="JTA">

Em persistence.xml:

Page 174: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Cache•O JPA possui dois níveis de cache

•O Contexto de Persistência, controlado pelo EntityManager (L1)

•Cache L2: Mecanismo compartilhado.

•Cache é um recurso de performance que deve ser usado com cuidado

•Há risco de resultar em inconsistência de dados

•Pode inclusive introduzir bugs

•O custo-benefício com os ganhos de performance poderá compensar o esforço extra de gerenciar o cache

Page 175: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Cache L1 (contexto de persistência) e L2

Page 176: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Cache L1: Entity Manager•O EntityManager normalmente está vinculado a uma transação, que dura no

mínimo o tempo de uma operação.

• Durante essa operação o objeto é sincronizado com o banco e copiado para o contexto de persistência.

• Enquanto durar o contexto de persistência, o estado dos objetos é mantido (não é necessário fazer novas consultas ao banco de dados para atualizar o estado)

•Nos ambientes CMT (Container-Managed Transactions), a duração do contexto de persistência é a mesma do contexto transacional

• O padrão recomendado para ambientes BMT (Bean-Managed Transactions) é também abrir o contexto transacional logo após a obtenção do EntityManager, e fechar o EntityManager após cometer ou fazer rollback da transação

Page 177: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Cache L1: Entity Manager•Quando uma transação e o contexto de persistência são fechados, as entidades

entram no estado detached (desligadas) e precisam de alguma política de locking para garantir sua integridade, caso precisem ser religadas na próxima transação.

Page 178: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Cache L1: Entity Manager•Em ambientes CMT o EntityManager pode ser injetado com a opção EXTENDED

que mantém o contexto aberto entre transações. @PersistenceContext(PersistenceContextType.EXTENDED)private EntityManager entityManager;

Page 179: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Cache L2 para todos os objetos•O cache de segundo nível (L2) é compartilhado entre contextos

de persistência •É preciso habilitá-lo explicitamente usando

•Ou usando propriedades

<persistence-unit ...> <shared-cache-mode>ALL</shared-cache-mode> </persistence-unit>

<persistence-unit ...> ... <properties> ... <property name="javax.persistence.sharedCache.mode" value="ALL"/> </properties> </persistence-unit>

Page 180: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Cache L2 seletivo•Habilitar cache para todas as entidades pode não ser uma boa idéia. A

estratégia oposta é desabilitar exceto para as anotadas como @Cacheable

• Isto pode ser configurado mudando o shared-cache-mode para

•Se a maioria dos objetos deve participar do cache pode-se configurar para todas irem para o cache L2 a menos que declarem @Cacheable(false).

•Com o serviço habilitado, objetos não encontrados no contexto de persistência serão buscados no cache L2.

@Cacheable @Entity public class Produto { … }

<shared-cache-mode>ENABLE_SELECTIVE</shared-cache-mode>

<shared-cache-mode>DISABLE_SELECTIVE</shared-cache-mode>

Page 181: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

javax.persistence.Cache•API da interface Cache permite acesso ao cache L2

•Pode-se obter uma instância de Cache através do EntityManager

Cache cache = emf.getCache();

•Os principais métodos dessa classe são:

•contains(classe, entidade) – que retorna true se o objeto estiver no cache.

•evict(classe, objeto) – remove o objeto do cache

•evictAll() – esvazia o cache

Page 182: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

javax.persistence.Cache•Este código checa se um objeto está no cache, e remove do cache se estiver boolean isCached =;if ( cache.contains(Produto.class, Long.valueOf(123)) ) { cache.evict(Produto.class, Long.valueOf(123)); }

•Pode-se também remover do cache todas as entidades de uma classe:

cache.evict(MyEntity.class);  

•Ou ainda esvaziar o cache inteiro: cache.evictAll();

•Objetos cacheáveis são automaticamente incluídos ao cache no commit()

Page 183: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Retrieve Mode•O modo de gravação do cache pode ser configurada para um EntityManager

usando a propriedade javax.persistence.cache.retrieveMode

•Pode também ser configurada para um query específico usando setHint(): Query query = em.createQuery("Select p from Produto p"); query.setHint("javax.persistence.cache.retrieveMode", CacheStoreMode.BYPASS);

•As constantes do enum CacheStoreMode são:

•USE (usa o objeto do cache) •BYPASS (ignora o objeto do cache) •REFRESH (atualiza o objeto do cache)

Page 184: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Quando usar o cache L2•Entre as vantagens de usar este cache está evitar acessar o banco para

entidades que já foram carregadas

•As melhores candidatas são entidades que

•São acessadas com frequência e nunca ou raramente são modificadas

•Não sejam inválidas se estiverem desatualizadas

•Como desvantagens estão o consumo de memória maior e objetos que podem ficar obsoletos (caso sejam atualizados no banco)

•Este cache não deve ser usado para objetos atualizados com frequência

Page 185: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Locks

•Locks travam um objeto para evitar alterações concorrentes quando os dados são usados simultaneamente por aplicações diferentes

•Há duas estratégias:

•Lock otimista (default): não impede o acesso ao objeto, mas incrementa um número de versão das alterações. Se o número mudar antes do commit, rejeita as alterações.

•Lock pessimista: impede acesso a um objeto, geralmente por um determinado tempo (transação ou operação) e por um determinado modo (leitura, gravação)

Page 186: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Locks otimistas•Requerem configuração* através de mapeamento de um campo @Version

modificado apenas pelo provedor de persistência •É preciso definir um atributo numérico do tipo Long/long, Integer/int, Short/

short) ou Timestamp e anotá-lo com @Version ou configurar via orm.xml:

@Entity public class Produto { @Version long version; }

•O provedor incrementa o campo a cada commit realizado com sucesso

•Se outra transação tentar alterar a entidade e o provedor detectar que a versão foi alterada desde a última leitura, lança OptimisticLockException

* alguns provedores configuram campos de versão automaticamente

Page 187: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Lock Modes•Modos de travamento são especificados na enumeração LockModeType e

usados em métodos de EntityManager

• OPTIMISTIC: obtém trava otimista (entidades com @Version). Mesmo que READ

• OPTIMISTIC_FORCE_INCREMENT: obtém trava otimista e força incremento da versão. Mesmo que WRITE

• PESSIMISTIC_READ: permite leitura simultânea por outras transações, mas não permite modificações

• PESSIMISTIC_WRITE: não permite acesso por outras transações

• PESSIMISTIC_FORCE_INCREMENT: não permite acesso por outras transações e incrementa a versão (se houver)

• NONE: não realiza travamento

Page 188: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Aplicando LockModes•EntityManager.lock(): aplica lock em toda a transação:

em.lock(produto, LockModeType.PESSIMISTIC_WRITE);

• Os efeitos de lock() terminam com o commit(), portanto a chamada requer uma transação ativa (será lançada uma exceção se não houver)

•Query.setLockMode(): aplica um lock durante a execução de um Query: query.setLockMode(LockModeType.PESSIMISTIC_FORCE_INCREMENT)

• Em um @NamedQuery pode-se configurar através de atributo lockMode: @NamedQuery(name="...", query="...", lockMode="PESSIMISTIC_READ")

•Pode-se aplicar um lock durante uma operação find() ou refresh()Produto p = em.find(Produto.class, pk, LockModeType.OPTIMISTIC);

em.refresh(p, LockModeType.OPTIMISTIC_FORCE_INCREMENT);

Page 189: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Locks pessimistas•Se for necessário evitar que uma colisão ocorra antes do commit da transação

é preciso usar uma trava pessimista

•Obtém exclusividade de gravação ou acesso a uma entidade durante o período que um cliente estiver usando

•Podem ser aplicadas em transações (método lock()) ou operações (find(), refresh() e queries configurados com lockMode)

•Principais LockModeTypes: PESSIMISTIC_READ (leitura compartilhada) e PESSIMISTIC_WRITE (acesso exclusivo)

•Deve-se definir um timeout (importante para evitar deadlock). Um timeout default (em milissegundos) pode ser definido em persistence.xml

<properties> <property name="javax.persistence.lock.timeout" value="1000"/></properties>

Page 190: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Lock timeout•Se o timeout expirar e a trava não puder ser fornecida será lançada uma

LockTimeoutException

• Timeouts podem ser especificados programaticamente via EntityManager ou até mesmo para um query específico, sobrepondo o timeout default

•O trecho de código abaixo altera o timeout default e usa locks pessimistas apenas durante as operações find() e refresh():

Map<String,Object> props = new HashMap(); props.put("javax.persistence.lock.timeout", 2000);   Produto produto = em.find(Produto.class, 1, LockModeType.PESSIMISTIC_WRITE, props); em.refresh(produto, LockModeType.PESSIMISTIC_WRITE, props);

Page 191: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Problema dos N+1 selects•O problema conhecido como dos “N+1 selects” ocorre quando vários

queries contendo um único elemento são realizados quando um único query poderia ter sido feito para receber vários elementos

•Em ORMs esse tipo de situação pode ocorrer devido à forma como os queries são gerados

•Se um objeto é recuperado, selects são feitos para cada um dos seus relacionamentos. Com muitos objetos, o mesmo processo poderia gerar vários queries desnecessários

SELECT P.* FROM PEDIDO E WHERE P.TOTAL > 1000 ... N selects para ADDRESSSELECT I.* FROM ITEM I WHERE I.ITEM_ID = 123 SELECT I.* FROM ITEM I WHERE I.ITEM_ID = 456 SELECT I.* FROM ITEM I WHERE I.ITEM_ID = 789 ...

Page 192: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Join e Batch Fetching•A forma de resolver o problema dos “N+1 selects” em JPA é através de

join fetching (eager queries com "left join fetch")

•O query irá carrega todos os elementos da coleção para o contexto

•Provedores como EclipseLink e Hibernate oferecem alternativas proprietárias que inclui operações em lote

•No EclipseLink pode-se configurar consultas em lote usando @BatchFetch nos relacionamentos

@BatchFetch(type=BatchFetchType.EXISTS)

•No Hibernate há uma anotação similar (para classes e relacionamentos), que especifica o tamanho do lote)

@BatchSize(size=100)

Page 193: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Exercícios

•22. Configure um cache L2 para a entidade Livro.

•23. Escreva uma aplicação que tente incrementar 100 vezes o preço de um Produto (em um loop). Inicie com o valor 100.

•a) Rode a aplicação com um cliente

•b) Rode a aplicação com dois clientes

•c) Configure um controle transacional para evitar que um cliente veja um valor que não seja 100, 200 ou 300.

Page 194: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Exercícios de revisão

•Faça os exercícios 4, 5, 8 e 9 da aplicação Biblioteca* (usam as classes da Hierarquia 5)

•4) Aplicação Web usando mapeamento básico JPA

•5) Relacionamentos em JPA

•8) Mapeamento de herança em JPA

•9) JPA queries (JPQL e Criteria)

*Exercicios: http://www.argonavis.com.br/download/exercicios_javaee.html

Page 195: JPA java persistence api - argonavis.com.br · Introdução 2. Configuração do ... •Um provedor de persistência JPA (ex: Hibernate, ... •Pode ser necessário adaptar os exercícios

J A

V A

E E

7

Referências•[1] Java Persistence 2.1 Expert Group. JSR 338: JavaTM Persistence API, Version

2.1. Oracle. 2013. http://download.oracle.com/otndocs/jcp/persistence-2_1-fr-eval-spec/index.html

•[2] Christian Bauer et al. Java Persistence with Hibernate, Second Edition. Manning, 2015.

•[3] Eric Jendrock et al. The Java EE 7 Tutorial. Oracle. 2014. https://docs.oracle.com/javaee/7/JEETT.pdf

•[4] Linda deMichiel and Bill Shannon. JSR 342. The Java Enterprise Edition Specification. Version 7. Oracle, 2013. http://download.oracle.com/otn-pub/jcp/java_ee-7-fr-spec/JavaEE_Platform_Spec.pdf

•[5] Arun Gupta. Java EE 7 Essentials. O’Reilly and Associates. 2014.