Return to site

🚀🗄️ DOING JPA IN QUARKUS WITH PANACHE (REPOSITORY PATTERN)

October 11, 2025

TL;DR

Panache trims JPA boilerplate in Quarkus. Implement PanacheRepository〈 T〉 (or PanacheRepositoryBase〈 T, ID〉 ) to get a fluent CRUD/query API, paging & sorting via PanacheQuery, and fewer lines everywhere.

🔸 WHY PANACHE (REPO PATTERN)?

▪️ Less boilerplate vs plain JPA: ready-made CRUD & query helpers

▪️ Clear separation: your domain stays lean, repos encapsulate DB access

▪️ First-class paging, sorting, projections via PanacheQuery

🔸 QUICK SETUP

〈 !-- pom.xml --〉

〈 dependency〉

〈 groupId〉 io.quarkus〈 /groupId〉

〈 artifactId〉 quarkus-hibernate-orm-panache〈 /artifactId〉

〈 /dependency〉

〈 dependency〉

〈 groupId〉 io.quarkus〈 /groupId〉

〈 artifactId〉 quarkus-jdbc-postgresql〈 /artifactId〉

〈 /dependency〉

// Entity

@Entity

public class Book {

@Id @GeneratedValue Long id;

String title;

String author;

LocalDate publishedOn;

}

// Repository

@ApplicationScoped

public class BookRepository implements PanacheRepository〈 Book〉 { }

Docs: Quarkus Panache guide & javadoc for the full API. (Quarkus)

🔸 PANACHE REPOSITORY: THE ESSENTIAL METHODS

PanacheRepository〈 T〉 extends the full API from PanacheRepositoryBase〈 T, ID〉 . Below are the core families you’ll use daily (multiple overloads exist). See javadoc for the exhaustive list. (Javadoc)

Create & Update

▪️ persist(entity) / persist(entities…)

▪️ persistAndFlush(entity)

▪️ flush() (force sync)

▪️ isPersistent(entity) (managed?)

Read by id

▪️ findById(id) / findByIdOptional(id)

Delete

▪️ delete(entity)

▪️ deleteById(id)

▪️ deleteAll()

▪️ delete("status", Status.OLD) / delete("name like ?1", pattern) (simplified JPQL) (Stack Overflow)

Count

▪️ count()

▪️ count("author", author) / count("title like ?1", pattern)

List/Stream everything (for small sets)

▪️ listAll() / listAll(Sort.by("publishedOn").descending())

▪️ streamAll()

Query (simplified JPQL / named / params)

▪️ find(query, params…) → returns PanacheQuery〈 T〉

▪️ find(query, Sort, params…)

▪️ list(query, params…) / stream(query, params…)

▪️ findAll() / findAll(Sort)

Paging & Sorting with PanacheQuery

PanacheQuery〈 Book〉 q = Book.find("author", "Pratchett")

.page(Page.of(0, 20))

.sort(Sort.by("publishedOn").descending());

List〈 Book〉 page = q.list(); // current page

long total = q.count(); // total items

Tip: prefer PanacheQuery + page() for large datasets; use list/stream only for small tables. (Quarkus)

🔸 EXAMPLES YOU’LL REUSE

// Create

@Transactional

public Book add(Book b) {

persist(b); // managed; id filled after flush

return b;

}

// Read + paging

public List〈 Book〉 latestBy(String author, int page, int size) {

return find("author", author)

.page(Page.of(page, size))

.sort(Sort.by("publishedOn").descending())

.list();

}

// Update (managed entity)

@Transactional

public void rename(long id, String newTitle) {

Book b = findById(id);

if (b != null) b.title = newTitle; // dirty checking on flush

}

// Delete by query

@Transactional

public long purgeOld(LocalDate before) {

return delete("publishedOn 〈 ?1", before);

}

🔸 TAKEAWAYS

▪️ Implement PanacheRepository〈 T〉 to get a rich, fluent CRUD & query API fast

▪️ Use find(…) → PanacheQuery for paging/sorting; avoid listAll() on big tables

▪️ Embrace simplified JPQL strings ("author", value) for concise queries

▪️ Remember transactions (@Transactional) for write ops

#Quarkus #JPA #Hibernate #Panache #Java #JakartaEE #Backend #ORM #CleanCode #JavaEE #DevTips

Go further with Java certification:

Java👇

Spring👇