JPA - JPQL

Este capítulo fala sobre JPQL e como ele funciona com unidades de persistência. Neste capítulo, os exemplos seguem a mesma hierarquia de pacotes, que usamos no capítulo anterior da seguinte maneira:

Linguagem Java Persistence Query

JPQL é Java Persistence Query Language definida na especificação JPA. É usado para criar consultas em entidades para armazenar em um banco de dados relacional. JPQL é desenvolvido com base na sintaxe SQL. Mas isso não afetará o banco de dados diretamente.

JPQL pode recuperar informações ou dados usando a cláusula SELECT, pode fazer atualizações em massa usando as cláusulas UPDATE e DELETE. A API EntityManager.createQuery () oferece suporte para linguagem de consulta.

Estrutura de Consulta

A sintaxe JPQL é muito semelhante à sintaxe SQL. Ter a sintaxe semelhante ao SQL é uma vantagem porque o SQL é uma linguagem de consulta estruturada simples e muitos desenvolvedores a estão usando em aplicativos. O SQL funciona diretamente em tabelas, registros e campos de banco de dados relacional, enquanto JPQL funciona com classes e instâncias Java.

Por exemplo, uma consulta JPQL pode recuperar um objeto de entidade em vez de conjunto de resultados de campo do banco de dados, como no SQL. A estrutura da consulta JPQL da seguinte maneira.

SELECT ... FROM ...
[WHERE ...]
[GROUP BY ... [HAVING ...]]
[ORDER BY ...]

A estrutura das consultas JPQL DELETE e UPDATE é mais simples da seguinte maneira.

DELETE FROM ... [WHERE ...]
 
UPDATE ... SET ... [WHERE ...]

Funções escalares e agregadas

Funções escalares retornam valores resultantes com base em valores de entrada. As funções agregadas retornam os valores resultantes calculando os valores de entrada.

Siga o mesmo exemplo de gerenciamento de funcionários usado nos capítulos anteriores. Aqui, vamos percorrer as classes de serviço usando funções escalares e agregadas de JPQL.

Vamos supor que a tabela jpadb.employee contém os seguintes registros.

Eid Ename Salário Grau
1201 Gopal 40.000 Gerente técnico
1202 Manisha 40.000 Leitor de Provas
1203 Masthanvali 40.000 Escritor técnico
1204 Satish 30000 Escritor técnico
1205 Krishna 30000 Escritor técnico
1206 Kiran 35000 Leitor de Provas

Crie uma classe chamada ScalarandAggregateFunctions.java debaixo com.tutorialspoint.eclipselink.service pacote da seguinte forma.

package com.tutorialspoint.eclipselink.service;

import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.persistence.Query;

public class ScalarandAggregateFunctions {
   public static void main( String[ ] args ) {
   
      EntityManagerFactory emfactory = Persistence.createEntityManagerFactory( "Eclipselink_JPA" );
      EntityManager entitymanager = emfactory.createEntityManager();

      //Scalar function
      Query query = entitymanager.
      createQuery("Select UPPER(e.ename) from Employee e");
      List<String> list = query.getResultList();

      for(String e:list) {
         System.out.println("Employee NAME :"+e);
      }
      
      //Aggregate function
      Query query1 = entitymanager.createQuery("Select MAX(e.salary) from Employee e");
      Double result = (Double) query1.getSingleResult();
      System.out.println("Max Employee Salary :" + result);
   }
}

Após a compilação e execução do programa acima, você obterá a saída no painel do console do Eclipse IDE da seguinte forma:

Employee NAME :GOPAL
Employee NAME :MANISHA
Employee NAME :MASTHANVALI
Employee NAME :SATISH
Employee NAME :KRISHNA
Employee NAME :KIRAN
ax Employee Salary :40000.0

Entre, E, Palavras-chave semelhantes

'Entre', 'E' e 'Como' são as principais palavras-chave do JPQL. Essas palavras-chave são usadas após a cláusula Where em uma consulta.

Crie uma classe chamada BetweenAndLikeFunctions.java debaixo com.tutorialspoint.eclipselink.service pacote da seguinte forma:

package com.tutorialspoint.eclipselink.service;

import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.persistence.Query;
import com.tutorialspoint.eclipselink.entity.Employee;

public class BetweenAndLikeFunctions {
   public static void main( String[ ] args ) {
   
      EntityManagerFactory emfactory = Persistence.createEntityManagerFactory( "Eclipselink_JPA" );
      EntityManager entitymanager = emfactory.createEntityManager();
      
      //Between
      Query query = entitymanager.createQuery( "Select e " + "from Employee e " + "where e.salary " + "Between 30000 and 40000" );
      
      List<Employee> list=(List<Employee>)query.getResultList( );

      for( Employee e:list ){
         System.out.print("Employee ID :" + e.getEid( ));
         System.out.println("\t Employee salary :" + e.getSalary( ));
      }

      //Like
      Query query1 = entitymanager.createQuery("Select e " + "from Employee e " + "where e.ename LIKE 'M%'");
      
      List<Employee> list1=(List<Employee>)query1.getResultList( );
      
      for( Employee e:list1 ) {
         System.out.print("Employee ID :"+e.getEid( ));
         System.out.println("\t Employee name :"+e.getEname( ));
      }
   }
}

Após a compilação e execução do programa acima, você obterá a saída no painel do console do Eclipse IDE da seguinte forma:

Employee ID :1201	 Employee salary :40000.0
Employee ID :1202	 Employee salary :40000.0
Employee ID :1203	 Employee salary :40000.0
Employee ID :1204	 Employee salary :30000.0
Employee ID :1205	 Employee salary :30000.0
Employee ID :1206	 Employee salary :35000.0

