Eh bien, la question dit à peu près tout. Utilisation de JPARepository, comment mettre à jour une entité?
JPARepository a seulement une méthode save, ce qui ne me dit pas si c'est créer ou mettre à jour. Par exemple, j'insère un objet simple dans la base de données Utilisateur, qui comporte trois champs: prénom et nom de famille et âge:
@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;
}
}
Ensuite, je simplement "enregistrer", qui à ce stade est un insert en fait:
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);
Ok tout va bien. Maintenant, je veux mettre à jour cet utilisateur, disons changer son âge. Eh bien, je pourrais utiliser une requête pour cela, QueryDSL ou NamedQuery, peu importe. Mais, étant donné que je veux juste utiliser spring-data-jpa et le JPARepository, comment puis-je lui dire qu'au lieu d'un insert, je veux faire une mise à jour?
Plus précisément, comment puis-je dire à spring-data-jpa que les utilisateurs qui ont le même nom d'utilisateur et le même prénom sont en réalité EQUAL et qu'il est supposé mettre à jour l'entité. Remplacer les égaux n'a pas fonctionné.
Merci!
L'identité des entités est définie par leurs clés primaires. Puisque firstname
et lastname
ne font pas partie de la clé primaire, vous ne pouvez pas dire à JPA de traiter User
s avec les mêmes firstname
s et lastname
s de manière égale s'ils ont différent userId
s.
Ainsi, si vous souhaitez mettre à jour une User
identifiée par ses firstname
et lastname
, vous devez rechercher cette User
par une requête, puis modifier les champs appropriés de l'objet. votre trouvé. Ces modifications seront automatiquement transférées dans la base de données à la fin de la transaction, de sorte que vous n'aurez rien à faire pour enregistrer ces modifications explicitement.
EDIT:
Je devrais peut-être élaborer sur la sémantique générale de l'APP. Il existe deux approches principales pour la conception des API de persistance:
approche insertion/mise à jour. Lorsque vous devez modifier la base de données, vous devez appeler explicitement les méthodes de l'API de persistance: appelez insert
pour insérer un objet ou update
pour enregistrer le nouvel état de l'objet dans la base de données.
approche par unité de travail. Dans ce cas, vous avez un ensemble d'objets gérés par la bibliothèque de persistance. Toutes les modifications que vous apportez à ces objets seront automatiquement vidées dans la base de données à la fin de l'unité de travail (c'est-à-dire à la fin de la transaction en cours dans le cas typique). Lorsque vous devez insérer un nouvel enregistrement dans la base de données, vous rendez l'objet correspondant géré . Les objets gérés sont identifiés par leurs clés primaires. Ainsi, si vous créez un objet avec une clé primaire prédéfinie , elle est gérée , il sera associé à l'enregistrement de la base de données du même identifiant et l'état de cet objet sera propagé à cet enregistrement automatiquement.
JPA suit l'approche ultérieure. save()
dans Spring Data JPA s'appuie sur merge()
en clair, par conséquent, il rend votre entité gérée comme décrit ci-dessus. Cela signifie que l'appel de save()
sur un objet avec un identifiant prédéfini mettra à jour l'enregistrement de base de données correspondant plutôt que d'en insérer un nouveau, et explique également pourquoi save()
ne s'appelle pas create()
.
Puisque la réponse de @axtavt se concentre sur JPA
pas spring-data-jpa
Mettre à jour une entité en interrogeant, l'enregistrement n'est pas efficace, car il nécessite deux interrogations. En outre, l'interrogation peut être assez coûteuse, car elle peut joindre d'autres tables et charger toutes les collections contenant fetchType=FetchType.EAGER
.
Spring-data-jpa
prend en charge l'opération de mise à jour.
Vous devez définir la méthode dans l'interface du référentiel et l'annoter avec @Query
et @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
sert à définir une requête personnalisée et @Modifying
signifie à spring-data-jpa
que cette requête est une opération de mise à jour et qu'elle nécessite executeUpdate()
pas executeQuery()
.
Vous pouvez simplement utiliser cette fonction avec la fonction JPA save (), mais l'objet envoyé en tant que paramètre doit contenir un identifiant existant dans la base, sinon cela ne fonctionnera pas, car save () lorsque nous envoyons un objet sans identifiant, il ajoute directement une ligne dans base de données, mais si nous envoyons un objet avec un identifiant existant, les colonnes déjà trouvées dans la base de données sont modifiées.
public void updateUser(Userinfos u) {
User userFromDb = userRepository.findById(u.getid());
// crush the variables of the object found
userFromDb.setFirstname("john");
userFromDb.setLastname("dew");
userFromDb.setAge(16);
userRepository.save(userFromDb);
}
Comme ce qui a déjà été mentionné par d'autres, la save()
contient à la fois les opérations de création et de mise à jour.
Je veux juste ajouter un complément sur ce qui se cache derrière la méthode save()
.
Tout d’abord, voyons la hiérarchie expand/Implement du CrudRepository<T,ID>
,
Ok, vérifions l'implémentation de save()
à 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);
}
}
Comme vous pouvez le voir, il va d'abord vérifier si l'ID existe ou non. Si l'entité est déjà présente, seule la mise à jour se fera par la méthode merge(entity)
et si c'est le cas, un nouvel enregistrement est inséré par persist(entity)
méthode.
En utilisant spring-data-jpa save (), je rencontrais le même problème que @DtechNet. Je veux dire que chaque save () créait un nouvel objet au lieu d'une mise à jour. Pour résoudre ce problème, je devais ajouter "version" classée dans l'entité et la table associée.
Voici comment j'ai résolu le problème:
User inbound = ...
User existing = userRepository.findByFirstname(inbound.getFirstname());
if(existing != null) inbound.setId(existing.getId());
userRepository.save(inbound);
la méthode des données de ressort save()
vous aidera à effectuer les tâches suivantes: ajouter un nouvel élément et mettre à jour un élément existant.
Il suffit d'appeler la save()
et de profiter de la vie :))
public void updateLaserDataByHumanId(String replacement, String humanId) {
List<LaserData> laserDataByHumanId = laserDataRepository.findByHumanId(humanId);
laserDataByHumanId.stream()
.map(en -> en.setHumanId(replacement))
.collect(Collectors.toList())
.forEach(en -> laserDataRepository.save(en));
}
Plus précisément, comment puis-je dire à spring-data-jpa que les utilisateurs qui ont le même nom d'utilisateur et le même prénom sont en réalité EQUAL et qu'il est supposé mettre à jour l'entité. Remplacer les égaux n'a pas fonctionné.
Dans ce but particulier, on peut introduire une clé composite comme celle-ci:
CREATE TABLE IF NOT EXISTS `test`.`user` (
`username` VARCHAR(45) NOT NULL,
`firstname` VARCHAR(45) NOT NULL,
`description` VARCHAR(45) NOT NULL,
PRIMARY KEY (`username`, `firstname`))
Cartographie:
@Embeddable
public class UserKey implements Serializable {
protected String username;
protected String firstname;
public UserKey() {}
public UserKey(String username, String firstname) {
this.username = username;
this.firstname = firstname;
}
// equals, hashCode
}
Voici comment l'utiliser:
@Entity
public class UserEntity implements Serializable {
@EmbeddedId
private UserKey primaryKey;
private String description;
//...
}
JpaRepository ressemblerait à ceci:
public interface UserEntityRepository extends JpaRepository<UserEntity, UserKey>
Ensuite, vous pouvez utiliser les éléments suivants idiom: accepter DTO avec informations utilisateur, extraire nom et prénom et créer une clé utilisateur, puis créer une UserEntity avec cette clé composite, puis appeler Spring Data save () qui doit tout trier. pour toi.