[JPA,삽질] @OneToMany 시 연관 테이블 정보 불러오는 방법

백승호·2022년 4월 6일
0

JPA를 공부해보고자 하는 마음에 단방향으로 진행해도 무방한 연관관계 설정에 양방향을 사용해보았습니다.

처음부터 쉽지 않았습니다.. 단순히 주 테이블에 @ManyToOne을 해주고 다른 연관테이블에 @OneToMany를 해주는 것에 끝나지 않았습니다.

바로 코드 보면서 시작하겠습니다.



Product 테이블(주 테이블)

@NoArgsConstructor
@Getter
@Entity
public class Product {

    @GeneratedValue(strategy = GenerationType.AUTO)
    @Id
    private Long id;

    @Column(nullable = false)
    private String title;
   
   	@Column(nullable = false)
    private String image;
    
    @Column(nullable = false)
    private String link;
    
    @Column(nullable = false)
    private int lprice;
    
    @Column(nullable = false)
    private int myprice;

    @JsonManagedReference
    @JoinColumn(name = "user_id")
    @ManyToOne
    private User user;

User 테이블

@NoArgsConstructor
@Getter
@Entity
public class User {

    @GeneratedValue(strategy = GenerationType.AUTO)
    @Id
    private Long id;

    @Column(nullable = false, unique = true)
    private String username;

    @Column(nullable = false)
    private String password;

    @Column(nullable = false, unique = true)
    private String email;

    @Column(nullable = false )
    @Enumerated(value = EnumType.STRING) //DB에 저장될 때 무조건 스트링으로 저장
    private UserRoleEnum role;

    @JsonBackReference
    @Column(nullable = false)
    @OneToMany(mappedBy = "user", fetch = FetchType.EAGER)
    private List<Product> products =new ArrayList<>();

위와 같이 테이블을 설계했고, 양방향 관계에서 @OneToMany를 사용한 필드에 fetch=FetchType.EAGER 속성을 넣어줘야 영속성 문제에 관련된 에러를 방지할 수 있다는 걸 깨달았습니다.

추가로 @JsonBackReference@JsonManagedReference(주테이블에!)을 붙여주지 않으면 양방향에서 무한 순환참조를 진행하여 sendError()가 나는 것도 확인했습니다.
(물론 어노테이션 붙이는 것 말고 다른 방법으로 해결 가능합니다. 밑에 주소 참조)

양방향 매핑시 에러 해결


문제

자 그럼 이제 양방향의 이점을 살려서 user.getProducts()와 같은 식으로 정보를 뽑아 올 수 있길 바라며 아래와 같은 코드를 실행해 보았습니다.
(controller와 repository는 생략합니다)


//로그인한 유저가 고른 상품을 저장하는 POST과정

 	@Transactional
    public Product createProduct(ProductRequestDto requestDto, User user){
        // 요청받은 DTO 로 DB에 저장할 객체 만들기
        Product product = new Product(requestDto, user);
      
        productRepository.save(product);

        return product;
    }
    
//로그인한 유저의 상품만 조회하는 GET과정    
    
    @Transactional
    public List<Product> getOwnProducts(User user) {
        //양방향으로 묶어놨던 user의 product
        return user.getProducts();
    }

그러나 원하는 결과는 나오지 않았고 콘솔창을 확인해보니 ProductList[]으로 찍혀있습니다..!

분명 post로 유저정보와 상품정보를 주고 save 시켰는데 왜 size가 0일까요..

이를 해결하기 위해서는 User테이블이 갖고 있는 List<Product> products 리스트에 add를 시켜줘야합니다!!

해결


//로그인한 유저가 고른 상품을 저장하는 POST과정

 	@Transactional
    public Product createProduct(ProductRequestDto requestDto, User user){
        // 요청받은 DTO 로 DB에 저장할 객체 만들기
        Product product = new Product(requestDto, user);
        //add 부분!!!!!
      	user.getProducts().add(product);
        productRepository.save(product);

        return product;
    }
    
//로그인한 유저의 상품만 조회하는 GET과정    
    
    @Transactional
    public List<Product> getOwnProducts(User user) {
        //양방향으로 묶어놨던 user의 product
        return user.getProducts();
    }

정상적으로 원하는 결과물이 나왔습니다~

profile
처음처럼

0개의 댓글