Bem, a pergunta praticamente diz tudo. Usando o JPARepository, como atualizo uma entidade?
O JPARepository possui apenas um método de salvamento , que não informa se é realmente criado ou atualizado. Por exemplo, eu inserir um simples objeto para o usuário do banco de dados, que tem três campos: firstname
, lastname
e 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;
}
}
Então eu simplesmente chamo save()
, que neste momento é realmente uma inserção no banco de dados:
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);
Por enquanto, tudo bem. Agora eu quero atualizar este usuário, digamos, mudar sua idade. Para esse propósito, eu poderia usar uma consulta, QueryDSL ou NamedQuery, qualquer que seja. Mas, considerando que eu só quero usar o spring-data-jpa e o JPARepository, como posso dizer que, em vez de uma inserção, quero fazer uma atualização?
Especificamente, como digo ao spring-data-jpa que os usuários com o mesmo nome de usuário e nome são realmente iguais e que a entidade existente deveria ser atualizada? Substituir iguais não resolveu esse problema.
fonte
Respostas:
A identidade das entidades é definida por suas chaves primárias. Desde
firstname
elastname
não são partes da chave primária, você não pode dizer JPA para deleiteUser
s com os mesmosfirstname
s elastname
s como iguais se eles têm diferentesuserId
s.Portanto, se você quiser atualizar um
User
identificado por itsfirstname
elastname
, precisará encontrá-loUser
por uma consulta e depois alterar os campos apropriados do objeto encontrado. Essas alterações serão liberadas no banco de dados automaticamente no final da transação, para que você não precise fazer nada para salvar essas alterações explicitamente.EDITAR:
Talvez eu deva elaborar a semântica geral da JPA. Existem duas abordagens principais para o design de APIs de persistência:
abordagem de inserção / atualização . Quando você precisar modificar o banco de dados, chame métodos de API de persistência explicitamente: ligue
insert
para inserir um objeto ouupdate
salve o novo estado do objeto no banco de dados.Abordagem por unidade de trabalho . Nesse caso, você tem um conjunto de objetos gerenciados pela biblioteca de persistência. Todas as alterações feitas nesses objetos serão liberadas no banco de dados automaticamente no final da Unidade de trabalho (ou seja, no final da transação atual, no caso típico). Quando você precisa inserir um novo registro no banco de dados, você gerencia o objeto correspondente . Os objetos gerenciados são identificados por suas chaves primárias, para que, se você criar um objeto com chave primária predefinida gerenciada , ele será associado ao registro do banco de dados do mesmo ID e o estado desse objeto será propagado automaticamente para esse registro.
A JPA segue a última abordagem.
save()
no Spring Data, o JPA é suportado pelomerge()
JPA comum, portanto, ele gerencia sua entidade como descrito acima. Isso significa que a chamadasave()
de um objeto com ID predefinido atualizará o registro do banco de dados correspondente em vez de inserir um novo e também explica por quesave()
não é chamadocreate()
.fonte
extends CrudRepository<MyEntity, Integer>
vez deextends CrudRepository<MyEntity, String>
como deveria. Isso ajuda? Eu sei que isso é quase um ano depois. Espero que isso ajude mais alguém.Como a resposta de @axtavt se concentra em
JPA
nãospring-data-jpa
Para atualizar uma entidade consultando, o salvamento não é eficiente, pois requer duas consultas e, possivelmente, a consulta pode ser bastante cara, pois pode ingressar em outras tabelas e carregar quaisquer coleções que tenham
fetchType=FetchType.EAGER
Spring-data-jpa
suporta operação de atualização.Você precisa definir o método na interface do repositório. E anotou-o com
@Query
e@Modifying
.@Query
é para definir consulta personalizada e@Modifying
é para dizerspring-data-jpa
que esta consulta é uma operação de atualização e que exigeexecuteUpdate()
nãoexecuteQuery()
.Você pode especificar outros tipos de retorno:
int
- o número de registros que estão sendo atualizados.boolean
- true se houver um registro sendo atualizado. Caso contrário, false.Nota : Execute este código em uma transação .
fonte
To update an entity by querying then saving is not efficient
essas não são as únicas duas opções. Existe uma maneira de especificar a identificação e obter o objeto de linha sem consultá-lo. Se você fizer umrow = repo.getOne(id)
e depoisrow.attr = 42; repo.save(row);
assistir os logs, verá apenas a consulta de atualização.Você pode simplesmente usar essa função com save () JPAfunction, mas o objeto enviado como parâmetro deve conter um ID existente no banco de dados, caso contrário não funcionará, porque save () quando enviamos um objeto sem ID, ele adiciona diretamente uma linha no banco de dados, mas se enviarmos um objeto com um ID existente, ele mudará as colunas já encontradas no banco de dados.
fonte
Como o que já foi mencionado por outros, o
save()
próprio contém operações de criação e atualização.Eu só quero adicionar um complemento sobre o que está por trás do
save()
método.Primeiro, vamos ver a hierarquia de extensão / implementação do
CrudRepository<T,ID>
,Ok, vamos verificar a
save()
implementação emSimpleJpaRepository<T, ID>
,Como você pode ver, ele verificará se o ID existe ou não, primeiro, se a entidade já estiver lá, apenas a atualização ocorrerá por
merge(entity)
método e, caso contrário, um novo registro será inserido porpersist(entity)
método.fonte
Usando spring-data-jpa
save()
, eu estava tendo o mesmo problema que o @DtechNet. Quero dizer que todossave()
estavam criando um novo objeto em vez de atualizar. Para resolver isso, tive que adicionar umversion
campo à entidade e à tabela relacionada.fonte
Foi assim que resolvi o problema:
fonte
@Transaction
método acima para várias solicitações de banco de dados. Nesse caso, não há necessidade deuserRepository.save(inbound);
alterações automaticamente.O
save()
método de dados spring ajudará você a executar os dois: adicionar novo item e atualizar um item existente.Basta ligar para
save()
e aproveitar a vida :))fonte
Id
, ele será salvo, como posso evitar salvar um novo registro.fonte
Para este fim específico, pode-se introduzir uma chave composta como esta:
Mapeamento:
Aqui está como usá-lo:
JpaRepository ficaria assim:
Então, você pode usar o seguinte idioma: aceite o DTO com informações do usuário, extraia o nome e o primeiro nome e crie UserKey, crie uma UserEntity com essa chave composta e invoque o Spring Data save () que deve resolver tudo para você.
fonte