Home Buscando Dados com JPQL & Criteria API - Jakarta EE
Post
Cancelar

Buscando Dados com JPQL & Criteria API - Jakarta EE

Baseado nos cursos da Softblue

JPQL

• Java Persistence Query Language

• Linguagem para busca de entidades

– Bastante semelhança com o SQL, usado em bancos de dados relacionais

• A JPQL referencia apenas entidades

– Não referencia tabelas ou colunas presentes no banco de dados

• Buscar todas as contas correntes

1
SELECT c FROM ContaCorrente c

• Buscar contas correntes com limite superior a 1000

1
SELECT c FROM ContaCorrente c WHERE c.limite > 1000

• Buscar os nomes dos titulares de contas da agência 3456

1
SELECT c.titularConta FROM ContaCorrente c WHERE c.numAgencia = 3456

• Buscar a quantidade de contas do titular José Silva

1
SELECT COUNT(c) FROM ContaCorrente c WHERE c.titularConta = 'José Silva'

• Buscar a soma dos saldos das contas correntes, agrupada por agência

1
2
3
SELECT c.numAgencia, SUM(c.saldo) FROM ContaCorrente c
  GROUP BY c.numAgencia
  ORDER BY c.numAgencia

Relacionamentos e a JPQL

• A linguagem JPQL também suporta relacionamentos

• Os relacionamentos podem ser expressos de duas formas

– Usando o “.”, como acontece com qualquer propriedade de uma entidade

• Possível em relacionamentos um-para-um e muitos-para-um

– Usando o conceito de join, similar ao aplicado na linguagem SQL

• [INNER] JOIN

• LEFT [OUTER] JOIN

• RIGHT [OUTER] JOIN

classDiagram
    class Pedido{
      -cliente: Cliente
    }
    class Cliente{
      -pedidos: List<Pedido>
    }
    Pedido "*" -- "1" Cliente
1
2
3
4
5
SELECT p FROM Pedido p WHERE p.cliente.nome = 'Pedro'

SELECT p FROM Pedido p INNER JOIN p.cliente c WHERE c.nome = 'Pedro'

SELECT p FROM Cliente c INNER JOIN c.pedidos p WHERE c.nome = 'Pedro'

EAGER na JPQL

• Através da linguagem JPQL, é possível fazer com que relacionamentos definidos como LAZY se comportem como EAGER

1
2
3
4
5
SELECT c FROM Cliente c INNER JOIN c.pedidos p
WHERE c.nome = 'Pedro' /*Relacionamento LAZY*/

SELECT c FROM Cliente c INNER JOIN FETCH c.pedidos p
WHERE c.nome = 'Pedro' /*O uso do FETCH força o carregamento das entidades (modo EAGER)*/

Buscando Entidades

• O EntityManager possui o método createQuery(), que permite o uso da JPQL

1
2
3
4
5
Query q = em.createQuery("SELECT p FROM Pedido p"); //@SuppressWarnings("unchecked")
List<Pedido> pedidos = q.getResultList();

TypedQuery<Pedido> q = em.createQuery("SELECT p FROM Pedido p", Pedido.class);
List<Pedido> pedidos = q.getResultList();

• Se você souber que o resultado da query retorna 1 resultado, você pode simplificar

1
2
TypedQuery<Pedido> q = em.createQuery("SELECT p FROM Pedido p", Pedido.class);
Pedido pedido = q.getSingleResult();

Parâmetros em Queries JPQL

• A JPQL suporta o uso de parâmetros

1
2
3
4
5
6
7
8
9
10
11
TypedQuery<Integer> q = em.createQuery(
  "SELECT p.id FROM Pedido p WHERE p.valor > :valor", Integer.class)
  .setParameter("valor", 1000)//Parâmetros nomeados
  .setMaxResults(5);
List<Integer> ids = q.getResultList();

TypedQuery<Integer> q = em.createQuery(
  "SELECT p.id FROM Pedido p WHERE p.valor > ?1 and p.pais LIKE ?2", Integer.class)//Parâmetros posicionais
  .setParameter(1, 500)
  .setParameter(2, "B%");
List<Integer> ids = q.getResultList();

Named Queries

• A JPA suporta o uso de queries nomeadas

• Devem ser declaradas em uma entidade

1
2
3
4
5
6
7
8
@NamedQuery(name = "All", query = "SELECT p FROM Pedido p")
public class Pedido { }

@NamedQueries({ 
  @NamedQuery(name = "All", query = "SELECT p FROM Pedido p"),
  @NamedQuery(name = "Free", query = "SELECT p FROM Pedido p WHERE p.valor = 0")
})
public class Pedido { }

• A execução de uma named query é parecida com a de qualquer query JPQL

1
2
TypedQuery<Pedido> q = em.createNamedQuery("All", Pedido.class);
List<Pedido> pedidos = q.getResultList();

Update & Delete com JPQL

• A JPQL suporta a atualização e exclusão de registros em lote, de acordo com os critérios desejados

1
2
3
4
5
6
7
Query q = em.createQuery(
  "UPDATE Pedido p SET p.valor = 100 WHERE p.valor = 50");
