Как обновить несколько записей в БД в Spring Boot?
Есть у меня ситуация: в запросе передается список элементов, мне нужно обновить эти элементы в базе данных(они там уже есть).
Есть ли способ обновить их с помощью JPA/Hibernate? Или же лучше положиться на код и обновить их в цикле да сохранить сразу все? Суть метода в том, чтобы к полю settlmentAmount добавить(или отнять) определённое значение.
public void updateListSettlementAmountById(List<UpdateListSettlementAmountRequest> requests) {
Iterable<Ingredient> ingredients = ingredientRepository
.findAllById(requests.stream()
.map(UpdateListSettlementAmountRequest::getId).toList());
Map<Short, UpdateListSettlementAmountRequest> requestMap = requests
.stream()
.collect(Collectors.toMap(UpdateListSettlementAmountRequest::getId, param -> param));
ingredients.forEach(ingredient -> {
UpdateListSettlementAmountRequest param = requestMap.get(ingredient.getId());
if(param.isReceipt() && param.getId() != null){
ingredient.setSettlementAmount(ingredient.getSettlementAmount().add(param.getAmount()));
} else if(!param.isReceipt() && param.getId() != null){
ingredient.setSettlementAmount(ingredient.getSettlementAmount().subtract(param.getAmount()));
}
});
ingredientRepository.saveAll(ingredients);
}
Сущности, которые использую в методе:
package ru.buzynnikov.inventory_service.models;
import jakarta.persistence.*;
import java.math.BigDecimal;
import java.util.Objects;
/**
* Модель сущности ингредиента, хранящейся в базе данных.
* Эта сущность предназначена для хранения данных об ингредиенте и поддерживает следующие поля:
* уникальный идентификатор ({@code id}),
* наименование ингредиента ({@code name}),
* количество доступного ингредиента ({@code amount}),
* расчетная количество ингредиента ({@code settlementAmount}),
* процент отходов при использовании ингредиента ({@code wastePercent}).
*/
@Entity
public class Ingredient {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Short id;
private String name;
@Column(precision = 7, scale = 3) // Аннотация задаёт точность числа и количество знаков после запятой
private BigDecimal amount;
@Column(name = "settlement_amount", precision = 7, scale = 3)
private BigDecimal settlementAmount;
@Column(name = "waste_percentage", precision = 4, scale = 3)
private BigDecimal wastePercent;
public Short getId() {
return id;
}
public void setId(Short id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public BigDecimal getAmount() {
return amount;
}
public void setAmount(BigDecimal amount) {
this.amount = amount;
}
public BigDecimal getSettlementAmount() {
return settlementAmount;
}
public void setSettlementAmount(BigDecimal settlementAmount) {
this.settlementAmount = settlementAmount;
}
public BigDecimal getWastePercent() {
return wastePercent;
}
public void setWastePercent(BigDecimal wastePercent) {
this.wastePercent = wastePercent;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Ingredient that = (Ingredient) o;
return Objects.equals(id, that.id) && Objects.equals(name, that.name);
}
@Override
public int hashCode() {
return Objects.hash(id, name);
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder("Ingredient{");
sb.append("id=").append(id);
sb.append(", name='").append(name).append('\'');
sb.append(", amount=").append(amount);
sb.append(", settlementAmount=").append(settlementAmount);
sb.append(", wastePercent=").append(wastePercent);
sb.append('}');
return sb.toString();
}
}
И вот:
package ru.buzynnikov.inventory_service.controllers.dto;
import java.math.BigDecimal;
public class UpdateListSettlementAmountRequest {
private Short id;
private BigDecimal amount;
private Boolean receipt;
public Short getId() {
return id;
}
public BigDecimal getAmount() {
return amount;
}
public Boolean isReceipt() {
return receipt;
}
}
Ответы (1 шт):
Суть JPA это работа с persience контекстом, которая предполагает загрузку данных из БД, их модификацию на уровне кода и отправку обратно диффа который вычисляется автоматически.
То что вы хотите противоречит концепции JPA и если нет проблем с производительностью, и имеет смысл только для для оптимизации.
Есть синтаксис на JPQL для такого:
@Modifying
@Query("UPDATE Ingredient i
SET i.settlementAmount= i.settlementAmount+ :delta
WHERE a.id = :id")
int midify(@Param("delta") BigDecimal amount, @Param("id") Long id);
Конкретно в вашем случае лучше оставить как есть, потому что для каждого значения число может быть уникальным и собрать запрос будет себе дороже.