Подход к передаче идентификатора объекта в качестве переменной пути при обновлении не совсем верен. Подумайте об этом: у вас есть @RequestBody
, почему вы тоже не включили идентификатор в это тело? Почему вы хотите указать переменную пути для него?
Теперь, если у вас есть полный Customer
с его идентификатором из тела, вам не нужно делать какие-либо вызовы в ваш репозиторий, потому что hibernate добавляет его в состояние persistent
уже на основе его идентификатора и простой
public Customer update(Customer newCustomer) {
return customerRepository.save(newCustomer);
}
должен работать.
Q: Что такое постоянное состояние?
A: Постоянный объект связан со строкой таблицы базы данных и управляется текущим запущенным контекстом постоянства. (customerRepository.findById()
просто запрашивает у БД, существует ли сущность с указанным идентификатором и добавляет ее в постоянное состояние. Hibernate управляет всем этим процессом, если у вас есть поле @Id
с комментариями и заполнено, другими словами:
Customer customer = new Customer();
customer.setId(1);
- это ПОЧТИ то же самое, что и:
Customer customer = customerRepository.findById(1).get();
)
СОВЕТЫ: В любом случае, вы не должны иметь (если вы не знали) модель на уровне контроллера. Почему? Допустим, ваша модель Customer
может иметь несколько разрешений. Одна из возможных структур может выглядеть следующим образом:
@Entity
public class Customer{
//private fields here;
@OneToMany(mappedBy="customer",--other configs here--)
private List<Permission> permissions;
}
и
@Entity
public class Permission{
@Id
private Long id;
private String name;
private String creationDate;
@ManyToOne(--configs here--)
private Customer customer;
}
Вы можете видеть, что у вас есть перекрестная ссылка между Customer
и Permission
сущностью, которая в конечном итоге приведет к исключение переполнения стека (если вы этого не понимаете, вы можете подумать о рекурсивной функции, которая не имеет условия для остановки и вызывается снова и снова => переполнение стека. То же самое происходит и здесь).
Что вы можете сделать? Создание так называемого DTO
класса, который вы хотите, чтобы клиент получал вместо модели. Как вы можете создать этот DTO? Подумайте, что пользователь НУЖЕН знать.
1) Является ли "creationDate" из Permission
обязательным полем для пользователя? Не совсем.
2) Является ли "id" из Permission
обязательным для пользователя полем? В некоторых случаях да, в других - нет.
Возможный CustomerDTO
может выглядеть следующим образом:
public class CustomerDTO
{
private String firstName;
private String lastName;
private List<String> permissions;
}
, и вы можете заметить, что я использую List<String>
вместо List<Permission>
для разрешений клиента, которые фактически являются именами разрешений.
public CustomerDTO convertModelToDto(Customer customer)
{
//hard way
CustomerDTO customerDTO = new CustomerDTO();
customerDTO.setFirstName(customer.getFirstName());
customerDTO.setLastName(customer.getLastName());
customerDTO.setPermissions(
customer.getPermissions()
.stream()
.map(permission -> permission.getName())
.collect(Collectors.toList());
);
// easy-way => using a ModelMapper
customerDTO = modelMapper.map(customer,CustomerDTO.class);
return customerDTO;
}