32
Java Persistence API JPA Marco Reis Software Architect http:// marcoreis.net

Aula JPA

Embed Size (px)

DESCRIPTION

Apostila da aula de JPA, cobrindo os seguintes tópicos: - jpa - hibernate - many-to-one - mapeamento objeto relacional - entity manager - junit - namedquery - query

Citation preview

Page 1: Aula JPA

Java Persistence APIJPA

Marco ReisSoftware Architecthttp://marcoreis.net

Page 2: Aula JPA

Agenda• Mapeamento objeto-relacional.

• JPA x Hibernate.

• Criação das tabelas.

• Executar comandos de inclusão, alteração, exclusão e consulta.

Page 3: Aula JPA

Código-fonte• O projeto de exemplo com o código-fonte está disponível

em:

– https://github.com/masreis/e-commerce

Page 4: Aula JPA

Mapeamento objeto-relacional• JPA é um modelo de persistência baseado

em POJO.• Java é utilizada em ambientes corporativos,

com grandes bancos de dados.• Agiliza o desenvolvimento, já que não

precisamos escrever comandos SQL.• Fácil de mudar de banco de dados, caso

necessário.

Page 5: Aula JPA

JPA x Hibernate

• JPA é a especificação da Oracle para mapenamento objeto-relacional.

• Hibernate apresentava uma maneira mais elegante de trabalhar com a persistência do que o J2EE.

Page 6: Aula JPA

Arquivo de configuração• O arquivo persistence.xml contém os parâmetros de

configuração para acesso ao banco de dados e deve estar no diretório META-INF.

• Persistence unit name (e-commerce-pu): indica os parâmetros de acesso à base de dados.

• transaction-type: RESOURCE_LOCAL para servidor web e JTA para servidor de aplicação.

• Provider: qualquer implementação do JPA. Pode ser o Hibernate, OpenJPA ou EclipseLink, que é o produto oficial da Oracle.

Page 7: Aula JPA

persistence.xml<?xml version="1.0" encoding="UTF-8"?><persistence xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://java.sun.com/xml/ns/persistence

http://java.sun.com/xml/ns/persistence/persistence_2_0.xsd" version="2.0" xmlns="http://java.sun.com/xml/ns/persistence">

<persistence-unit name="e-commerce-pu" transaction-type="RESOURCE_LOCAL"> <provider>org.hibernate.ejb.HibernatePersistence</provider> <properties> <property name="hibernate.dialect" value="org.hibernate.dialect.HSQLDialect" /> <property name="hibernate.hbm2ddl.auto" value="update" /> <property name="hibernate.show_sql" value="true" /> <property name="hibernate.format_sql" value="true" />

<property name="javax.persistence.jdbc.driver" value="org.hsqldb.jdbcDriver" /> <property name="javax.persistence.jdbc.url" value="jdbc:hsqldb:file:e-commerce/db;shutdown=true;hsqldb.write_delay=false;" /> <property name="javax.persistence.jdbc.user" value="SA" /> <property name="javax.persistence.jdbc.password" value="" /> </properties> </persistence-unit></persistence>

Page 8: Aula JPA

Entidades• Com JPA podemos mapear as classes de entidade

diretamente para o banco de dados.

• Vamos considerar as seguintes classes:

– Usuario

– Cliente

– Produto

– Categoria

• As anotações do JPA estão no pacote javax.persistence.

Page 9: Aula JPA

Classe Usuariopackage net.marcoreis.ecommerce.entidades;

import java.util.Date;

public class Usuario { private Long id; private String email; private String nome; private Date ultimoLogin;

{sets e gets}

}

Page 10: Aula JPA

Classe Usuario persistente@Entitypublic class Usuario { @Id @GeneratedValue private Long id; private String email; private String nome; private Date ultimoLogin;}

• Para persistir uma classe usando JPA é necessário adicionar ao menos as seguintes anotações:

– @Entity: a classe será armazenada em uma tabela.

– @Id: campo da chave-primária.

– @GeneratedValue: a chave-primária será gerada automaticamente.

Page 11: Aula JPA

Teste unitário com JUnit

<dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.11</version></dependency>

• As funcionalidades serão testadas com o Junit.

• Cada funcionalidade será validada com um teste unitário.

• As classes de teste vão ficar no pacote:

– net.marcoreis.ecommerce.teste

• As classes do JUnit estão em org.junit.

• Para rodar um teste, vá no menu Run-Run as-JUnit test.

• Adicione a dependência do Maven no pom.xml.

• Utilize o @Before e @After para inicializar e finalizar variáveis. Quando o teste envolver inclusão, alteração ou exclusão de registros, é obrigatório o begin() e commit().

Page 12: Aula JPA

