Mientras usaba Hibernate con Spring Boot JPA, noté que al intentar implementar un método de actualización en un artefacto de repositorio que extiende la interfaz CrudRepository de Spring, el objeto de entidad completo que se actualizará debe pasarse a dicho método de actualización. Intuitivamente, eso parecía un desperdicio y quería saber cuál es una forma limpia de hacer que Spring Data/JPA asuma que solo los valores pasados necesitan actualizarse y dejar intactos los que no se pasaron.
Este es el método de servicio tal como está ahora,
public void updateCustomer(Long id, Customer customer) throws Exception { customerRepository.save(customer); }En JPA, pasa la entidad y el marco determina qué propiedades ha cambiado. Si aún no sabía esto, le sugiero que dedique un poco más de tiempo a leer sobre los fundamentos de JPA. En la superficie, JPA parece fácil y accesible, pero si no comprende los principios en los que se basa, terminará dedicando mucho tiempo a depurar y buscar en Google para descifrar los mensajes de error.
Cuando se administra una entidad, JPA tomará una copia del objeto cuando se cargó y luego la comparará con la versión pasada para save/persist y determinará qué columnas deben actualizarse. Esto lo convierte en un modelo de desarrollador fácil de usar, donde (a menudo) no tiene que pensar en los cambios en sus entidades.
Puede pensar, como sugiere Rob, que cargar una sola entidad para cambiar una sola propiedad es un desperdicio, pero no siempre es así. Tanto EclipseLink como Hibernate usan un caché compartido (segundo nivel) de forma predeterminada, por lo que si una entidad ya se cargó, se puede cargar desde la memoria en lugar de la base de datos, y una vez que haya modificado la entidad, JPA compara dos objetos en la memoria y genera el SQL necesario para modificar columnas.
Algunas veces necesita optimizar su código JPA (pero solo cuando ha medido qué operaciones son lentas). Un escenario clásico es la eliminación/actualización masiva, donde no desea que JPA dedique tiempo a leer/copiar/administrar entidades que está eliminando/actualizando. En esos casos, puede usar consultas de eliminación o actualización, en lugar de cargar la entidad y llamar a EntityManager.remove() o modificar la entidad dentro de una transacción. Sin embargo, debe tener en cuenta que esto pasa por alto EntityListeners y las instrucciones en cascada, ya que solo se llaman para entidades administradas.