J'ai donc examiné divers didacticiels sur JPA avec Spring Data. Cela a été fait à plusieurs reprises et je ne suis pas tout à fait sûr de la bonne approche.
Supposons qu'il y ait l'entité suivante:
package stackoverflowTest.dao;
import javax.persistence.*;
@Entity
@Table(name = "customers")
public class Customer {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
@Column(name = "id")
private long id;
@Column(name = "name")
private String name;
public Customer(String name) {
this.name = name;
}
public Customer() {
}
public long getId() {
return id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Nous avons également un DTO qui est récupéré dans la couche service et ensuite transmis au contrôleur/côté client.
package stackoverflowTest.dto;
public class CustomerDto {
private long id;
private String name;
public CustomerDto(long id, String name) {
this.id = id;
this.name = name;
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Supposons maintenant que le client souhaite changer de nom dans le Web. Il y aura alors une action du contrôleur: le DTO mis à jour avec l'ancien ID et le nouveau nom.
Maintenant, je dois enregistrer ce DTO mis à jour dans la base de données.
Malheureusement, il n’existe actuellement aucun moyen de mettre à jour un client existant (hormis la suppression de l’entrée dans la base de données et la création d’un nouveau Cusomter avec un nouvel identifiant généré automatiquement)
Toutefois, comme cela n’est pas faisable (en particulier si une telle entité pourrait avoir des centaines de relations potentielles), deux solutions simples me sont alors venues à l’esprit:
ou
Ma question est donc de savoir s’il existe une règle générale pour procéder ainsi? Peut-être quels sont les inconvénients des deux méthodes que j’ai expliquées?
Encore mieux que @Tanjim Rahman répondez, vous pouvez utiliser Spring Data JPA en utilisant la méthode T getOne(ID id)
Customer customerToUpdate = customerRepository.getOne(id);
customerToUpdate.setName(customerDto.getName);
customerRepository.save(customerToUpdate);
Est-ce préférable, car getOne(ID id)
ne vous donne qu'un objet référence (proxy) et ne le récupère pas à partir de la base de données. Sur cette référence, vous pouvez définir ce que vous voulez et sur save()
, il fera juste une instruction SQL UPDATE comme vous l’attendez. En comparaison, lorsque vous appelez find()
comme dans @Tanjim Rahmans, vous devez exécuter une commande SQL SELECT pour extraire physiquement l'entité de la base de données, ce dont vous n'avez pas besoin lorsque vous mettez à jour.
Mise à jour JPA simple ..
Customer customer = em.find(id, Customer.class); //Consider em as JPA EntityManager
customer.setName(customerDto.getName);
em.merge(customer);
Si vous devez travailler directement avec des DTO plutôt qu'avec des entités, vous devez extraire l'instance existant Client et mapper les champs mis à jour à partir du DTO.
Customer entity = //load from DB
//map fields from DTO to entity
Il s’agit plus d’une question d’initialisation d’objet que d’une question jpa. Les deux méthodes fonctionnent et vous pouvez les avoir simultanément, généralement si la valeur du membre de données est prête avant l’instanciation, utilisez les paramètres du constructeur, si cette valeur peut être mis à jour après l'instanciation, vous devriez avoir un passeur.
Dans Spring Data, vous définissez simplement une requête de mise à jour si vous avez l'ID.
@Repository
public interface CustomerRepository extends JpaRepository<Customer , Long> {
@Query("update Customer c set c.name = :name WHERE c.id = :customerId")
void setCustomerName(@Param("customerId") Long id);
}
Certaines solutions prétendent utiliser les données Spring et font JPA oldschool (même avec des mises à jour perdues) à la place.