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();
}
정상적으로 원하는 결과물이 나왔습니다~