# Jakarta Persistence (JPA) en Quarkus: Acceso a Datos con EntityManager

## **Introducción**

Jakarta Persistence (JPA) es la especificación estándar para acceso a datos relacionales en Java. Quarkus implementa JPA completamente a través de Hibernate ORM, proporcionando todas las características de la especificación.

## **¿Qué es JPA?**

JPA proporciona una API estándar para mapear objetos Java a tablas de base de datos relacionales. Permite trabajar con objetos en lugar de SQL directo, aunque también soporta SQL cuando es necesario.

## **EntityManager: El Corazón de JPA**

El `EntityManager` es la interfaz principal para interactuar con la base de datos:

```go
@Inject
EntityManager entityManager;

@Transactional
public Hero createHero(Hero hero) {
    entityManager.persist(hero);
    entityManager.flush();
    return hero;
}
```

## **Operaciones Básicas**

### **CRUD Operations**

```go
// Create
entityManager.persist(hero);

// Read
Hero hero = entityManager.find(Hero.class, id);

// Update
hero.setPowerLevel(95);
entityManager.merge(hero);

// Delete
entityManager.remove(hero);
```

### **Métodos Avanzados**

```go
// Obtener referencia lazy
Hero hero = entityManager.getReference(Hero.class, id);

// Refrescar desde BD
entityManager.refresh(hero);

// Desvincular del contexto
entityManager.detach(hero);

// Verificar si está gestionada
boolean isManaged = entityManager.contains(hero);

// Forzar sincronización
entityManager.flush();

// Limpiar contexto
entityManager.clear();
```

## **Named Queries**

Las Named Queries se definen en las entidades y se validan en tiempo de compilación:

```go
@Entity
@NamedQueries({
    @NamedQuery(
        name = "Hero.findAll",
        query = "SELECT h FROM Hero h ORDER BY h.name"
    ),
    @NamedQuery(
        name = "Hero.findByPowerLevel",
        query = "SELECT h FROM Hero h WHERE h.powerLevel >= :minLevel"
    )
})
public class Hero {
    // ...
}

// Uso
TypedQuery<Hero> query = entityManager.createNamedQuery("Hero.findAll", Hero.class);
List<Hero> heroes = query.getResultList();
```

## **JPQL (Java Persistence Query Language)**

JPQL permite escribir queries dinámicas usando sintaxis similar a SQL pero orientada a objetos:

```go
String jpql = "SELECT h FROM Hero h WHERE h.powerLevel >= :minLevel";
TypedQuery<Hero> query = entityManager.createQuery(jpql, Hero.class);
query.setParameter("minLevel", 80);
List<Hero> heroes = query.getResultList();
```

### **JOIN FETCH (Evitar N+1)**

```go
String jpql = "SELECT DISTINCT h FROM Hero h LEFT JOIN FETCH h.missions";
TypedQuery<Hero> query = entityManager.createQuery(jpql, Hero.class);
List<Hero> heroes = query.getResultList();
```

## **Criteria API**

La Criteria API permite construir queries type-safe programáticamente:

```go
CriteriaBuilder cb = entityManager.getCriteriaBuilder();
CriteriaQuery<Hero> query = cb.createQuery(Hero.class);
Root<Hero> hero = query.from(Hero.class);

Predicate powerPredicate = cb.greaterThanOrEqualTo(hero.get("powerLevel"), 80);
query.where(powerPredicate);
query.orderBy(cb.desc(hero.get("powerLevel")));

TypedQuery<Hero> typedQuery = entityManager.createQuery(query);
List<Hero> heroes = typedQuery.getResultList();
```

## **Relaciones entre Entidades**

### **OneToMany**

```go
@Entity
public class Hero {
    @OneToMany(mappedBy = "hero", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
    private List<Mission> missions;
}
```

### **ManyToOne**

```go
@Entity
public class Mission {
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "hero_id", nullable = false)
    private Hero hero;
}
```

## **Lifecycle Callbacks**

Los callbacks permiten ejecutar código en diferentes momentos del ciclo de vida:

```go
@Entity
public class Hero {
    @PrePersist
    protected void onCreate() {
        createdAt = LocalDateTime.now();
    }
    
    @PreUpdate
    protected void onUpdate() {
        updatedAt = LocalDateTime.now();
    }
    
    @PostLoad
    protected void onLoad() {
        // Inicializar colecciones lazy
    }
}
```

## **Optimistic Locking**

El `@Version` permite implementar optimistic locking:

```go
@Entity
public class Hero {
    @Version
    private Long version;
}
```

## **Ejemplo Completo**

Nuestro demo muestra:

* EntityManager con todas sus operaciones
    
* Named Queries
    
* JPQL queries dinámicas
    
* Criteria API
    
* Relaciones OneToMany/ManyToOne
    
* Lifecycle callbacks
    
* Optimistic locking
    

## **Ventajas en Quarkus**

1. **Implementación Completa**: Todas las características de JPA
    
2. **Integración CDI**: EntityManager inyectable con @Inject
    
3. **Performance**: Hibernate optimizado para Quarkus
    
4. **Startup Rápido**: Procesamiento en tiempo de compilación
    

## **Conclusión**

JPA en Quarkus proporciona acceso completo a bases de datos relacionales con todas las características de la especificación. La integración con CDI y Transactions hace que sea muy fácil de usar.

## **Recursos**

* [Demo completo](file:///Users/josediaz/Projects/JoeDayz/jakartaee-2026/quarkus-demos/jpa/)
    
* [Quarkus Hibernate ORM Guide](https://quarkus.io/guides/hibernate-orm)
    
* [Jakarta Persistence Specification](https://jakarta.ee/specifications/persistence/)
