web-dev-qa-db-fra.com

Comment mettre à jour magnifiquement une entité JPA dans Spring Data?

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:

  1. créer un setter pour l'identifiant dans la classe Customer - et ainsi permettre la définition de l'identifiant, puis sauvegarder l'objet Customer via le référentiel correspondant.

ou

  1. ajoutez le champ id au constructeur et chaque fois que vous souhaitez mettre à jour un client, vous créez toujours un nouvel objet avec l'ancien id, mais les nouvelles valeurs des autres champs (dans ce cas, seul le nom)

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?

8
Lukas Makor

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.

34
Robert Niestroj

Mise à jour JPA simple .. 

Customer customer = em.find(id, Customer.class); //Consider em as JPA EntityManager
customer.setName(customerDto.getName);
em.merge(customer);
3
Esty

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
1
Alan Hay

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. 

1
Amer Qarabsa

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.

0
gorefest