Querying Data

About

Querying is one of the most critical parts of working with JPA. JPA provides multiple ways to retrieve, filter, and manipulate data from the database using object-oriented approaches rather than SQL. This simplifies development and improves maintainability.

Types of Queries in JPA

JPA supports four main ways to query data:

  1. JPQL (Java Persistence Query Language)

  2. Criteria API

  3. Native SQL Queries

  4. Derived Query Methods (Spring Data JPA)

1. JPQL (Java Persistence Query Language)

About

JPQL stands for Java Persistence Query Language. It is the standard query language of JPA (Java Persistence API) and is used to query Java entity objects instead of database tables directly.

Characteristics

Feature
Description

Object-Oriented

Operates on entity objects, not tables or columns.

Portable

Not tied to a specific database vendor.

Static / Dynamic

Can be defined at compile-time or built dynamically at runtime.

Supports Joins

Can navigate object relationships using JOIN.

Part of JPA Standard

Fully standardized across JPA providers (Hibernate, EclipseLink, etc).

Syntax Structure

SELECT <select_clause>
FROM <entity_class> [AS] <alias>
[WHERE <conditions>]
[GROUP BY ...]
[HAVING ...]
[ORDER BY ...]

Example

SELECT e FROM Employee e WHERE e.department.name = 'IT'

JPQL vs SQL

Feature
SQL
JPQL

Targets

Tables and Columns

Entities and Fields

Joins

Based on foreign keys

Based on object relationships

Type

Database-level

Application-level abstraction

Portability

Vendor-specific

Vendor-agnostic

2. Criteria API

About

The Criteria API is a type-safe, programmatic way of building dynamic queries using Java objects and methods rather than writing strings. It's especially useful for building complex queries where the structure is determined at runtime.

Characteristics

  • Type-safe: Catches syntax and field errors at compile time.

  • Dynamic: Ideal for building queries with user-driven filters.

  • Verbose: Requires more boilerplate than JPQL.

  • Integrated with Metamodel: Can use static metamodel classes for even more type safety.

  • Portable: Part of the JPA specification and works across JPA providers.

Syntax Structure

CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Employee> cq = cb.createQuery(Employee.class);
Root<Employee> root = cq.from(Employee.class);
cq.select(root).where(cb.equal(root.get("department"), "IT"));
List<Employee> results = em.createQuery(cq).getResultList();

Criteria API vs JPQL

Feature
Criteria API
JPQL

Query Type

Object-oriented, Java code

String-based query language

Type Safety

Compile-time checked

X Runtime only

Dynamic Querying

Strong support

Requires string concatenation

Readability

Verbose and less readable

More concise and readable

Maintainability

Refactor-friendly

Errors possible if entity fields renamed

Ideal Use Case

Complex, conditional filters

Simple to moderately complex queries

3. Native SQL

About

Native SQL queries in JPA allow you to write plain SQL and run it through JPA. These are useful when you need database-specific functionality, use raw SQL joins, stored procedures, or complex queries not supported by JPQL.

Characteristics

  • Full SQL power: Uses complete database syntax.

  • Database dependent: Tied to a specific RDBMS dialect.

  • Bypasses abstraction: Operates directly on DB tables.

  • Less portable: Might break if the DB vendor changes.

  • Mapping required: You can map results to entities or DTOs manually.

Syntax Structure

Query query = em.createNativeQuery("SELECT * FROM employee WHERE status = ?", Employee.class);
query.setParameter(1, "ACTIVE");
List<Employee> result = query.getResultList();

Native SQL vs JPQL

Feature
Native SQL
JPQL

Syntax

Raw SQL

Object-oriented query

Portability

XVendor-specific

Portable across DBs

Entity Awareness

X Works with tables

Works with entities

Use of ORM Features

X Limited or manual

Fully integrat

Use Case

Complex SQL, vendor-specific logic

Standard CRUD and entity navigation

4. Named Queries

About

Named Queries are static, pre-defined JPQL queries that are defined using annotations (typically on the entity class). They promote reuse and centralize query logic.

Characteristics

  • Static and pre-compiled: Verified at deployment.

  • Reusable: Can be called anywhere via name.

  • Maintainable: Kept with the entity for better encapsulation.

  • Optimizable: Some providers pre-parse/optimize them.

  • Supports both JPQL and native: Use @NamedQuery or @NamedNativeQuery.

Syntax Structure

@Entity
@NamedQuery(
    name = "Employee.findByStatus",
    query = "SELECT e FROM Employee e WHERE e.status = :status"
)

Usage:

em.createNamedQuery("Employee.findByStatus")
  .setParameter("status", "ACTIVE")
  .getResultList();

Named Query vs JPQL

Feature
Named Query
JPQL

Definition Time

Compile time

Runtime

Reusability

Easily reused

Needs to be redefined each time

Location

In entity or XML config

Inline in code

Maintainability

Centralized

Scattered

Use Case

Frequently used queries

One-off, dynamic, or simple queries

Last updated

Was this helpful?