Simplify your persistence code for Hibernate ORM via the active record or the repository pattern
—
Core functionality for entities using the Active Record pattern through PanacheEntity and PanacheEntityBase. This pattern allows entities to inherit query and persistence methods directly as static methods on the entity class.
Foundation classes for the Active Record pattern.
public abstract class PanacheEntity extends PanacheEntityBase {
@Id
@GeneratedValue
public Long id;
@Override
public String toString();
}
public abstract class PanacheEntityBase {
// Inherits all static query and persistence methods
// Instance methods
public void persist();
public void persistAndFlush();
public void delete();
public boolean isPersistent();
}Usage:
@Entity
public class Person extends PanacheEntity {
public String name;
public LocalDate birth;
public PersonStatus status;
}Static methods for finding entities by ID or query.
public static <T extends PanacheEntityBase> T findById(Object id);
public static <T extends PanacheEntityBase> T findById(Object id, LockModeType lockModeType);
public static <T extends PanacheEntityBase> Optional<T> findByIdOptional(Object id);
public static <T extends PanacheEntityBase> Optional<T> findByIdOptional(Object id, LockModeType lockModeType);
public static <T extends PanacheEntityBase> PanacheQuery<T> find(String query, Object... params);
public static <T extends PanacheEntityBase> PanacheQuery<T> find(String query, Sort sort, Object... params);
public static <T extends PanacheEntityBase> PanacheQuery<T> find(String query, Map<String, Object> params);
public static <T extends PanacheEntityBase> PanacheQuery<T> find(String query, Sort sort, Map<String, Object> params);
public static <T extends PanacheEntityBase> PanacheQuery<T> find(String query, Parameters params);
public static <T extends PanacheEntityBase> PanacheQuery<T> find(String query, Sort sort, Parameters params);
public static <T extends PanacheEntityBase> PanacheQuery<T> findAll();
public static <T extends PanacheEntityBase> PanacheQuery<T> findAll(Sort sort);Usage:
// Find by ID
Person person = Person.findById(1L);
Optional<Person> maybePerson = Person.findByIdOptional(1L);
// Find with queries
List<Person> activeUsers = Person.find("status", PersonStatus.Active).list();
List<Person> namedUsers = Person.find("name = ?1", "John").list();
List<Person> sortedUsers = Person.find("status", PersonStatus.Active)
.page(0, 10).list();
// Find all
List<Person> allPeople = Person.findAll().list();
List<Person> sortedPeople = Person.findAll(Sort.by("name")).list();Convenience methods that directly return Lists (shortcuts for find().list()).
public static <T extends PanacheEntityBase> List<T> list(String query, Object... params);
public static <T extends PanacheEntityBase> List<T> list(String query, Sort sort, Object... params);
public static <T extends PanacheEntityBase> List<T> list(String query, Map<String, Object> params);
public static <T extends PanacheEntityBase> List<T> list(String query, Sort sort, Map<String, Object> params);
public static <T extends PanacheEntityBase> List<T> list(String query, Parameters params);
public static <T extends PanacheEntityBase> List<T> list(String query, Sort sort, Parameters params);
public static <T extends PanacheEntityBase> List<T> listAll();
public static <T extends PanacheEntityBase> List<T> listAll(Sort sort);Usage:
// Direct list results
List<Person> activeUsers = Person.list("status", PersonStatus.Active);
List<Person> sortedUsers = Person.list("name like ?1", "J%", Sort.by("name"));
List<Person> allPeople = Person.listAll();
// With named parameters
Map<String, Object> params = Map.of("status", PersonStatus.Active, "city", "NYC");
List<Person> nycActive = Person.list("status = :status AND city = :city", params);
// With Parameters helper
List<Person> filtered = Person.list("status = :status AND age > :age",
Parameters.with("status", PersonStatus.Active).and("age", 18));Methods that return Streams for memory-efficient processing (require active transaction).
public static <T extends PanacheEntityBase> Stream<T> stream(String query, Object... params);
public static <T extends PanacheEntityBase> Stream<T> stream(String query, Sort sort, Object... params);
public static <T extends PanacheEntityBase> Stream<T> stream(String query, Map<String, Object> params);
public static <T extends PanacheEntityBase> Stream<T> stream(String query, Sort sort, Map<String, Object> params);
public static <T extends PanacheEntityBase> Stream<T> stream(String query, Parameters params);
public static <T extends PanacheEntityBase> Stream<T> stream(String query, Sort sort, Parameters params);
public static <T extends PanacheEntityBase> Stream<T> streamAll();
public static <T extends PanacheEntityBase> Stream<T> streamAll(Sort sort);Usage:
@Transactional
public void processAllUsers() {
Person.streamAll()
.filter(person -> person.status == PersonStatus.Active)
.forEach(this::processActivePerson);
}
@Transactional
public List<String> getActiveUserNames() {
return Person.stream("status", PersonStatus.Active)
.map(person -> person.name)
.collect(Collectors.toList());
}Methods for counting entities without loading them.
public static long count();
public static long count(String query, Object... params);
public static long count(String query, Map<String, Object> params);
public static long count(String query, Parameters params);Usage:
// Count all entities
long totalUsers = Person.count();
// Count with conditions
long activeUsers = Person.count("status", PersonStatus.Active);
long adultUsers = Person.count("age >= :age", Parameters.with("age", 18));Methods for saving entities to the database.
// Instance methods
public void persist();
public void persistAndFlush();
// Static batch methods
public static void persist(Iterable<?> entities);
public static void persist(Stream<?> entities);
public static void persist(Object firstEntity, Object... entities);Usage:
// Single entity persistence
Person person = new Person();
person.name = "John Doe";
person.persist(); // or person.persistAndFlush()
// Batch persistence
List<Person> people = Arrays.asList(person1, person2, person3);
Person.persist(people);
// Multiple entities
Person.persist(person1, person2, person3);Methods for removing entities from the database.
// Instance method
public void delete();
// Static methods
public static long deleteAll();
public static boolean deleteById(Object id);
public static long delete(String query, Object... params);
public static long delete(String query, Map<String, Object> params);
public static long delete(String query, Parameters params);Usage:
// Delete single entity
Person person = Person.findById(1L);
person.delete();
// Delete by ID
boolean deleted = Person.deleteById(1L);
// Bulk delete
long deletedCount = Person.delete("status", PersonStatus.Inactive);
Person.deleteAll(); // Delete all entities
// Delete with conditions
long deleted = Person.delete("age < :age AND status = :status",
Parameters.with("age", 18).and("status", PersonStatus.Inactive));Bulk update operations using HQL.
public static int update(String query, Object... params);
public static int update(String query, Map<String, Object> params);
public static int update(String query, Parameters params);Usage:
// Bulk updates
int updated = Person.update("status = ?1 where age >= ?2", PersonStatus.Adult, 18);
// With named parameters
int updated = Person.update("status = :newStatus where city = :city",
Parameters.with("newStatus", PersonStatus.Verified).and("city", "NYC"));Direct access to EntityManager and Session for advanced operations.
public static EntityManager getEntityManager();
public static Session getSession();
public static void flush();Usage:
// Direct EntityManager access
EntityManager em = Person.getEntityManager();
CriteriaBuilder cb = em.getCriteriaBuilder();
CriteriaQuery<Person> cq = cb.createQuery(Person.class);
// Hibernate Session access
Session session = Person.getSession();
Query<?> nativeQuery = session.createNativeQuery("SELECT * FROM person WHERE...");
// Manual flush
Person.flush();Panache supports simplified query syntax that automatically expands:
"order by name" → "from Person order by name""name" (with single param) → "from Person where name = ?""where age > 18" → "from Person where age > 18""age > 18 AND status = 'ACTIVE'" → "from Person where age > 18 AND status = 'ACTIVE'""set status = ?1" → "update from Person set status = ?1""status = ?1 where age > ?2" → "update from Person set status = ?1 where age > ?2""status" (with single param) → "delete from Person where status = ?""age < 18" → "delete from Person where age < 18"Reference named queries with # prefix:
List<Person> active = Person.list("#Person.findActive");Install with Tessl CLI
npx tessl i tessl/maven-io-quarkus--quarkus-hibernate-orm-panache