π― JPA Query Features: Your Magic Toolkit for Finding Data
Imagine youβre a detective with a super-powered magnifying glass. You can ask ANY question about your data, and get the EXACT answers you need!
π The Big Picture
Think of a database like a giant toy box with millions of toys. JPA Query Features are your special powers to:
- Count toys (Aggregate Functions)
- Ask tricky questions (Subqueries)
- Build custom search robots (Criteria API)
Letβs unlock each power, one by one!
π JPQL Aggregate Functions
What Are They?
Aggregate functions are like math helpers. Instead of looking at each toy one-by-one, they look at ALL toys and give you ONE answer.
Simple Analogy: Imagine counting ALL your crayons instead of saying βred, blue, greenβ¦β You just say βI have 24 crayons!β
The 5 Super Powers
| Function | What It Does | Real Example |
|---|---|---|
COUNT |
Counts items | How many users? |
SUM |
Adds numbers | Total sales? |
AVG |
Finds average | Average age? |
MAX |
Finds biggest | Highest score? |
MIN |
Finds smallest | Cheapest item? |
Code Examples
COUNT - Count all employees:
SELECT COUNT(e)
FROM Employee e
Returns: 150 (one number!)
SUM - Total of all salaries:
SELECT SUM(e.salary)
FROM Employee e
Returns: 5000000
AVG - Average salary:
SELECT AVG(e.salary)
FROM Employee e
Returns: 33333.33
MAX & MIN together:
SELECT MAX(e.salary), MIN(e.salary)
FROM Employee e
Returns: 100000, 20000
GROUP BY Magic β¨
Want to count employees per department? Use GROUP BY!
SELECT e.department, COUNT(e)
FROM Employee e
GROUP BY e.department
Returns:
- Sales β 50
- Engineering β 80
- HR β 20
π JPQL Subqueries
What Are They?
A subquery is a question inside a question. Like asking:
βShow me employees who earn MORE than the AVERAGE salaryβ
First, you need to find the average. Then, compare everyone to it!
The Nesting Trick
graph TD A["Main Query"] --> B["Subquery"] B --> C["Answer from Subquery"] C --> D["Main Query Uses Answer"]
Real Examples
Find employees earning above average:
SELECT e FROM Employee e
WHERE e.salary > (
SELECT AVG(e2.salary)
FROM Employee e2
)
Find departments with more than 10 employees:
SELECT d FROM Department d
WHERE (
SELECT COUNT(e)
FROM Employee e
WHERE e.department = d
) > 10
WHERE vs HAVING with Subqueries
| Use WHERE | Use HAVING |
|---|---|
| Filter rows | Filter groups |
| Before grouping | After grouping |
-- HAVING example
SELECT e.department, AVG(e.salary)
FROM Employee e
GROUP BY e.department
HAVING AVG(e.salary) > 50000
ποΈ Criteria API: Build Queries Like LEGO!
Why Criteria API?
JPQL is like writing a letter. Criteria API is like building with LEGO blocks!
| JPQL | Criteria API |
|---|---|
| String-based | Object-based |
| Easy typos | Compiler checks |
| Fixed | Dynamic |
When to Use Criteria API:
- β Search forms with optional filters
- β Dynamic sorting
- β Type-safe queries
π§ CriteriaBuilder: Your Tool Factory
What Is It?
CriteriaBuilder is like a toolbox factory. It creates all the tools you need to build queries.
Getting Your Builder
EntityManager em = ...;
CriteriaBuilder cb = em.getCriteriaBuilder();
Tools CriteriaBuilder Creates
graph TD CB["CriteriaBuilder"] --> CQ["CriteriaQuery"] CB --> P["Predicates"] CB --> E["Expressions"] CB --> O["Orders"]
| Method | Creates | Example |
|---|---|---|
createQuery() |
Query object | New query |
equal() |
= condition | name = βJohnβ |
gt() |
> condition | salary > 50000 |
like() |
LIKE pattern | name LIKE βJ%β |
and() |
AND logic | A AND B |
or() |
OR logic | A OR B |
π CriteriaQuery: Your Query Blueprint
What Is It?
CriteriaQuery is the blueprint of your query. You tell it:
- WHAT to select
- FROM which table
- WHERE conditions
Building a Query Step-by-Step
// Step 1: Get the builder
CriteriaBuilder cb = em.getCriteriaBuilder();
// Step 2: Create the blueprint
CriteriaQuery<Employee> cq =
cb.createQuery(Employee.class);
// Step 3: Define the "FROM"
Root<Employee> emp = cq.from(Employee.class);
// Step 4: Define "SELECT"
cq.select(emp);
// Step 5: Execute!
List<Employee> results =
em.createQuery(cq).getResultList();
Visual Flow
graph TD A["CriteriaBuilder"] -->|creates| B["CriteriaQuery"] B -->|defines| C["Root - FROM clause"] C -->|add| D["Select"] D -->|add| E["Where/Predicates"] E -->|execute| F["Results!"]
π Predicates: Your Filter Conditions
What Are Predicates?
Predicates are true/false questions about your data.
βIs salary > 50000?β β TRUE or FALSE
Creating Predicates
CriteriaBuilder cb = em.getCriteriaBuilder();
Root<Employee> emp = cq.from(Employee.class);
// Simple predicate: salary > 50000
Predicate salaryCheck =
cb.gt(emp.get("salary"), 50000);
// Apply it!
cq.where(salaryCheck);
Combining Predicates
AND - Both must be true:
Predicate highSalary =
cb.gt(emp.get("salary"), 50000);
Predicate inSales =
cb.equal(emp.get("dept"), "Sales");
// salary > 50000 AND dept = 'Sales'
cq.where(cb.and(highSalary, inSales));
OR - Either can be true:
// dept = 'Sales' OR dept = 'Marketing'
cq.where(cb.or(inSales, inMarketing));
NOT - Opposite:
// NOT (salary < 30000)
cq.where(cb.not(lowSalary));
Common Predicate Methods
| Method | Meaning | SQL Equivalent |
|---|---|---|
equal() |
Equals | = |
notEqual() |
Not equals | != |
gt() |
Greater than | > |
ge() |
Greater or equal | >= |
lt() |
Less than | < |
le() |
Less or equal | <= |
like() |
Pattern match | LIKE |
between() |
In range | BETWEEN |
isNull() |
Is null | IS NULL |
in() |
In list | IN (β¦) |
π Joins in Criteria: Connecting Tables
What Are Joins?
Joins connect related tables. Like connecting puzzle pieces!
graph LR E["Employee"] -->|works in| D["Department"] E -->|has| P["Projects"]
Types of Joins
| Join Type | Meaning |
|---|---|
INNER JOIN |
Only matching rows |
LEFT JOIN |
All left + matching right |
RIGHT JOIN |
All right + matching left |
Creating Joins in Criteria
Basic Join:
Root<Employee> emp =
cq.from(Employee.class);
// Join to Department
Join<Employee, Department> dept =
emp.join("department");
// Now filter on department!
cq.where(
cb.equal(dept.get("name"), "Sales")
);
Left Join (keep all employees):
Join<Employee, Department> dept =
emp.join("department", JoinType.LEFT);
Multiple Joins:
Root<Employee> emp =
cq.from(Employee.class);
Join<Employee, Department> dept =
emp.join("department");
Join<Employee, Project> proj =
emp.join("projects");
// Filter: Sales dept AND active projects
cq.where(
cb.and(
cb.equal(dept.get("name"), "Sales"),
cb.equal(proj.get("active"), true)
)
);
Fetch Joins (Performance Boost!)
Fetch joins load related data in ONE query:
// Without fetch: N+1 queries problem!
// With fetch: 1 query only!
Root<Employee> emp =
cq.from(Employee.class);
emp.fetch("department", JoinType.LEFT);
π― Complete Example: Dynamic Search
Letβs build a real search form!
public List<Employee> search(
String name,
Double minSalary,
String department
) {
CriteriaBuilder cb =
em.getCriteriaBuilder();
CriteriaQuery<Employee> cq =
cb.createQuery(Employee.class);
Root<Employee> emp =
cq.from(Employee.class);
// Collect predicates dynamically
List<Predicate> predicates =
new ArrayList<>();
// Add conditions only if provided
if (name != null) {
predicates.add(
cb.like(emp.get("name"),
"%" + name + "%")
);
}
if (minSalary != null) {
predicates.add(
cb.ge(emp.get("salary"),
minSalary)
);
}
if (department != null) {
Join<Employee, Department> dept =
emp.join("department");
predicates.add(
cb.equal(dept.get("name"),
department)
);
}
// Apply all predicates with AND
cq.where(
cb.and(predicates.toArray(
new Predicate[0]))
);
return em.createQuery(cq)
.getResultList();
}
π Quick Reference
graph LR A["JPA Query Features"] --> B["Aggregate Functions"] A --> C["Subqueries"] A --> D["Criteria API"] B --> B1["COUNT/SUM/AVG"] B --> B2["MAX/MIN"] B --> B3["GROUP BY"] C --> C1["Nested SELECT"] C --> C2["WHERE subquery"] C --> C3["HAVING subquery"] D --> D1["CriteriaBuilder"] D --> D2["CriteriaQuery"] D --> D3["Predicates"] D --> D4["Joins"]
π‘ Remember These!
- Aggregates = Math on groups (COUNT, SUM, AVG, MAX, MIN)
- Subqueries = Questions inside questions
- CriteriaBuilder = Your tool factory
- CriteriaQuery = Your query blueprint
- Predicates = True/false filters
- Joins = Connecting related tables
π You did it! You now have the power to ask ANY question about your data. Go build something amazing!
