Bueno, la pregunta lo dice todo. Usando JPARepository, ¿cómo actualizo una entidad?
JPARepository solo tiene un método de guardar , que no me dice si es crear o actualizar en realidad. Por ejemplo, insertar un simple objeto al usuario de base de datos, que tiene tres campos: firstname
, lastname
y 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 aquí todo bien. Ahora quiero actualizar a este usuario, por ejemplo, cambiar su edad. Para este propósito, podría usar una consulta, QueryDSL o NamedQuery, lo que sea. Pero, considerando que solo quiero usar spring-data-jpa y el JPARepository, ¿cómo le digo que en lugar de una inserción 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 realmente IGUALES y que se supone que la entidad existente debe actualizarse? Anular iguales no resolvió este problema.
fuente
Respuestas:
La identidad de las entidades se define por sus claves principales. Dado que
firstname
ylastname
no son partes de la clave primaria, no puede decirle a JPA que trateUser
s con los mismosfirstname
syslastname
iguales si tienenuserId
s diferentes .Por lo tanto, si desea actualizar un
User
identificado por sufirstname
ylastname
, debe buscarloUser
mediante una consulta y luego cambiar los campos apropiados del objeto que encontró. Estos cambios se transferirán automáticamente a la base de datos al final de la transacción, por lo que no necesita hacer nada para guardar estos cambios explícitamente.EDITAR:
Tal vez debería profundizar en la semántica general de JPA. Existen 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 API de persistencia: llama
insert
para insertar un objeto oupdate
para guardar un nuevo estado del objeto en la base de datos.Enfoque de unidad de trabajo . En este caso, tiene un conjunto de objetos gestionados por la biblioteca de persistencia. Todos los cambios que realice en estos objetos se transferirán automáticamente a la base de datos al final de la Unidad de trabajo (es decir, al final de la transacción actual en el caso típico). Cuando necesita insertar un nuevo registro en la base de datos, hace que se gestione el objeto correspondiente . Los objetos administrados se identifican por sus claves primarias, de modo que si crea un objeto con clave primaria predefinida administrada , se asociará con el registro de la base de datos de la misma identificación, y el estado de este objeto se propagará a ese registro automáticamente.
JPA sigue el último enfoque.
save()
en Spring Data JPA está respaldado pormerge()
JPA simple, por lo tanto, hace que su entidad se administre como se describe anteriormente. Significa que llamarsave()
a un objeto con una identificación predefinida actualizará el registro de la base de datos correspondiente en lugar de insertar uno nuevo, y también explica por quésave()
no se llamacreate()
.fuente
extends CrudRepository<MyEntity, Integer>
lugar deextends CrudRepository<MyEntity, String>
como debería haberlo hecho. ¿Eso ayuda? Sé que esto es casi un año después. Espero que ayude a alguien más.Dado que la respuesta de @axtavt se centra en
JPA
nospring-data-jpa
Para actualizar una entidad mediante consultas, entonces 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
.@Query
es para la definición de consulta personalizada y@Modifying
es por decirspring-data-jpa
que esta consulta es una operación de actualización y requiereexecuteUpdate()
noexecuteQuery()
.Puede especificar otros tipos de devolución:
int
- el número de registros que se actualizan.boolean
- verdadero si hay un registro que se está actualizando. De lo contrario, falso.Nota : Ejecute este código en una transacción .
fuente
To update an entity by querying then saving is not efficient
Estas no son las dos únicas opciones. Hay una manera de especificar id y obtener el objeto de fila sin consultarlo. Si hace unrow = repo.getOne(id)
y luegorow.attr = 42; repo.save(row);
y mira los registros, verá solo la consulta de actualización.Simplemente puede usar esta función con la función save () JPA, pero el objeto enviado como parámetro debe contener una identificación existente en la base de datos; de lo contrario, no funcionará, porque save () cuando enviamos un objeto sin identificación, agrega directamente una fila en base de datos, pero si enviamos un objeto con una identificación existente, cambia las columnas que ya se encuentran en la base de datos.
fuente
Como lo que 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 extender / implementar de
CrudRepository<T,ID>
,Ok, verifiquemos la
save()
implementación enSimpleJpaRepository<T, ID>
,Como puede ver, verificará si la ID existe o no en primer lugar, si la entidad ya está allí, solo se realizará la actualización por
merge(entity)
método y, de lo contrario, se insertará un nuevo registro porpersist(entity)
método.fuente
Usando spring-data-jpa
save()
, estaba teniendo el mismo problema que @DtechNet. Quiero decir que cada unosave()
estaba creando un nuevo objeto en lugar de una actualización. Para resolver esto, tuve que agregar elversion
campo a la entidad y la tabla relacionada.fuente
Así es como resolví el problema:
fuente
@Transaction
método anterior para varias solicitudes de db. Y en este caso no es necesariouserRepository.save(inbound);
, los cambios se enjuagan automáticamente.El
save()
método Spring Data lo ayudará a realizar ambas cosas: agregar un nuevo elemento y actualizar un elemento existente.Solo llama al
save()
y disfruta de la vida :))fuente
Id
lo guardaré, ¿cómo puedo evitar guardar un nuevo registro?fuente
Para este propósito particular, se puede introducir una clave compuesta como esta:
Cartografía:
Aquí está cómo usarlo:
JpaRepository se vería así:
Luego, puede usar el siguiente modismo: acepte DTO con información de usuario, extraiga el nombre y el nombre y cree UserKey, luego cree una UserEntity con esta clave compuesta y luego invoque Spring Data save (), que debería resolver todo por usted.
fuente