Employee ID :1202	 Employee name :Manisha
Employee ID :1203	 Employee name :Masthanvali

Encomenda

Para solicitar os registros em JPQL, usamos a cláusula ORDER BY. O uso dessa cláusula é igual ao uso em SQL, mas trata de entidades. Siga o exemplo do pedido.

Crie uma classe Ordering.java em com.tutorialspoint.eclipselink.service pacote da seguinte forma:

package com.tutorialspoint.eclipselink.service;

import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.persistence.Query;
import com.tutorialspoint.eclipselink.entity.Employee;

public class Ordering {

   public static void main( String[ ] args ) {
      EntityManagerFactory emfactory = Persistence.createEntityManagerFactory( "Eclipselink_JPA" );
      EntityManager entitymanager = emfactory.createEntityManager();
      
      //Between
      Query query = entitymanager.createQuery( "Select e " + "from Employee e " + "ORDER BY e.ename ASC" );

      List<Employee> list = (List<Employee>)query.getResultList( );

      for( Employee e:list ) {
         System.out.print("Employee ID :" + e.getEid( ));
         System.out.println("\t Employee Name :" + e.getEname( ));
      }
   }
}

Após a compilação e execução do programa acima, você obterá a saída no painel do console do Eclipse IDE da seguinte forma:

Employee ID :1201	 Employee Name :Gopal
Employee ID :1206	 Employee Name :Kiran
Employee ID :1205	 Employee Name :Krishna
Employee ID :1202	 Employee Name :Manisha
Employee ID :1203	 Employee Name :Masthanvali
Employee ID :1204	 Employee Name :Satish

Consultas nomeadas

Uma anotação @NamedQuery é definida como uma consulta com uma string de consulta predefinida e imutável. Em vez de consultas dinâmicas, o uso de consultas nomeadas pode melhorar a organização do código, separando as strings de consulta JPQL do POJO. Ele também passa os parâmetros de consulta em vez de incorporar literais dinamicamente na string de consulta e resulta em consultas mais eficientes.

Primeiro de tudo, adicione a anotação @NamedQuery à classe de entidade Employee chamada Employee.java debaixo com.tutorialspoint.eclipselink.entity pacote da seguinte forma:

package com.tutorialspoint.eclipselink.entity;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.NamedQuery;
import javax.persistence.Table;

@Entity
@Table
@NamedQuery(query = "Select e from Employee e where e.eid = :id", name = "find employee by id")

public class Employee {
   @Id
   @GeneratedValue(strategy = GenerationType.AUTO) 	
   
   private int eid;
   private String ename;
   private double salary;
   private String deg;
   
   public Employee(int eid, String ename, double salary, String deg) {
      super( );
      this.eid = eid;
      this.ename = ename;
      this.salary = salary;
      this.deg = deg;
   }
   
   public Employee( ) {
      super();
   }

   public int getEid( ) {
      return eid;
   }
   
   public void setEid(int eid) {
      this.eid = eid;
   }

   public String getEname( ) {
      return ename;
   }
   
   public void setEname(String ename) {
      this.ename = ename;
   }

   public double getSalary( ) {
      return salary;
   }
   
   public void setSalary(double salary) {
      this.salary = salary;
   }

   public String getDeg( ) {
      return deg;
   }
   
   public void setDeg(String deg) {
      this.deg = deg;
   }
   
   @Override
   public String toString() {
      return "Employee [eid=" + eid + ", ename=" + ename + ", salary=" + salary + ", deg=" + deg + "]";
   }
}

Crie uma classe chamada NamedQueries.java debaixo com.tutorialspoint.eclipselink.service pacote da seguinte forma:

package com.tutorialspoint.eclipselink.service;

import java.util.List;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.persistence.Query;
import com.tutorialspoint.eclipselink.entity.Employee;

public class NamedQueries {
   public static void main( String[ ] args ) {
   
      EntityManagerFactory emfactory = Persistence.createEntityManagerFactory( "Eclipselink_JPA" );
      EntityManager entitymanager = emfactory.createEntityManager();
      Query query = entitymanager.createNamedQuery("find employee by id");
      
      query.setParameter("id", 1204);
      List<Employee> list = query.getResultList( );
      
      for( Employee e:list ){
         System.out.print("Employee ID :" + e.getEid( ));
         System.out.println("\t Employee Name :" + e.getEname( ));
      }
   }
}

Após a compilação e execução do programa acima, você obterá a saída no painel do console do Eclipse IDE da seguinte forma:

Employee ID :1204	 Employee Name :Satish

Depois de adicionar todas as classes acima, a hierarquia do pacote é mostrada da seguinte forma:

Carregamento ansioso e lento

O conceito principal do JPA é fazer uma cópia duplicada do banco de dados na memória cache. Durante a transação com o banco de dados, primeiro isso afetará os dados duplicados e, apenas quando for confirmado usando o gerenciador de entidade, as alterações serão efetuadas no banco de dados.

Existem duas maneiras de obter registros do banco de dados - eager fetch e lazy fetch.

Eager fetch

Buscando o registro inteiro enquanto encontra o registro usando a chave primária.

Preguiçoso

Ele verifica a disponibilidade ou o notifica com a chave primária, se houver. Mais tarde, se você chamar qualquer um dos métodos getter dessa entidade, ele buscará o todo.

Mas a busca lenta é possível quando você tenta buscar o registro pela primeira vez. Dessa forma, uma cópia de todo o registro já está armazenada na memória cache. Em termos de desempenho, a busca lenta é preferível.