#spring #spring-boot #hibernate #rest #jpa
Вопрос:
У меня есть класс клиентов, в котором у каждого клиента может быть несколько продуктов. Класс выглядит следующим образом:
@Entity
@Table(name = "customer")
public class Customer {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "id")
private Long id;
@Column(name = "firstName")
private String firstName;
@Column(name = "lastName")
private String lastName;
@OneToMany(targetEntity=Product.class, mappedBy = "customer", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
@PrimaryKeyJoinColumn
@JsonManagedReference
private List<Product> products = new ArrayList<>();
//getters and setters here
}
и класс продукта имеет одну единственную связь с другими классами, и это выглядит следующим образом:
@Entity
@Table(name = "product")
public class Product {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
@ManyToOne(targetEntity=Customer.class, fetch = FetchType.LAZY)
@JoinColumn(name = "customer_id")
@JsonBackReference
private Customer customer;
@OneToOne(mappedBy = "product", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
@PrimaryKeyJoinColumn
@JsonManagedReference
private SomeType1 someType1;
@OneToOne(mappedBy = "product", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
@PrimaryKeyJoinColumn
@JsonManagedReference
private SomeType2 someType2;
@OneToOne(mappedBy = "product", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
@PrimaryKeyJoinColumn
@JsonManagedReference
private SomeType3 someType3;
@OneToOne(mappedBy = "product", cascade = CascadeType.ALL, orphanRemoval = true, fetch = FetchType.LAZY)
@PrimaryKeyJoinColumn
@JsonManagedReference
private SomeType4 someType4;
//getters and setters here
}
Я пытаюсь добиться следующей функциональности с помощью этого:
Учитывая идентификатор клиента и идентификатор продукта, обновите значения в SomeType1, SomeType2, SomeType3
классах. Я получаю обновленные SomeType1, SomeType2, SomeType3
объекты из пользовательского интерфейса и хочу обновить значения в БД. У меня уже есть PUT
метод для этого.
Here’s the PUT
method:
@PutMapping(value = "customer/{id}/product/{product_id}")
@ResponseBody
public ResponseEntity<Product> updateProduct(@PathVariable final String id,
@PathVariable final String product_id, @RequestBody final Product product) {
Optional<Customer> customerInDb = customerService.getCustomerById(id);
if (!customerInDb.isPresent()) {
throw new ResponseStatusException(HttpStatus.NOT_FOUND,
MessageFormat.format("Customer with id {0} does not exist.", id));
} else {
product.setId(Long.valueOf(product_id));
product.setCustomer(customerInDb.get());
Product savedProduct = customerService.createProduct(product);
return ResponseEntity.ok(savedProduct);
}
}
Я получаю следующую ошибку для этого вызова REST:
javax.persistence.EntityExistsException: A different object with the same identifier value was already associated with the session : [com.myapp.arg.entities.SomeType2#12]
В чем может быть причина этого?
Способ создания продукта:
@Override
public Product createProduct(Product product) {
Product savedProduct = productRepository.save(product);
return savedProduct;
}
Ввод JSON в PUT
метод:
{
"id":9,
"someType1":{
"id":9,
"avg":20,
"total":20
},
"someType2":{
"id":9,
"circum":45.0,
"strength":45.0,
"totalNav":0.0
},
"someType3":{
"id":9,
"tensile":87,
"pull":128,
"push":56,
"upward":28.0
},
"measuredBy":"SJ",
"addedDate":"2021-05-23",
"type":"Prime"
}
Комментарии:
1. пожалуйста, покажите
createProduct
метод. И в будущем не абстрагируйтесь от проблемы с каким — то типом 1, каким-то типом 2-это затрудняет нам отслеживание/решение2. @JAsgarov Я добавил
createProduct
метод в вопрос. Спасибо вам за предложение относительно абстрагирования проблемы.3. 1. что вы выдаете за а
@RequestBody final Product product
? поделитесь json plz, особенноSomeTypeN
свойствами 2. совершенно плохая идея передавать сущность в качестве модели, вы должны использовать отдельные классы для транспортировки и сохранения целей 3. показатьCustomer
отображение вProduct
4. чтоproduct(Long.valueOf(product_id))
делать? это какой-то метод или опечатка?4. @YuriyTsarkov Я обновил вопрос вашими предложениями. Спасибо вам за ваш отзыв (пункт 2 в вашем комментарии).
Ответ №1:
вы используете один и тот же идентификатор для всех ваших сущностей. Идентификатор должен быть уникальным
Комментарии:
1. Но эти идентификаторы автоматически генерируются для дочерних сущностей. Стратегия создания идентификаторов для этих дочерних сущностей имеет значение
GenerationType.AUTO
. Нужно ли мне это менять? Поскольку дочерние сущности имеют разные таблицы, возможно, что идентификаторы могут быть одинаковыми.2. вы можете сохранить автогенерацию, просто удалите эту строку
product.setId(Long.valueOf(product_id));
, чтобы jpa могла автоматически позаботиться о создании вспомогательных средств