Si bien el patrón repository será una de las cosas más esperadas para personas que vengan de frameworks como Spring, para gente que haya trabajado con frameworks como Django, Ruby on Rails o Laravel, tal vez tengan más costumbre con el patrón Active Record.
Active Record es un patrón de diseño de sistemas de acceso a datos en los cuales el propio modelo de datos lleva los métodos que le permiten a esa misma instancia persistirse a sí misma, actualizarse o borrarse. Eso hace que no haya que usar repositorios. Si queremos persistir una instancia nueva de una clase, únicamente llamamos al método .persist() de la misma:
private void crearLibro() {
Book b = new Book();
b.setTitle("El título de mi libro");
b.setDescription("La descripción de mi libro");
b.setNumPages(240);
// El siguiente método guardará el libro b en base de datos
// con la información que le hemos dado.
b.persist();
}
Para hacer esto en Panache, lo que tendremos que hacer es declarar nuestros modelos de datos como clases que extiendan de la clase PanacheEntity. Por ejemplo, para crear una clase llamada Book que sea un modelo persistente, podemos usar el siguiente código:
import jakarta.persistence.Entity;
import io.quarkus.hibernate.orm.panache.PanacheEntity;
@Entity
public class Book extends PanacheEntity {
private String title;
private String description;
private int numPages;
private LocalDate pubDate;
public Book() {
// Sigue siendo necesario tener un constructor vacío.
// Si es el único constructor, entonces no es obligatorio
// ponerlo de acuerdo con las reglas del lenguaje Java.
}
public Book(String title, String description) {
this.title = title;
this.description = description;
}
}
Si vienes de leer o ver el capítulo anterior, donde hablaba de entidades JPA y de repositorios, tal vez te suene el código. Voy a explicar algunas diferencias.
Para poder tener una entidad Active Record en Panache ORM, esa entidad tiene que extender de la clase PanacheEntity. Esta clase la encontramos en el paquete io.quarkus.hibernate.orm.panache. Se trata de una clase que contiene todos los métodos que de otro modo estarían en el repositorio, como persist, delete... Estos métodos son de instancia y por lo tanto persistir un registro luego es tan fácil como llamar al método persist() sobre la instancia de la entidad que queremos persistir.
PanacheEntity también trae el resto de métodos estáticos que de otro modo estarían en el repositorio. Por ejemplo, podemos seguir buscando libros por su identificador. Sin embargo, ahora usaríamos métodos estáticos de la propia clase entidad que vayamos a usar:
Book foundBook = Book.findById(5);
List<Book> allBooks = Book.listAll();
Una PanacheEntity no necesita declarar un campo de tipo identificador. Esta es la principal diferencia con respecto al uso del patrón Repository. No hay que poner ningún atributo que tenga un campo anotado como @Id @GeneratedValue, porque ese campo ya viene en el PanacheEntity y será implícito, junto con sus getters y sus setters. Sin embargo, sigue siendo necesario especificar que esa clase es una entidad de JPA, así que hay que seguir poniendo la anotación @Entity a la clase, aunque ya extienda de PanacheEntity. Quitando estas dos consideraciones, se va a comportar exactamente igual que una entidad gestionada mediante repositorios.
Como en el patrón Active Record la clase es rica y tiene todas las responsabilidades de acceso a datos, no es necesario un repositorio. Sin embargo, en algunos casos tal vez compense crear servicios propios para facilitar la creación, recuperación, modificación o eliminación de datos.
Puedes ver un ejemplo de uso en el gist https://gist.github.com/danirod/6ac5d6d42bb93145547788907b1165ee, donde he adjuntado una entidad completa que usa Active Record y un recurso que es capaz de insertar libros y de recuperar la lista de libros previamente insertada.