¿Cómo actualizo una entidad usando spring-data-jpa?
Bueno, la pregunta lo dice prácticamente todo. Usando JPARepository, ¿cómo actualizo una entidad?
JPARepository solo tiene un método para guardar , que no me dice si realmente se está creando o actualizando. Por ejemplo, inserto un Objeto simple en el Usuario de la base de datos, que tiene tres campos : y firstname
:lastname
age
@Entity
public class User {
private String firstname;
private String lastname;
//Setters and getters for age omitted, but they are the same as with firstname and lastname.
private int age;
@Column
public String getFirstname() {
return firstname;
}
public void setFirstname(String firstname) {
this.firstname = firstname;
}
@Column
public String getLastname() {
return lastname;
}
public void setLastname(String lastname) {
this.lastname = lastname;
}
private long userId;
@Id
@GeneratedValue(strategy=GenerationType.AUTO)
public long getUserId(){
return this.userId;
}
public void setUserId(long userId){
this.userId = userId;
}
}
Luego simplemente llamo save()
, que en este punto es en realidad una inserción en la base de datos:
User user1 = new User();
user1.setFirstname("john"); user1.setLastname("dew");
user1.setAge(16);
userService.saveUser(user1);// This call is actually using the JPARepository: userRepository.save(user);
Hasta ahora, todo bien. Ahora quiero actualizar este usuario, digamos cambiar su edad. Para ello podría utilizar una Consulta, ya sea QueryDSL o NamedQuery, lo que sea. Pero, considerando que solo quiero usar spring-data-jpa y JPARepository, ¿cómo le digo que en lugar de insertar quiero hacer una actualización?
Específicamente, ¿cómo le digo a spring-data-jpa que los usuarios con el mismo nombre de usuario y nombre son en realidad IGUAL y que se supone que la entidad existente debe actualizarse? Anular iguales no resolvió este problema.
La identidad de las entidades está definida por sus claves primarias. Dado que firstname
y lastname
no son partes de la clave principal, no puede decirle a JPA que trate User
los mensajes con los mismos firstname
sys lastname
como iguales si tienen userId
s diferentes.
Entonces, si desea actualizar un objeto User
identificado por su firstname
y lastname
, debe encontrarlo User
mediante una consulta y luego cambiar los campos apropiados del objeto que encontró. Estos cambios se descargarán automáticamente en la base de datos al final de la transacción, por lo que no necesita hacer nada para guardar estos cambios explícitamente.
EDITAR:
Quizás debería dar más detalles sobre la semántica general de JPA. Hay dos enfoques principales para el diseño de API de persistencia:
enfoque de inserción/actualización . Cuando necesite modificar la base de datos, debe llamar explícitamente a los métodos de la API de persistencia: llama
insert
para insertar un objeto oupdate
para guardar el nuevo estado del objeto en la base de datos.Enfoque de unidad de trabajo . En este caso tienes un conjunto de objetos administrados por la biblioteca de persistencia. Todos los cambios que realice en estos objetos se descargarán automáticamente en la base de datos al final de la Unidad de trabajo (es decir, al final de la transacción actual en un caso típico). Cuando necesite insertar un nuevo registro en la base de datos, haga que se administre el objeto correspondiente . Los objetos administrados se identifican por sus claves principales, de modo que si crea un objeto con una clave principal predefinida administrada , se asociará con el registro de la base de datos con la misma identificación y el estado de este objeto se propagará a ese registro automáticamente.
JPA sigue este último enfoque. save()
en Spring Data, JPA está respaldado por merge()
JPA simple, por lo tanto, hace que su entidad se administre como se describe anteriormente. Significa que llamar save()
a un objeto con una identificación predefinida actualizará el registro de base de datos correspondiente en lugar de insertar uno nuevo, y también explica por qué save()
no se llama create()
.
Dado que la respuesta de @axtavt se centra en JPA
nospring-data-jpa
Actualizar una entidad mediante una consulta y luego guardar no es eficiente porque requiere dos consultas y posiblemente la consulta puede ser bastante costosa ya que puede unir otras tablas y cargar cualquier colección que tenga.fetchType=FetchType.EAGER
Spring-data-jpa
admite la operación de actualización.
Debe definir el método en la interfaz del Repositorio y anotarlo con @Query
y @Modifying
.
@Modifying
@Query("update User u set u.firstname = ?1, u.lastname = ?2 where u.id = ?3")
void setUserInfoById(String firstname, String lastname, Integer userId);
@Query
es para definir una consulta personalizada y @Modifying
es para indicar spring-data-jpa
que esta consulta es una operación de actualización y que executeUpdate()
no requiere executeQuery()
.
Puede especificar el tipo de devolución como int
, teniendo la cantidad de registros que se actualizan.
Nota : Ejecute este código en una Transacción .
Como ya han mencionado otros, el save()
mismo contiene operaciones de creación y actualización.
Solo quiero agregar un suplemento sobre lo que hay detrás del save()
método.
En primer lugar, veamos la jerarquía de extensión/implementación de CrudRepository<T,ID>
,
Ok, verifiquemos la save()
implementación en SimpleJpaRepository<T, ID>
,
@Transactional
public <S extends T> S save(S entity) {
if (entityInformation.isNew(entity)) {
em.persist(entity);
return entity;
} else {
return em.merge(entity);
}
}
Como puede ver, primero verificará si la ID existe o no, si la entidad ya está allí, solo se actualizará por merge(entity)
método y, en caso contrario, se insertará un nuevo registro por persist(entity)
método.
El método de datos de primavera save()
le ayudará a realizar ambas cosas: agregar un nuevo elemento y actualizar un elemento existente.
Simplemente llama save()
y disfruta de la vida :))