q.executeUpdate();

Query q = em.createQuery(
  "DELETE FROM Pedido p WHERE p.valor = 20");
q.executeUpdate();

Criteria API

• É uma API que permite que você busque dados, de forma semelhante à JPQL

• É baseada em uma objetos e métodos, e não em Strings como a JPQL

– Esta é uma vantagem, pois a query já é checada durante a compilação

• A Criteria API é mais verbosa

Passos Para Usar a Criteria API

• Exemplo de query

– Listar os números de contas bancárias cujo saldo seja inferior a R$ 5000, e ordená-las por ordem decrescente de saldo

• Em JPQL:

1
2
3
4
SELECT c.numero
FROM ContaBancaria c
WHERE c.saldo < 5000
ORDER BY c.saldo DESC

• Usando a Criteria API:

  1. Obter um CriteriaBuilder
1
CriteriaBuilder cb = em.getCriteriaBuilder();
  1. Criar um CriteriaQuery
1
CriteriaQuery<String> cq = cb.createQuery(String.class);
  1. Definir o FROM
1
Root<ContaBancaria> contaBancaria = cq.from(ContaBancaria.class);
  1. Definir o SELECT
1
cq.select(contaBancaria.get(ContaBancaria_.numero));
  1. Definir o WHERE
1
cq.where(cb.lessThan(contaBancaria.get(ContaBancaria_.saldo), 5000.0));
  1. Definir o ORDER BY
1
cq.orderBy(cb.desc(contaBancaria.get(ContaBancaria_.saldo)));
  1. Executar a query
1
2
TypedQuery<String> q = em.createQuery(cq);
List<String> result = q.getResultList();

Exemplo usando JOIN

JPQL

1
2
3
4
SELECT cc.saldo
FROM ContaBancaria cc INNER JOIN cc.cliente c
WHERE c.nome = 'Carlos' 
ORDER BY cc.saldo ASC

Criteria API

1
2
3
4
5
6
7
8
9
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Double> cq = cb.createQuery(Double.class);
Root<ContaBancaria> contaBancaria = cq.from(ContaBancaria.class);
Join<ContaBancaria, Cliente> cliente = contaBancaria.join(ContaBancaria_.cliente);
cq.select(contaBancaria.get(ContaBancaria_.saldo));
cq.where(cb.equal(cliente.get(Cliente_.nome), "Carlos"));
cq.orderBy(cb.asc(contaBancaria.get(ContaBancaria_.saldo)));
TypedQuery<Double> q = em.createQuery(cq);
List<Double> result = q.getResultList();

Métodos de CriteriaBuilder

• Métodos condicionais

MétodoDescrição
equal()Testa se duas expressões são iguais
notEqual()Testa se duas expressões são diferentes
greaterThan()Testa se a primeira expressão numérica é maior do que a segunda expressão numérica
greaterThanOrEqualTo()Testa se a primeira expressão numérica é maior ou igual à segunda expressão numérica
lessThan()Testa se a primeira expressão numérica é menor do que a segunda expressão numérica
lessThanOrEqualTo()Testa se a primeira expressão numérica é menor ou igual à segunda expressão numérica
between()Testa se a primeira expressão está entre dois valores
like()Testa se a expressão possui determinado padrão

• Métodos de composição de predicados

MétodoDescrição
and()Aplica o operador E em duas expressões lógicas
or()Aplica o operador OU em duas expressões lógicas
not()Nega uma expressão lógica

Metamodel API

• Possibilita o acesso às propriedades das entidades com verificação durante a compilação

1
2
3
4
5
6
7
8
9
Join<ContaBancaria, Cliente> cliente = contaBancaria.join("cliente");
cq.select(contaBancaria.get("saldo"));
cq.where(cb.equal(cliente.get("nome"), "Carlos"));
cq.orderBy(cb.asc(contaBancaria.get("saldo")));//Problema de execução se alguma propriedade mudar de nome

Join<ContaBancaria, Cliente> cliente = contaBancaria.join(ContaBancaria_.cliente);
cq.select(contaBancaria.get(ContaBancaria_.saldo));
cq.where(cb.equal(cliente.get(Cliente_.nome), "Carlos"));
cq.orderBy(cb.asc(contaBancaria.get(ContaBancaria_.saldo)));//Se alguma propriedade mudar de nome, o erro ocorre na compilação

Classes de Metamodel

• É comum que a IDE gere as classes de Metamodel relacionadas às entidades

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@Entity
public class ContaBancaria {
  @Id
  private Integer id;
  private String numero;
  private String agencia;
  private Double saldo;
  @ManyToOne
  private Cliente cliente;
  // getters & setters
}

@Generated
@StaticMetamodel(ContaBancaria.class)
public class ContaBancaria_ {
  public static SingularAttribute<ContaBancaria, String> numero;
  public static SingularAttribute<ContaBancaria, Integer> id;
  public static SingularAttribute<ContaBancaria, String> agencia;
  public static SingularAttribute<ContaBancaria, Cliente> cliente;
  public static SingularAttribute<ContaBancaria, Double> saldo;
}
Esta postagem está licenciada sob CC BY 4.0 pelo autor.