Actualización de Precios de Pizza con Spring Data JPA

Clase 20 de 25Curso de Java Spring Data JPA: Bases de Datos

Contenido del curso

Spring Data Repositories

Resumen

Cuando necesitas ejecutar operaciones de escritura como update, insert o delete directamente desde un repositorio de Spring Data JPA, la anotación @Query por sí sola no es suficiente. Es imprescindible combinarla con @Modifying para que Spring entienda que no se trata de una consulta de lectura. A continuación se explica paso a paso cómo construir esta funcionalidad, desde el DTO hasta el controlador, incluyendo el uso de Spring Expression Language (SpEL) para manejar parámetros de forma elegante.

¿Cómo crear un DTO para transferir los datos de actualización?

El primer paso es definir un objeto que encapsule la información necesaria para la operación. Un DTO (Data Transfer Object) es una clase cuyo único propósito es transportar datos entre capas de la aplicación sin lógica de negocio.

Dentro del paquete service.dto se crea la clase UpdatePizzaPriceDTO [0:43]:

  • Se anota con @Data de Lombok para generar automáticamente getters, setters y constructores.
  • Contiene dos atributos: pizzaId de tipo int y newPrice de tipo double.

Este enfoque mantiene la separación de responsabilidades y evita exponer directamente la entidad de base de datos.

¿Cómo escribir un @Query con @Modifying en el repositorio?

En PizzaRepository se define el método updatePrice anotado con @Query y marcado como nativeQuery = true [1:25]. La consulta SQL resultante es:

sql UPDATE pizza SET price = :#{#newPizzaPrice.newPrice} WHERE id_pizza = :#{#newPizzaPrice.pizzaId}

¿Qué es el Spring Expression Language dentro de @Query?

El SpEL (Spring Expression Language) permite acceder a propiedades internas de un objeto recibido como parámetro único [2:30]. En lugar de recibir cada campo por separado con @Param, se recibe el DTO completo y se utiliza la sintaxis especial:

  • :#{#nombreParametro.atributo} — los dos puntos inician la referencia, el numeral abre la expresión y entre llaves se coloca nuevamente el numeral seguido del nombre del parámetro y su propiedad.

Esta técnica es especialmente útil cuando una consulta necesita múltiples campos de un mismo objeto, ya que reduce la cantidad de parámetros en la firma del método.

¿Por qué es obligatoria la anotación @Modifying?

Un @Query sin @Modifying solo puede ejecutar sentencias SELECT [7:10]. Si intentas ejecutar un update, insert o delete sin esta anotación, Spring lanzará un error 500 indicando que la operación no está permitida. Al agregar @Modifying sobre el método del repositorio, Spring sabe que debe ejecutar la instrucción como una operación de escritura.

java @Modifying @Query(value = "UPDATE pizza SET price = :#{#newPizzaPrice.newPrice} " + "WHERE id_pizza = :#{#newPizzaPrice.pizzaId}", nativeQuery = true) void updatePrice(@Param("newPizzaPrice") UpdatePizzaPriceDTO newPizzaPrice);

¿Cómo conectar servicio, controlador y la anotación @Transactional?

En PizzaService se crea el método updatePrice que recibe el DTO y lo pasa directamente al repositorio [4:30]. Este método debe llevar la anotación @Transactional de org.springframework.transaction.annotation — no la de Jakarta. Sin esta anotación, Spring también lanza un error 500 porque las operaciones de escritura requieren un contexto transaccional.

java @Transactional public void updatePrice(UpdatePizzaPriceDTO dto) { pizzaRepository.updatePrice(dto); }

En el controlador se expone un endpoint PUT en /price [5:05]:

  • Se recibe el DTO como @RequestBody.
  • Se verifica que la pizza exista usando existsById con el pizzaId del DTO.
  • Si existe, se invoca al servicio y se retorna un 200 OK.
  • Si no existe, se retorna un 400 Bad Request.

Al probar en Postman, se envía un JSON con pizzaId y newPrice. La pizza 7, que originalmente costaba 19.5, se actualiza primero a 19.99 y luego a 20 [6:15]. En la consola se observan dos consultas: el COUNT del existsById y luego el UPDATE construido en el repositorio.

Recuerda siempre dejar un espacio al final de cada línea dentro de consultas multilínea en @Query, para que Java no concatene mal el SQL resultante. ¿Has utilizado SpEL en tus repositorios? Comparte tu experiencia con esta técnica.