Skip to main content

Command Palette

Search for a command to run...

Quarkus Panache: Simplificando el Acceso a Datos

Updated
5 min read

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ísticaRepository PatternActive 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

  1. Menos Código: Reduce significativamente el boilerplate

  2. Métodos Mágicos: Generación automática de métodos comunes

  3. Type-Safe: Queries type-safe con validación en tiempo de compilación

  4. Flexible: Puedes usar ambos patrones en el mismo proyecto

  5. 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.

Recursos

More from this blog

JoeDayz

52 posts

Community Guy | Java Champion | AWS Architect | Software Architect