Inserindo registrospublic class TesteInsereUsuario {

private EntityManager em;

@Before public void inicializar() { em = JPAUtil.getInstance().getEntityManager(); em.getTransaction().begin(); }

@After public void finalizar() { em.getTransaction().commit(); em.close(); }

@Test public void inserirUsuario() { Usuario usuario = new Usuario(); usuario.setEmail("[email protected]"); usuario.setNome("Marco Reis"); Date data = new Date(); usuario.setUltimoLogin(data); em.persist(usuario); }}

Page 13: Aula JPA

Consulta registros gravados

@Entity@NamedQuery(name = "usuario.consultaAcessoDia", query = "from Usuario where cast(ultimoLogin as date) = :data")public class Usuario { @Id @GeneratedValue private Long id; private String email; private String nome; private Date ultimoLogin;}

• Para consultar os registros já gravados vamos usar uma Query ou uma NamedQuery.

• A NamedQuery fica na classe persistente, enquanto que a Query pode estar em qualquer outra classe do sistema.

• Os parâmetros podem usar as seguintes formas:– :nomeParametro1, :nomeParametro2.

– ?1, ?2, ?3.

Page 14: Aula JPA

NamedQuery

@Entity@NamedQuery(name = "usuario.consultaAcessoDia", query = "from Usuario where cast(ultimoLogin as date) = :data")public class Usuario { @Id @GeneratedValue private Long id; private String email; private String nome; private Date ultimoLogin;}

• Adicione uma NamedQuery em Usuario.

• O cast é necessário porque a data é armazenada em timestamp, e a consulta deve considerar somente a data, ignorando a hora/minuto/segundo.

Page 15: Aula JPA

Consulta registros gravados

public class TesteConsultaUsuarios {

private EntityManager em;

@Before public void inicializar() { em = JPAUtil.getInstance().getEntityManager(); }

@After public void finalizar() { em.close(); }

}

• Em seguida, vamos criar o teste unitário para verificar os usuários cadastrados.

Page 16: Aula JPA

Consulta registros gravados

@Test public void consultaTodosUsuarios() { String queryJPA = "from Usuario"; Query query = em.createQuery(queryJPA); List<Usuario> usuarios = query.getResultList(); for (Usuario usuario : usuarios) { System.out.println("Nome: " + usuario.getNome()); } }

• O primeiro teste unitário utiliza uma Query, retornando todos os usuários cadastrados.

Page 17: Aula JPA

Consulta registros gravados

@Test public void consultaUsuriosAcessoDia() { em = JPAUtil.getInstance().getEntityManager(); Query query = em.createNamedQuery("usuario.consultaAcessoDia"); query.setParameter("data", new Date()); List<Usuario> usuarios = query.getResultList(); for (Usuario usuario : usuarios) { System.out.println("Nome/ultimo login: " + usuario.getNome() + " - " + usuario.getUltimoLogin()); } }

• O teste unitário abaixo acessa a NamedQuery e passa um parâmetro, mostrando apenas os registros que têm a data de hoje.

Page 18: Aula JPA

Alterando registros gravados• Para os testes abaixo crie a classe TesteAlteraUsuario.

• Para alterar um registro, primeiro faça uma consulta pelo ID. Dessa forma, o objeto será gerenciado pelo EntityManager e poderá ser atualizado.

@Test public void alterarUsuario() { Long id = 2l; Usuario usuario = em.find(Usuario.class, id); Assert.assertNotNull("Usuario não cadastrado", usuario); usuario.setEmail("[email protected]"); usuario.setNome("Diego Lucas"); Date data = new Date(); usuario.setUltimoLogin(data); em.persist(usuario); }

Page 19: Aula JPA

Removendo registros gravados• Para os testes abaixo crie a classe

TesteRemoveUsuario.

• A exclusão deve ser feita após uma consulta pelo ID, seguindo a mesma ideia da alteração.

@Test public void removerUsuario() { Long id = 5l; Usuario usuario = em.find(Usuario.class, id); Assert.assertNotNull("Usuario não cadastrado", usuario); em.remove(usuario); }

Page 20: Aula JPA

Herança• Há 3 estratégias de herança no JPA:

– JOINED: uma tabela para cada entidade, não repete os campos.

– SINGLE_TABLE: apenas uma tabela para todas as classes.

– TABLE_PER_CLASS: uma tabela para cada classe, repetindo todos os campos.

Page 21: Aula JPA

Classe Cliente• Para mostrar o funcionamento da herança no JPA, crie a

classe Cliente, subclasse de Usuario.

• Não é necessário redefinir o Id, que já está na superclasse.@Entitypublic class Cliente extends Usuario { @Column(unique = true, nullable = false) private String cpfCnpj;

{sets e gets}}

Page 22: Aula JPA

