Quarkus Panache: Simplificando el Acceso a Datos
Introducción
Quarkus Panache es una extensión que simplifica el acceso a datos con Hibernate ORM. Proporciona dos patrones de programación que reducen significativamente el código boilerplate necesario para operaciones de base de datos.
¿Qué es Panache?
Panache es una capa de abstracción sobre Hibernate ORM que proporciona:
Métodos mágicos para queries comunes
Dos patrones de programación (Repository y Active Record)
API simplificada para operaciones CRUD
Menos código boilerplate
Dos Patrones de Panache
1. Repository Pattern
Similar a Spring Data, donde las entidades son POJOs simples y la lógica de acceso a datos está en repositorios:
@Entity
public class Hero extends PanacheEntityBase {
@Id
@GeneratedValue
private Long id;
private String name;
private Integer powerLevel;
// Getters y setters
}
@ApplicationScoped
public class HeroRepository implements PanacheRepository<Hero> {
// Métodos personalizados
public List<Hero> findPowerfulHeroes() {
return find("powerLevel >= ?1", 80).list();
}
}
Ventajas:
Separación clara entre entidad y lógica de acceso a datos
Fácil de testear (puedes mockear el repositorio)
Mejor para lógica compleja
Similar a Spring Data (familiar para muchos desarrolladores)
2. Active Record Pattern
Donde las entidades extienden PanacheEntity y tienen métodos directamente:
@Entity
public class Villain extends PanacheEntity {
public String name;
public Integer powerLevel;
// Métodos de instancia
public static List<Villain> findPowerful() {
return find("powerLevel >= ?1", 80).list();
}
}
Ventajas:
Más simple y directo
Menos clases (no necesitas repositorio)
Ideal para operaciones CRUD básicas
Código más compacto
Operaciones Comunes
Buscar
// Repository Pattern
heroRepository.findById(id);
heroRepository.find("name", "Superman");
heroRepository.find("powerLevel >= ?1", 80).list();
// Active Record Pattern
Villain.findById(id);
Villain.find("name", "Joker");
Villain.find("powerLevel >= ?1", 80).list();
Crear
// Repository Pattern
Hero hero = new Hero();
hero.setName("Superman");
hero.setPowerLevel(95);
heroRepository.persist(hero);
// Active Record Pattern
Villain villain = new Villain();
villain.name = "Joker";
villain.powerLevel = 80;
villain.persist();
Actualizar
// Repository Pattern
Hero hero = heroRepository.findById(id);
hero.setPowerLevel(98);
// Los cambios se persisten automáticamente en managed entities
// Active Record Pattern
Villain villain = Villain.findById(id);
villain.powerLevel = 85;
// Los cambios se persisten automáticamente
Eliminar
// Repository Pattern
heroRepository.deleteById(id);
heroRepository.delete(hero);
// Active Record Pattern
Villain.deleteById(id);
villain.delete();
Métodos Mágicos
Panache proporciona métodos que se generan automáticamente basándose en el nombre:
// Estos métodos se generan automáticamente:
findById(id)
find("field", value)
find("field = ?1", value)
find("field1 = ?1 and field2 = ?2", value1, value2)
list()
listAll()
count()
count("field = ?1", value)
delete("field = ?1", value)
update("field = ?1 where id = ?2", newValue, id)
Queries con Panache Query API
Queries Simples
// Por campo
find("name", "Superman")
// Con operador
find("powerLevel >= ?1", 80)
// Con múltiples condiciones
find("powerLevel >= ?1 and isActive = ?2", 80, true)
// Con ORDER BY
find("powerLevel >= ?1 order by powerLevel desc", 80)
// Con named parameters
find("powerLevel >= :minLevel", Parameters.with("minLevel", 80))
Paginación
// Primera página (10 items)
find("powerLevel >= ?1", 80).page(0, 10)
// Segunda página
find("powerLevel >= ?1", 80).page(1, 10)
// Navegar
PanacheQuery<Hero> query = find("powerLevel >= ?1", 80);
Page<Hero> firstPage = query.page(0, 10);
Page<Hero> secondPage = query.page(1, 10);
Proyecciones
// Seleccionar campos específicos
find("select name, powerLevel from Hero where powerLevel >= ?1", 80)
Comparación de Patrones
| Característica | Repository Pattern | Active Record Pattern |
| Separación de responsabilidades | ✅ Alta | ⚠️ Media |
| Testabilidad | ✅ Fácil de mockear | ⚠️ Más difícil |
| Simplicidad | ⚠️ Más clases | ✅ Menos código |
| Lógica compleja | ✅ Mejor | ⚠️ Puede ser confuso |
| Operaciones CRUD básicas | ✅ Bueno | ✅ Excelente |
| Familiaridad | ✅ Similar a Spring Data | ⚠️ Menos común |
Ejemplo Completo: Repository Pattern
@Entity
public class Hero extends PanacheEntityBase {
@Id
@GeneratedValue
private Long id;
private String name;
private Integer powerLevel;
private Boolean isActive = true;
// Getters y setters
}
@ApplicationScoped
public class HeroRepository implements PanacheRepository<Hero> {
public List<Hero> findPowerfulHeroes(int minLevel) {
return find("powerLevel >= ?1 order by powerLevel desc", minLevel).list();
}
public List<Hero> findActiveHeroes() {
return find("isActive = true").list();
}
public Page<Hero> findHeroesPaginated(int page, int size) {
return findAll().page(page, size);
}
public long countPowerful(int minLevel) {
return count("powerLevel >= ?1", minLevel);
}
}
Ejemplo Completo: Active Record Pattern
@Entity
public class Villain extends PanacheEntity {
public String name;
public Integer powerLevel;
public Boolean isActive = true;
// Métodos estáticos para queries
public static List<Villain> findPowerful(int minLevel) {
return find("powerLevel >= ?1 order by powerLevel desc", minLevel).list();
}
public static List<Villain> findActive() {
return find("isActive = true").list();
}
// Métodos de instancia
public void activate() {
this.isActive = true;
persist(); // O simplemente modificar si está managed
}
public void deactivate() {
this.isActive = false;
persist();
}
}
Cuándo Usar Cada Patrón
Usa Repository Pattern cuando:
Necesitas separación clara de responsabilidades
Tienes lógica de acceso a datos compleja
Quieres fácil testabilidad
Trabajas en equipo grande (mejor organización)
Usa Active Record Pattern cuando:
Tienes operaciones CRUD simples
Quieres menos código
Trabajas en proyectos pequeños
Prefieres simplicidad sobre organización
Ventajas de Panache
Menos Código: Reduce significativamente el boilerplate
Métodos Mágicos: Generación automática de métodos comunes
Type-Safe: Queries type-safe con validación en tiempo de compilación
Flexible: Puedes usar ambos patrones en el mismo proyecto
Performance: Optimizado para Quarkus
Integración con JPA
Panache está construido sobre Hibernate ORM, por lo que:
Todas las características de JPA están disponibles
Puedes usar JPQL cuando necesites
Las relaciones funcionan igual
Los lifecycle callbacks funcionan
Ejemplo Completo
Nuestro demo muestra:
Repository Pattern completo con HeroRepository
Active Record Pattern completo con VillainEntity
Comparación de ambos patrones
Queries complejas con Panache Query API
Paginación y proyecciones
Conclusión
Quarkus Panache simplifica enormemente el acceso a datos. Tanto el Repository Pattern como el Active Record Pattern tienen sus ventajas, y puedes elegir el que mejor se adapte a tu proyecto o usar ambos según necesites.




