Да, ваше исправление - это добавление cartProduct.setCart(cart);
Это потому, что CartProduct является владельцем и хранителем ForeignKey. Вышеупомянутое утверждение устанавливает FK.
Способ думать об этом - концепция owning entity
. Когда у вас есть mappedBy="cart"
, вы говорите, что класс CartProduct
владеет отношениями. Это означает, что только класс CartProduct
выполняет сохранение. Это говорит JPA создать FK в таблице CartProduct
. Тем не менее, мы замечаем, что save вызывается не на CartProduct
, а на Cart
, и все же cartProducts
все еще сохраняется. Это потому, что у вас есть аннотация cascade = CascadeType.ALL
. Это говорит JPA каскадировать определенные операции, когда они выполняются для Cart
, в этом случае операция save
.
Вы должны напечатать операторы SQL и изучить различия в разных конфигурациях и тестовых примерах. Это поможет вам лучше понять.
У вас также есть FetchType.EAGER. Как правило, это вредная привычка, которая обычно приводит к бесконечным проблемам.
Хороший способ думать о двунаправленном отображении состоит в том, что List<CartProducts> cartProducts
- это поле только для запроса. Чтобы сохранить CartProduct
, вы должны позвонить в save на cartProductRepository
напрямую. Э.Г.
CartProduct cartProduct=new CartProduct();
cartProduct.setProduct(productRepository.findById(1L).get());
cartProduct.setQuantity(2);
cartProduct.setCart(cart);
cartProductRepository.save(cartProduct);
, а затем
cart.getCartProducts().add(cartProduct);
и удалите все аннотации каскада и страстного извлечения. Когда Hibernate говорит, что вы должны управлять обеими сторонами отношений, это означает, что.
Выполнение этого способа приведет к одному запросу на сохранение. Используя каскадную аннотацию, вы обнаружите, что при добавлении элементов в корзину и вызове save для нее сгенерированный sql сначала удалит все существующие cartProducts
элементы из базы данных и будет повторно добавлять их вместе с новым каждый раз, когда вы сохранить вызов. Для корзины с 10 предметами вместо одного сохранения у вас будет удаление и 10 новых сохранений. Определенно менее желательно. Если вам нужно перезагрузить корзину с нуля, самый эффективный способ - получить корзину, а затем cart.setCartProducts(cartProductRepository.findAllByCart(cart));
, что в любом случае делает FetchType.EAGER. Когда вы понимаете все это, вы понимаете, что вам не нужно = new ArrayList<>();
для вашего cartProducts.