Exercícios

Exercícios sobre Java Persistence API (JPA)

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.

Relembrando…

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:


Questionário

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?

  • a) Hibernate é especificação e JPA a implementação
  • b) Ambos implementações de um ORM
  • c) Ambos especificações de um ORM
  • d) JPA é especificação e Hibernate a implementação  

Exercício 2 – As anotações @Entity, @Id e @GeneratedValue servem, respectivamente, para:

  • a) Associar uma classe a uma tabela, indicar a chave primária no banco e permitir que o banco gere automaticamente a chave, de maneira obrigatória.
  • b) Associar uma classe a uma tabela, indicar chave primária no banco e permitir o desenvolvedor se encarregue pela geração da chave.
  • c) Associar uma classe a uma tabela, indicar chave primária no banco e permitir que o banco gere automaticamente a chave, de maneira opcional.  

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 ….");
  • a) Managed (Gerenciado)
  • b) Transient (Transiente)
  • c) New (Novo)
  • d) Removed (Removido)
  • e) Detached (Desatachado)  

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?

  • a) A query busca todas as movimentações.
  • b) A query busca todas as movimentações de entrada da conta 1.
  • c) A query busca todas as movimentações sendo de entrada ou da conta 1.
  • d) A query busca a primeira movimentação de entrada.  

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?  

  • a) Guardar as mensagens dos erros de validação
  • b) Definir a chave primeiro como auto increment
  • c) Guardar configurações específicas para um banco de dados
  • d) Configurar o mapeamento de relacionamentos  

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?

  • a) Removed (Removido)
  • b) Transient (Transiente)
  • c) New (Novo)
  • d) Detached (Desatachado)
  • e) Managed (Gerenciado)  

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?

  • a) O atributo perfil na classe Aluno.
  • b) Não há lado forte.
  • c) O atributo aluno na classe Perfil.  

Exercício 08 – Como se chama o método da interface javax.persistence.Query que devolve um único valor?

  • a)  getSingleResult()
  • b)  getUniqueResult()
  • c)   value()
  • d)  uniqueValue()
  • e) getOneResult()  

Exercício 09 – Qual das afirmações abaixo NÃO é verdadeira?

  • a) Relacionamentos LAZY, ao ser inicializados, precisam do EntityManager aberto.
  • b) Relacionamentos para-muitos (*ToMany) são LAZY por padrão.
  • c)  Relacionamentos LAZY não podem ser carregados antecipadamente, nem pelo JPQL.
  • d) Relacionamentos LAZY serão inicializados sob demanda (ao acessar).  

Exercício 10 – O método find() e o getReference() da interface EntityManager permitem que:

  • a) Encontre a relação entre o id passado e os objetos Transient da sessão com o banco.
  • b) Recuperemos o endereço de memória de um objeto através do seu id.
  • c) Recuperemos uma instância de uma entidade no banco de dados através do seu id.
  • d) Busquemos entre os objetos em memória, quais já foram persistidos.      

Quer ver um exemplo sobre como implementar um aplicação usando JPA? Veja esse exemplo no github.

Respostas do questionário

  • 1 – d
  • 2 – c
  • 3 – e
  • 4 – b
  • 5 – c
  • 6 – e
  • 7 – a
  • 8 – a
  • 9 – c
  • 10 – c

Exercícios práticos

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.

Exercicio 1 – Construindo uma aplicação com JPA

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ê deverá ler todo o enunciado e ao final entregar o código Java que supre todas os requisitos descrito.
  • Você pode utilizar IDEs de programação (NetBeans, eclipse, etc…), no entanto, é fortemente recomendado que você compreenda TODOS os códigos gerados pela IDE. O risco de se acomodar é seu.
  • Recomendamos que você utilize no mínimo 2 bases de dados diferentes para testar o funcionamento do JPA (MySQL e Postgres são as mais comuns).

Compreendendo a lógica que deve ser implementada.

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.

Quais bibliotecas você pode (deve) utilizar

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.     

Sugestão de passos para completar o exercício

  • Passo 1 – Faça a instalação das IDE’s, Banco de dados e configure o Java.
  • Passo 2 – Crie um projeto em sua IDE de preferência
  • Passo 3 – Adicione as bibliotecas necessárias ( JPA, Hibernate ou eclipselink, Driver do banco de dados)
  • Passo 4 – Crie as classes de entidade
 @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}}
  
 }
  • Passo 5 – Crie os controladores contendo os métodos:
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());
         }
     }
 }
  
  • Passo 6 – Crie uma classe de teste contendo um simples método Main();
  • Passo 7 –  Dentro da classe Main(), faça:
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());
     }
 }
  • Passo 8 – Teste!

Faça download do exercício resolvido no github:  

Exercicio 2 – Configurando o Fetch Type do JPA

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.

Onde o JPA ajuda?

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.   

O funcionamento do FetchType

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)  

Exemplo de output

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.