Двунаправленное отношение OneToMany Значение JoinColumn в Spring Data JPA равно нулю - PullRequest
0 голосов
/ 18 апреля 2019

У меня есть двунаправленное сопоставление OneToMany для двух объектов Cart и CartProduct.Всякий раз, когда мы вставляем объект Cart с продуктами корзины, таблица CartProduct должна заполняться cart_id.Вот проблема, когда я вставляю объект корзины, все вроде бы нормально, кроме JoinColumn(card_id), что приводит к нулевому значению в таблице CartProduct.Я делаю это правильно?

Cart.Java

package com.springtesting.model.cart;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.springtesting.model.AbstractAuditingEntity;
import com.springtesting.model.user.UserProfile;
import lombok.Data;
import lombok.EqualsAndHashCode;

import javax.persistence.*;
import java.util.ArrayList;
import java.util.List;

@EqualsAndHashCode(callSuper = true)
@Entity
@Data
@Table(name = "cart")
public class Cart  extends AbstractAuditingEntity
{
    private static final long serialVersionUID = 6294902210705780249L;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private Long id;

    @OneToOne
    @JoinColumn(name = "user_profile_id")
    @JsonIgnoreProperties(value = {"addresses"})
    private UserProfile userProfile;

    @ManyToOne
    @JoinColumn(name = "cart_status")
    private CartStatus cartStatus;

    @OneToMany(mappedBy = "cart", cascade = CascadeType.ALL,fetch = FetchType.EAGER)
    //@ElementCollection(targetClass = CartProduct.class)
    private List<CartProduct> cartProducts=new ArrayList<>();

}

CartProduct.Java

package com.springtesting.model.cart;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.springtesting.model.AbstractAuditingEntity;
import com.springtesting.model.product.Product;
import lombok.Data;
import lombok.EqualsAndHashCode;

import javax.persistence.*;

@EqualsAndHashCode(callSuper = true)
@Entity
@Data
@Table(name = "cart_product")
public class CartProduct extends AbstractAuditingEntity
{
    private static final long serialVersionUID = 6498067041321289048L;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private Long id;

    @OneToOne
    @JoinColumn(name = "product_id")
    private Product product;

    @Column(name = "quantity")
    private Integer quantity;


    @ManyToOne
    @JoinColumn(name = "cart_id",referencedColumnName = "id")
    @JsonIgnoreProperties(value = {"userProfile","cartStatus","cartProducts"})
    private Cart cart;

}

TestCase.Ява

 @Test
    public void insertCart()
    {
        Cart cart=new Cart();
        cart.setUserProfile(userProfileRepository.findAllByUserId(1L).get());
        cart.setCartStatus(cartStatusRepository.findById(1L).get());
        List<CartProduct> cartProducts=new ArrayList<>();

        CartProduct cartProduct=new CartProduct();
        cartProduct.setProduct(productRepository.findById(1L).get());
        cartProduct.setQuantity(2);
        cartProducts.add(cartProduct);

        cartProduct=new CartProduct();
        cartProduct.setProduct(productRepository.findById(2L).get());
        cartProduct.setQuantity(1);
        cartProducts.add(cartProduct);

        cart.setCartProducts(cartProducts);

        cartRepository.saveAndFlush(cart);

    }

Ответы [ 2 ]

1 голос
/ 23 апреля 2019

Да, ваше исправление - это добавление 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.

0 голосов
/ 18 апреля 2019

Мне кажется, я разобрался с решением. На основе документов Hibernate

Когда создается двунаправленная ассоциация, заявка Разработчик должен убедиться, что обе стороны синхронизированы постоянно.

Поэтому я вручную добавил объект cart в объект cartProduct, который сохраняет cart_id в таблице CartProduct

CartController.java

import com.pj.springsecurity.model.cart.Cart;
import com.pj.springsecurity.model.cart.CartProduct;
import com.pj.springsecurity.repo.CartRepository;
import org.springframework.web.bind.annotation.*;

import java.util.List;
import java.util.Optional;

@RestController
@RequestMapping("/api/v1/cart")
public class CartController
{
    private final CartRepository cartRepository;

    public CartController(CartRepository cartRepository)
    {
        this.cartRepository = cartRepository;
    }

    @GetMapping(path = "/list")
    public List<Cart> getAllCarts()
    {
        return cartRepository.findAll();
    }

    @GetMapping(path = "/find/user/{id}")
    public Optional<Cart> getCartBasedOnUserId(@PathVariable Long id)
    {
        return cartRepository.findAllByUserProfileUserId(id);
    }

    @PostMapping(path = "/product/add")
    public Cart addProductToCart(@RequestBody Cart cart)
    {
        List<CartProduct> cartProducts=cart.getCartProducts();
        for(CartProduct cartProduct: cartProducts)
        {
            cartProduct.setCart(cart);
        }
        return cartRepository.saveAndFlush(cart);
    }

    @PutMapping(path = "/update")
    public Cart updateCart(@RequestBody Cart cart)
    {
        return cartRepository.saveAndFlush(cart);
    }

    @DeleteMapping(path = "/delete")
    public Cart createEmptyCart(@RequestBody Cart cart)
    {
        return cartRepository.saveAndFlush(cart);
    }

    @DeleteMapping(path = "/product/delete")
    public void deleteProductFromCart(@RequestBody Cart cart)
    {
        List<CartProduct> cartProducts=cart.getCartProducts();
        for(CartProduct cartProduct: cartProducts)
        {
            cartProduct.setCart(null);
        }
        cartRepository.delete(cart);
    }
}

и тестовый набор обновлен с тем же

@Test
public void insertCart()
{
    Cart cart=new Cart();
    cart.setUserProfile(userProfileRepository.findAllByUserId(1L).get());
    cart.setCartStatus(cartStatusRepository.findById(1L).get());
    List<CartProduct> cartProducts=new ArrayList<>();

    CartProduct cartProduct=new CartProduct();
    cartProduct.setProduct(productRepository.findById(1L).get());
    cartProduct.setQuantity(2);
    cartProduct.setCart(cart);
    cartProducts.add(cartProduct);

    cartProduct=new CartProduct();
    cartProduct.setProduct(productRepository.findById(2L).get());
    cartProduct.setQuantity(1);
    cartProduct.setCart(cart);
    cartProducts.add(cartProduct);

    cart.setCartProducts(cartProducts);

    cartRepository.saveAndFlush(cart);

}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...