Nesse post vamos praticar tudo que sabemos sobre o JPA (Java Persistence API) com exercícios de fixação (teóricos e práticos) é uma excelente ferramenta para ajudar você a inserir dados no seu banco. Esse post tem como objetivo principal testar seus conhecimentos sobre essa ferramenta e permitir que você implemente, modifique, melhore, exemplos de código didáticos que utilizam o JPA.
Se você caiu nesse post e não lembra exatamente o que é o JPA, como ele funciona e pra que ele serve, vou ajudar refrescar sua memória.
Os bancos de dados relacionais são baseados em tabelas (entidades) e relacionamentos, por outro lado, a linguagem Java é Orientada a Objetos. Nesse contexto, podemos perceber que existe uma clara incompatibilidade entre o paradigma orientado à objetos e as tabelas de um banco, portanto, para manipular um banco de dados usando uma linguagem de programação é necessário um esforço adicional do programador.
O JPA faz parte de um conjunto de tecnologias que surgiu dessa necessidade de manipular dados no banco de dados por meio de código e visa facilitar esse trabalho fornecendo ferramentas eficientes para mapear as tabelas em objetos. O termo mapeamento objeto-relacional (ORM) surgiu para denominar ferramentas que fazem esse tipo de “ponte” entre o banco de dados e o código.
No Java existem várias implementações de ORMs como o eclipselink, hibernate, etc. No entanto, cada implementação seguiu suas próprias regras no inicio, causando um problema grave de compatibilidade entre os mapeadores. A solução para esse problema foi a criação de uma API genérica que definia regras mais rigidas de como os softwares ORM deveriam funcionar. Assim, nasceu o JPA – uma interface genérica que auxilia a utilização de ORMs no Java.
Quer relembrar os conceitos? veja um post que fizemos sobre esse assunto:
A primeira sequência de exercícios será puramente teórico, nesse questionário temos 10 questões sobre o JPA e detalhes de como utilizar essa ferramenta no Java. Leia com atenção as questões e ao final do questionário disponibilizamos as respostas.
Exercício 1 – Qual é a diferença entre JPA e Hibernate?
Exercício 2 – As anotações @Entity, @Id e @GeneratedValue servem, respectivamente, para:
Exercício 03 – Dado o trecho de código abaixo, diga: Qual é o estado da entidade Aluno neste momento?
Aluno aluno = new Aluno();
aluno.setId(3);
// Conta com Id 3 já foi persistida anteriormente.
aluno.setNome("João Pedro");
aluno.setEndereco("Rua ….");
Exercício 04 – Veja o código abaixo:
EntityManager manager = new JPAUtil().getEntityManager();
Conta conta = new Conta();
conta.setId(1);
Query query = manager.createQuery("select m from Movimentacao m where m.conta=:pConta" + " and m.tipoMovimentacao=:pTipo");
query.setParameter("pConta", conta);
query.setParameter("pTipo", TipoMovimentacao.ENTRADA);
List<Movimentacao> movimentacoes = query.getResultList();
manager.close()
Assumindo que tudo é compilado e executado corretamente, qual das afirmações abaixo é verdadeira?
Exercício 05 – Apesar de termos utilizado anotações para realizarmos o mapeamento entre classes e tabelas, algumas configurações se fazem necessárias no persistence.xml. Uma configuração muito importante é a “unidade de persistência”, qual é a finalidade dessa configuração?
Exercício 06 – Dentro do ciclo de vida de um objeto na JPA, qual estado garante que todas as modificações feitas no objeto serão sincronizadas com o banco de dados?
Exercício 07 – Observe o relacionamento bidirecional abaixo:
@Entity
public class Aluno {
@OneToOne
private Perfil perfil;
}
@Entity
public class Perfil {
@OneToOne(mappedBy="perfil")
private Aluno aluno;
}
Qual é o lado forte?
Exercício 08 – Como se chama o método da interface javax.persistence.Query que devolve um único valor?
Exercício 09 – Qual das afirmações abaixo NÃO é verdadeira?
Exercício 10 – O método find() e o getReference() da interface EntityManager permitem que:
Quer ver um exemplo sobre como implementar um aplicação usando JPA? Veja esse exemplo no github.
Agora que você já passou pelos posts teóricos vamos colocar a mão na massa com alguns exercícios práticos sobre JPA para treinar seus conhecimentos. Esses exercícios de JPA não possuem alta complexidade e têm a finalidade exclusivamente educacional, as resoluções estão presentes também no nosso github.
A programação java é um assunto bastante extenso, se você quer saber mais e ver mais exercícios clique aqui e acesse os exercícios.
Agora que já fizemos vários exercícios teóricos sobre JPA, vamos continuar nos aprofundando no assunto, mas agora vamos colocar a mão no código e tentar implementar algo um pouco diferente.
Veja as regras do exercício:
Neste exercício você irá criar um conjunto de entidades com um relacionamento muito simples. As entidades serão: Pessoa (contendo: id, login, senha, email, nome); Compra (contendo: id, valor, data, observacao).
Essa lógica representa o relacionamento que um cliente tem em qualquer loja onde ele pode realizar uma compra. Um cliente pode ter várias compras, no entanto, uma compra pode pertencer a apenas um cliente.
Para completar este exercício você deverá utilizar o JPA 2.x como especificação. Como implementação do JPA você pode escolher entre o Hibernate e o eclipselink. As bases de dados ficam a sua escolha, porém recomendamos o Postgres e o MySQL.
@Entity
@Table(name = "compra")
public class Compra implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Basic(optional = false)
@Column(name = "id")
private Integer id;
@Column(name = "valor")
private String valor;
@Column(name = "data")
@Temporal(TemporalType.DATE)
private Date data;
@Column(name = "observacao")
private String observacao;
@Column(name = "recebido")
private Boolean recebido;
{{getters and setters}}
}
public class CompraJpaController{
public void create(){}
public void edit(){}
public void destroy(){}
public void findAll(){}
public void findById(){}
}
public class EmProvider {
private static final String DB_PU = "AplicacaoAulaPU";
public static final boolean DEBUG = true;
private static final EmProvider singleton = new EmProvider();
private EntityManagerFactory emf;
private EmProvider() {}
public static EmProvider getInstance() {
return singleton;
}
public EntityManagerFactory getEntityManagerFactory() {
if(emf == null) {
emf = Persistence.createEntityManagerFactory(DB_PU);
}
if(DEBUG) {
System.out.println("factory created on: " + new Date());
}
return emf;
}
public void closeEmf() {
if(emf.isOpen() || emf != null) {
emf.close();
}
emf = null;
if(DEBUG) {
System.out.println("EMF closed at: " + new Date());
}
}
}
public class TestandoPersistencia {
public static void main(String[] args) {
Pessoa p = new Pessoa();
Date d = new Date();
p.setNome("Isabela");
p.setLoggin("isabela tal");
p.setEmail("icastilhog@gmail.com");
p.setSenha("teste");
List<Compra> compras = new ArrayList<>();
Compra c1 = new Compra();
c1.setData(d);
c1.setObservacao("compra impressora");
c1.setRecebido(true);
c1.setValor("890");
CompraJpaController c =
new CompraJpaController(EmProvider.getInstance().getEntityManagerFactory());
c.create(c1);
compras.add(c1);
p.setCompraList(compras);
PessoaJpaController j = new PessoaJpaController(EmProvider.getInstance().getEntityManagerFactory());
j.create(p);
System.out.println(j.findPessoaEntities());
}
}
Faça download do exercício resolvido no github:
No primeiro exercício de JPA um dos grandes problemas a serem resolvidos é a questão da eficiência ao realizar as buscas no banco de dados. É muito comum que ao programar utilizando esta API o programador tenha q se preocupar com cada comando executado, pois estes comandos resultam em operações que podem se tornar custosas em uma aplicação que recebe muitas requisições.
O JPA possui uma opção muito utilizada que é o FechType. Essa opção controla quais entidades serão carregadas ao realizar uma operação de SELECT na base de dados. Considere o seguinte diagrama de entidade-relacionamento:
Neste caso você pode observar que existem duas entidades e uma possui uma relação OneToMany com a outra (pessoa-compra).
Pense um pouco…
Ao realizar uma busca por compras, como o resultado é expressado?
SELECT * FROM compra;
output:
Se você conhece um pouco de SQL sabe que a coluna “pessoa_idpessoa” é a coluna que realiza a conexão entre as tabelas. Os números ali inseridos são as chaves primárias da tabela “pessoa”.
A partir deste ponto, toda a teoria dos InnerJoins, selects aninhados são aplicadas para gerar resultados interessantes para a aplicação e mostrar ao usuário.
Utilizando o JPA é possível buscar todas as pessoas e dentro delas acessar uma lista de compras feitas por elas. O problema de fazer isso é que muitas vezes não queremos que esses dados sejam carregados, assim precisamos controlar se esses relacionamentos serão mesmo carregados ao realizar um select. Para que isso seja realizado podemos utilizar o FechType.
Para resolver esses exercícios de JPA precisamos compreender que existem 2 tipos de “fetch”: LAZY loading, EAGER loading. No LAZY loading NÃO são carregados os relacionamentos dentro da busca principal. Já no EAGER loading, tudo será carregado.
Veja como utilizar o Lazy Loading:
import javax.persistence.FetchType;
@OneToOne(fetch=FetchType.LAZY)
@JoinColumn(name="user_profile_id")
private Profile getUserProfile() {
return userProfile;
}
Para utilizar o Eager Loading basta substituir a linha para:
@OneToOne(fetch=FetchType.EAGER)
Ao realizar uma operação de busca utilizando o EAGER loading , por exemplo:
controlPessoa.findEntities()
O resultado será algo como:
Pessoa{idPessoa=1
, nome=vinicius dos santos
, login=vinicius
, email=vinistos@gmail.com
, senha=1234
, compraList=[model.Compra[ idCompra=1 ], model.Compra[ idCompra=4 ]]}
Pessoa{idPessoa=2
, nome=Mario da silva
, login=mario
, email=mario@gmail.com
, senha=1234
, compraList=[model.Compra[ idCompra=3 ]]}
Pessoa{idPessoa=3
, nome=Gabriel garcia
, login=gabriel
, email=gabriel@gmail.com
, senha=1234
, compraList=[model.Compra[ idCompra=2 ]]}
Pessoa{idPessoa=4
, nome=Isabela Ribeiro
, login=isabela
, email=isabela@gmail.com
, senha=1234
, compraList=[]}
Ao realizar a mesma busca utilizando o LAZY loading, o resultado será:
Pessoa{idPessoa=1
, nome=vinicius dos santos
, login=vinicius
, email=vinistos@gmail.com
, senha=1234
, compraList={IndirectList: not instantiated}}
Pessoa{idPessoa=2
, nome=Mario da silva
, login=mario
, email=mario@gmail.com
, senha=1234
, compraList={IndirectList: not instantiated}}
Pessoa{idPessoa=3
, nome=Gabriel garcia
, login=gabriel
, email=gabriel@gmail.com
, senha=1234
, compraList={IndirectList: not instantiated}}
Pessoa{idPessoa=4
, nome=Isabela Ribeiro
, login=isabela
, email=isabela@gmail.com
, senha=1234
, compraList={IndirectList: not instantiated}}
O resultado de indirect list not instantiated representa a lista não carregada devido ao lazy loading. Como exercício você deverá implementar as classes definidas na Figura 1 e testar a utilização do LAZY e do EAGER loading.
Acesse a resposta aqui:
E ai, gostou dos exercícios JPA? Tem sugestões? deixa nos comentários 🙂
Esse post foi modificado em 26 de dezembro de 2021 09:50
This website uses cookies.