Teste do Cliente• Agora, crie a classe TesteInsereCliente para testar a

nova entidade.

• Não se esqueça dos métodos de inicialização e finalização.

• A título de teste, comente a linha do cpfCnpj e veja o resultado.

@Test public void inserirCliente() { Cliente cliente = new Cliente(); cliente.setEmail("[email protected]"); cliente.setNome("Jose Carlos"); // cliente.setCpfCnpj("123456"); em.persist(cliente); Assert.assertTrue("Cliente gravado com sucesso", cliente.getId() > 0); }

Page 23: Aula JPA

Como funciona• Acompanhando o log do Hibernate podemos verificar

que foram incluídos 2 registros, um na tabela Usuario e outro na tabela Cliente.

• Isso porque a estratégia de herança selecionada foi JOINED.Hibernate: insert into Usuario (id, email, nome, ultimoLogin) values (default, ?, ?, ?)Hibernate: insert into Cliente (cpfCnpj, id) values (?, ?)

Page 24: Aula JPA

Atividade• Crie as classes de teste Categoria:

– Inclusão.

– Alteração.

– Exclusão.

– Consulta todas as categorias.

Page 25: Aula JPA

Relacionamentos• O JPA tem as seguintes multiplicidades, seguindo o

modelo relacional:

– many-to-one.

– one-to-one.

– one-to-many.

– many-to-many.

Page 26: Aula JPA

Many-to-one• O relacionamento many-to-one está presente na classe

produto.

• Segundo o modelo, cada produto deve ter uma categoria.public class Produto { @Id @GeneratedValue private Long id; @ManyToOne private Categoria categoria; private String nome; private String descricao; private String especificacaoLoja; @Lob private byte[] especificacaoFabricante; private Double preco;}

Page 27: Aula JPA

Inserindo produtos• Para inserir um produto precisamos escolher uma

categoria válida.

• O primeiro passo é pesquisar uma categoria já cadastrada.

• Em seguida podemos preencher os demais atributos e persistir a entidade.

@Test public void inserirProduto() { Long idCategoria = 12l; Categoria categoria = em.find(Categoria.class, idCategoria); Assert.assertNotNull("Categoria não cadastrada", categoria); Produto produto = new Produto(); produto.setCategoria(categoria); produto.setDescricao("Colcha para cama de solteiro 120cm x 210cm"); produto.setNome("Colcha para cama de solteiro"); produto.setPreco(150.00); em.persist(produto); }

Page 28: Aula JPA

Consultando produtos• Para os exemplos seguintes crie a classe

TesteConsultaProdutos.

• O primeiro teste, consultarTodasCategorias, segue o mesmo princípio das demais.

@Test public void consultarTodosProdutos() { System.out.println("Consultar todos os produtos"); List<Produto> produtos = em.createQuery("from Produto").getResultList(); for (Produto p : produtos) { System.out.println(p.getId() + " - " + p.getNome()); } }

Page 29: Aula JPA

Consultando produtos pela categoria• O exemplo abaixo mostra os produtos de uma categoria

específica.

• Este teste usa uma Query, mas poderia ser facilmente adaptado para utilizar NamedQuery.

@Test public void consultarProdutosPelaCategoria() { System.out.println("Consultar produtos pela categoria"); Long idCategoria = 12l; List<Produto> produtos = em .createQuery("from Produto where categoria.id = ?1") .setParameter(1, idCategoria ).getResultList(); for (Produto p : produtos) { System.out.println(p.getId() + " - " + p.getNome()); } }

Page 30: Aula JPA

Consultando quantidades• Adicione as NamedQueries abaixo em Produto e o teste

na classe TesteConsultaProdutos.

@Test public void consultarTotalProdutoPelaCategoria() { System.out.println("Consultar total de produtos pela categoria"); Query query = em.createNamedQuery("produto.consultaTotalPorCategoria"); Long idCategoria = 12l; query.setParameter("idCategoria", idCategoria); Object resultado = query.getSingleResult(); System.out.println("Total de produtos na categoria: " + resultado); }

@NamedQueries({ @NamedQuery(name = "produto.consultaTotalPorCategoria", query = "select count(p) from Produto p where categoria.id = :idCategoria"), @NamedQuery(name = "produto.consultaPorIntervaloPreco", query = "from Produto where preco >= ?1 and preco <= ?2") })

Page 31: Aula JPA

Atividades• Criar o teste unitário para a NamedQuery

'produto.consultaPorIntervaloPreco' na classe TesteConsultaProdutos.

• Criar as classes abaixo, com seus relacionamentos, atributos e testes unitários.

– Venda (id, data, cliente).

– Item (id, produto, quantidade, valorUnitario, venda).

Page 32: Aula JPA

Referência• http://docs.oracle.com/javaee/6/tutorial/