Eh bien, la question dit à peu près tout. Utilisation de JPARepository, comment mettre à jour une entité?
JPARepository n'a qu'une méthode de sauvegarde , qui ne me dit pas s'il est réellement créé ou mis à jour. Par exemple, insérer un objet simple à la base de données utilisateur, qui a trois champs: firstname
, lastname
et 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;
}
}
Ensuite save()
, j'appelle simplement , qui à ce stade est en fait une insertion dans la base de données:
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);
Jusqu'ici tout va bien. Maintenant, je veux mettre à jour cet utilisateur, disons changer son âge. Pour cela, je pourrais utiliser une requête, QueryDSL ou NamedQuery, peu importe. Mais, étant donné que je veux juste utiliser spring-data-jpa et le référentiel JPAR, 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 avec le même nom d'utilisateur et le même prénom sont en fait EQUAL et que l'entité existante est censée être mise à jour? Le remplacement des égaux n'a pas résolu ce problème.
la source
Réponses:
L'identité des entités est définie par leurs clés primaires. Puisque
firstname
etlastname
ne font pas partie de la clé primaire, vous ne pouvez pas dire à JPA de traiterUser
s avec les mêmesfirstname
s etlastname
s comme égaux s'ils ont desuserId
s différents .Donc, si vous souhaitez mettre à jour un
User
identifié par sonfirstname
etlastname
, vous devez le trouverUser
par une requête, puis modifier les champs appropriés de l'objet que vous avez trouvé. Ces modifications seront automatiquement vidées dans la base de données à la fin de la transaction, de sorte que vous n'ayez rien à faire pour enregistrer ces modifications explicitement.ÉDITER:
Peut-être devrais-je élaborer sur la sémantique générale de JPA. Il existe deux approches principales pour la conception des API de persistance:
approche d'insertion / mise à jour . Lorsque vous avez besoin de modifier la base de données, vous devez appeler explicitement les méthodes d'API de persistance: vous appelez
insert
pour insérer un objet, ouupdate
pour enregistrer le nouvel état de l'objet dans la base de données.Approche de l'unité de travail . Dans ce cas, vous disposez d'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 un 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, de sorte que si vous créez un objet avec une clé primaire prédéfinie gérée , il sera associé à l'enregistrement de base de données du même identifiant et l'état de cet objet sera automatiquement propagé à cet enregistrement.
JPA suit cette dernière approche.
save()
dans Spring Data JPA est soutenu parmerge()
JPA simple, donc il rend votre entité gérée comme décrit ci-dessus. Cela signifie que l'appelsave()
à 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 ilsave()
n'est pas appelécreate()
.la source
extends CrudRepository<MyEntity, Integer>
au lieu deextends CrudRepository<MyEntity, String>
ce qu'il aurait dû. Est ce que ça aide? Je sais que c'est presque un an plus tard. J'espère que cela aide quelqu'un d'autre.Puisque la réponse de @axtavt se concentre sur le
JPA
nonspring-data-jpa
Mettre à jour une entité en interrogeant puis en enregistrant n'est pas efficace car cela nécessite deux requêtes et éventuellement la requête peut être assez coûteuse car elle peut rejoindre d'autres tables et charger toutes les collections qui ont
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
.@Query
sert à définir une requête personnalisée et@Modifying
indiquespring-data-jpa
que cette requête est une opération de mise à jour et qu'elleexecuteUpdate()
ne l' exige pasexecuteQuery()
.Vous pouvez spécifier d'autres types de retour:
int
- le nombre d'enregistrements mis à jour.boolean
- vrai si un enregistrement est mis à jour. Sinon, faux.Remarque : exécutez ce code dans une transaction .
la source
To update an entity by querying then saving is not efficient
ce ne sont pas les deux seuls choix. Il existe un moyen de spécifier l'id et d'obtenir l'objet de ligne sans l'interroger. Si vous faites unrow = repo.getOne(id)
et puisrow.attr = 42; repo.save(row);
et regardez les journaux, vous ne verrez que la requête de mise à jour.Vous pouvez simplement utiliser cette fonction avec la fonction JPA save (), mais l'objet envoyé comme paramètre doit contenir un identifiant existant dans la base de données 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, cela change les colonnes déjà trouvées dans la base de données.
la source
Comme cela a déjà été mentionné par d'autres, le
save()
lui - même contient à la fois une opération de création et de mise à jour.Je veux juste ajouter un supplément sur ce qui se cache derrière la
save()
méthode.Tout d'abord, voyons la hiérarchie étendre / implémenter le
CrudRepository<T,ID>
,Ok, vérifions l'
save()
implémentation àSimpleJpaRepository<T, ID>
,Comme vous pouvez le voir, il vérifiera si l'ID existe ou non dans un premier temps, si l'entité est déjà là, seule la mise à jour se fera par
merge(entity)
méthode et dans le cas contraire, un nouvel enregistrement est inséré parpersist(entity)
méthode.la source
En utilisant spring-data-jpa
save()
, j'avais le même problème que @DtechNet. Je veux dire que chacunsave()
créait un nouvel objet au lieu d'une mise à jour. Pour résoudre ce problème, j'ai dû ajouter unversion
champ à l'entité et à la table associée.la source
Voici comment j'ai résolu le problème:
la source
@Transaction
méthode ci-dessus pour plusieurs requêtes de base de données. Dans ce cas, inutileuserRepository.save(inbound);
, les modifications sont automatiquement supprimées.La
save()
méthode de données de printemps vous aidera à effectuer les deux: ajouter un nouvel élément et mettre à jour un élément existant.Appelez le
save()
et profitez de la vie :))la source
Id
je l'enregistrerai, comment puis-je éviter de sauvegarder un nouvel enregistrement.la source
Dans ce but particulier, on peut introduire une clé composite comme celle-ci:
Cartographie:
Voici comment l'utiliser:
JpaRepository ressemblerait à ceci:
Ensuite, vous pouvez utiliser l' idiome suivant : accepter DTO avec les informations de l'utilisateur, extraire le nom et le prénom et créer UserKey, puis créer une UserEntity avec cette clé composite, puis appeler Spring Data save () qui devrait tout trier pour vous.
la source