Aula 05, Programação para Web I
No encontro 4 vimos:
Hoje partimos daí.
Até aqui sabemos salvar um registro novo, com persist.
No fim, organizamos os cinco métodos num único lugar: o DAO.
find(classe, id) busca um registro específico pelo identificador. O primeiro argumento é a classe da entidade; o segundo é o valor do id.
Antes de usar o resultado, é preciso checar se ele não é null.
EntityManager em = emf.createEntityManager(); Professor professor = em.find(Professor.class, 1L); em.close(); if (professor != null) { System.out.println(professor.getNome()); }
merge(entidade) grava, no banco, as alterações feitas num objeto que já tem id preenchido, normalmente um objeto recuperado antes com find.
Sem um id já preenchido, merge não sabe qual registro alterar.
Professor professor = em.find(Professor.class, 1L); professor.setEmail("novo.email@ifrs.edu.br"); em.getTransaction().begin(); em.merge(professor); em.getTransaction().commit();
remove(entidade) apaga, do banco, a linha correspondente ao objeto passado.
Um objeto criado com new e nunca persistido não pode ser removido: o EntityManager não sabe a qual linha do banco ele corresponderia.
EntityManager em = emf.createEntityManager(); em.getTransaction().begin(); Professor professor = em.find(Professor.class, 1L); em.remove(professor); em.getTransaction().commit(); em.close();
find só serve quando já se sabe o id de quem se procura.
Para pedir "me dê todos os professores", find não serve, é preciso uma linguagem de consulta.
JPQL (Jakarta Persistence Query Language) é a linguagem de consulta do JPA.
A diferença para SQL: SQL consulta tabelas e colunas do banco. JPQL consulta entidades e atributos Java (as classes anotadas com @Entity, não as tabelas). O Hibernate traduz o JPQL escrito para o SQL de verdade, executado no banco.
hibernate.show_sql, já ligado desde o encontro 4, mostra essa tradução no console.
A consulta mais simples: pedir todos os registros de uma entidade.
"Professor", no JPQL, é o nome da entidade (a classe Java, não o nome da tabela).
EntityManager em = emf.createEntityManager(); List<Professor> professores = em .createQuery("SELECT p FROM Professor p", Professor.class) .getResultList(); em.close();
Uma consulta sem condição, como a do slide anterior, devolve todos os registros.
"Listar os alunos de uma turma específica" é uma pergunta diferente: precisa de uma condição.
O WHERE do JPQL aceita um parâmetro nomeado, preenchido com setParameter, nunca concatenando valor dentro da string da consulta.
EntityManager em = emf.createEntityManager(); List<Aluno> alunos = em .createQuery("SELECT a FROM Aluno a WHERE a.turma = :turma", Aluno.class) .setParameter("turma", turma) .getResultList(); em.close();
Vamos pensar: cinco operações, para cada uma das entidades do nosso projeto (listar, deletar, atualizar, buscar, salvar)
Quantos blocos de código, ao todo, seriam necessários para repetir essas cinco operações também para Turma e para Aluno?
Uma interface é um tipo que declara o que um conjunto de classes deve saber fazer, sem dizer como cada uma faz.
Ela só lista assinaturas de método (nome, parâmetros, retorno), sem corpo. Uma classe usa a palavra implements para assumir esse compromisso, e é ela quem escreve o corpo de cada método.
Toda classe Notificavel sabe notificar(mensagem): o que muda é como cada uma faz isso.
public interface Notificavel { void notificar(String mensagem); } public class NotificadorEmail implements Notificavel { public void notificar(String mensagem) { System.out.println("E-mail: " + mensagem); } } public class NotificadorSms implements Notificavel { public void notificar(String mensagem) { System.out.println("SMS: " + mensagem); } }
Quem chama notificar(mensagem) depende só da assinatura declarada na interface, não de qual classe a implementa, nem de como ela o faz por dentro.
Trocar ou acrescentar uma implementação não exige alterar o código que chama notificar(mensagem).
Esse desacoplamento resolve o problema de repetição visto há pouco.
Aplicado ao acesso a dados, esse padrão tem nome: Data Access Object, ou DAO.
Uma interface DAO concentra as cinco operações de acesso a dados de uma entidade: find, merge, remove e as duas consultas JPQL, todas já escritas para Professor nesta aula.
Só a assinatura dos métodos, sem corpo (como Notificavel), agora reunindo as cinco operações já escritas para Professor.
public interface ProfessorDAO { void salvar(Professor professor); Professor buscarPorId(Long id); List<Professor> listarTodos(); void atualizar(Professor professor); void remover(Long id); }
Uma classe implementa a interface e escreve, para cada assinatura, o corpo que já sabíamos fazer à mão. Ela guarda a EntityManagerFactory uma única vez, como campo da classe.
public class ProfessorDAOJPA implements ProfessorDAO { private EntityManagerFactory emf = Persistence.createEntityManagerFactory("turmas-pu"); // ... }
Vamos ver cada método a seguir, os quatro que já conhecemos, mais um novo.
O mesmo código de sempre, agora dentro do método da classe.
public void salvar(Professor professor) { EntityManager em = emf.createEntityManager(); em.getTransaction().begin(); em.persist(professor); em.getTransaction().commit(); em.close(); }
find, devolvendo o objeto encontrado.
public Professor buscarPorId(Long id) { EntityManager em = emf.createEntityManager(); Professor professor = em.find(Professor.class, id); em.close(); return professor; }
Recebe o objeto já alterado, e grava a alteração com merge.
public void atualizar(Professor professor) { EntityManager em = emf.createEntityManager(); em.getTransaction().begin(); em.merge(professor); em.getTransaction().commit(); em.close(); }
A mesma consulta JPQL de sempre, devolvendo a lista inteira.
public List<Professor> listarTodos() { EntityManager em = emf.createEntityManager(); List<Professor> professores = em .createQuery("SELECT p FROM Professor p", Professor.class) .getResultList(); em.close(); return professores; }
Busca-se o objeto primeiro com find, porque não é possível remover só com o id, direto.
public void remover(Long id) { EntityManager em = emf.createEntityManager(); em.getTransaction().begin(); Professor professor = em.find(Professor.class, id); em.remove(professor); em.getTransaction().commit(); em.close(); }
O tipo declarado à esquerda é a interface; só a instanciação, à direita do =, sabe que por trás está ProfessorDAOJPA.
ProfessorDAO dao = new ProfessorDAOJPA(); dao.salvar(new Professor("Ana", "ana@ifrs.edu.br")); Professor professor = dao.buscarPorId(1L); dao.atualizar(professor); List<Professor> todos = dao.listarTodos(); dao.remover(2L);
Individualmente: escrevam a interface TurmaDAO e a implementação TurmaDAOJPA completas.
Individualmente: escrevam a interface AlunoDAO e a implementação AlunoDAOJPA completas.

Quer trocar mais uma ideia? Me chama!