it-roy-ru.com

Как красиво обновить сущность JPA в Spring Data?

Поэтому я просмотрел различные учебники по JPA с использованием Spring Data, и во многих случаях это делалось по-разному, и я не совсем уверен, каков правильный подход.

Предположим, существует следующая сущность:

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;
}
}

У нас также есть DTO, который извлекается на уровне обслуживания и затем передается на сторону контроллера/клиента.

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;
}
}

Итак, теперь предположим, что Заказчик хочет изменить свое имя в webui - тогда будет некоторое действие контроллера, где будет обновленный DTO со старым идентификатором и новым именем.

Теперь я должен сохранить этот обновленный DTO в базе данных.

К сожалению, в настоящее время нет способа обновить существующего клиента (кроме как удалить запись в БД и создать новый Cusomter с новым автоматически сгенерированным идентификатором)

Однако, поскольку это невозможно (особенно если учесть, что такая сущность потенциально может иметь сотни отношений), - на мой взгляд, есть два простых решения:

  1. создать установщик для идентификатора в классе Customer - и, таким образом, разрешить установку идентификатора, а затем сохранить объект Customer через соответствующий репозиторий.

или же

  1. добавьте поле id в конструктор, и всякий раз, когда вы хотите обновить клиента, вы всегда создаете новый объект со старым идентификатором, но с новыми значениями для других полей (в данном случае только имя)

Так что мой вопрос, есть ли общее правило, как это сделать?.. Любой может быть, каковы недостатки двух методов, которые я объяснил?

8
Lukas Makor

Даже лучше, чем @Tanjim Rahman. Вы можете использовать Spring Data JPA, используя метод T getOne(ID id)

Customer customerToUpdate = customerRepository.getOne(id);
customerToUpdate.setName(customerDto.getName);
customerRepository.save(customerToUpdate);

Это лучше, потому что getOne(ID id)получает только ссылку (прокси) объект и не извлекает его из БД. С помощью этой ссылки вы можете установить то, что вам нужно, а в save() он будет выполнять только оператор SQL UPDATE, как вы ожидаете. Для сравнения, когда вы вызываете find(), как в @Tanjim Rahmans, ответьте на весенние данные. JPA выполнит SQL SELECT для физического извлечения сущности из БД, которая вам не нужна, когда вы просто обновляете.

34
Robert Niestroj

Простое обновление JPA .. 

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

Если вам нужно работать с DTO, а не с сущностями напрямую, вам следует извлечь существующий Customer экземпляр и сопоставить обновленные поля из DTO с этим.

Customer entity = //load from DB
//map fields from DTO to entity
1
Alan Hay

Это больше вопрос инициализации объекта, чем вопрос jpa, оба метода работают, и вы можете иметь их оба одновременно, обычно, если значение элемента данных готово до создания экземпляра, вы используете параметры конструктора, если это значение может быть обновляется после создания экземпляра у вас должен быть сеттер. 

1
Amer Qarabsa

В Spring Data вы просто определяете запрос на обновление, если у вас есть идентификатор

  @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);

  }

Некоторые решения утверждают, что используют данные Spring и используют вместо этого JPA oldschool (даже с потерянными обновлениями).

0
gorefest