ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [JPA] ID 참조와 조인 테이블을 이용한 단방향 M:N 매핑
    스프링프레임워크/jpa 2021. 1. 14. 17:19

    이번 포스트에서는 ID 참조를 이용해서 엔티티 간 단방향 M:N 연관 관계를 해결하는 방법을 알아보도록 하겠습니다.

     

    Product와 Category의 관계가 아래와 같다고 가정합니다.

    • Product와 Category는 M:N 연관관계이다.
    • 특정 Category에 있는 Product 정보 조회 기능이 필요하다.
    • 특정 Product가 속해 있는 Category 정보 조회 기능은 필요없다.

    위와 같은 가정하에서는 Product와 Category는 양방향 매핑 관계를 가질 필요가 없게되고, 단방향 매핑을 통해서 요구 사항을 만족 시킬 수 있게 됩니다.

    이 때 엔티티간에 연관 관계를 맺을 수도 있지만 아래와 같이 ID 참조를 이용해서 더 간편하게 표현 할 수 있습니다.

     

    우선 Product 클래스를 아래와 같이 구성합니다.

    • @CollectionTable의 joinColumns 속성을 사용해서 Product에서 product_category를 참조할 때 사용하는 조인 컬럼을 지정한다.
    • Category와의 연관 관계를 엔티티가 아닌 Category의 ID를 참조하게 합니다.
    @NoArgsConstructor(access = AccessLevel.PROTECTED)
    @Getter
    @Entity
    public class Product {
        @EmbeddedId
        private ProductId id;
    
        @ElementCollection
        @CollectionTable(name = "product_category", joinColumns = @JoinColumn(name = "product_id"))
        private Set<CategoryId> categoryIds = new HashSet<>();
    
        private String name;
    
        private Money price;
    
        private String detail;
    
        @OneToMany(cascade = {CascadeType.PERSIST, CascadeType.REMOVE, CascadeType.MERGE}, orphanRemoval = true, fetch = FetchType.EAGER)
        @JoinColumn(name = "product_id")
        @OrderColumn(name = "list_idx")
        private List<Image> images = new ArrayList<>();
    
    
        public Product(ProductId id, String name, Money price, String detail, List<Image> images) {
            this.id = id;
            this.name = name;
            this.price = price;
            this.detail = detail;
            this.images.addAll(images);
        }
    }
    public interface ProductRepository extends JpaRepository<Product, ProductId> {
    }

     

    다음으로 Product 엔티티와 연관 관계가 있는 Category 엔티티를 생성합니다.

    @NoArgsConstructor(access = AccessLevel.PROTECTED)
    @Getter
    @Entity
    public class Category {
        @EmbeddedId
        CategoryId id;
    
        String name;
    
        public Category(CategoryId id, String name) {
            this.id = id;
            this.name = name;
        }
    }
    interface CategoryRepository extends JpaRepository<Category, CategoryId> {
    }

     

    위와 같이 엔티티를 생성하고 테스트를 진행해보도록 하겠습니다.

    @Rollback(false)
    @Transactional
    @SpringBootTest
    @TestMethodOrder(OrderAnnotation.class)
    public class ProductTest {
        @Autowired
        ProductRepository productRepository;
    
        @Autowired
        CategoryRepository categoryRepository;
    
        @Test
        @Order(1)
        public void 카테고리_등록() {
            CategoryId categoryId = new CategoryId(1l);
            Category category = new Category(categoryId, "가전");
            Category savedCategory = categoryRepository.save(category);
    
            assertThat(savedCategory.getId()).isEqualTo(category.getId());
        }
    
        @Test
        @Order(2)
        public void 상품_등록() {
            Product product = new Product(new ProductId("prod-999"), "999", new Money(999), "detail",
                    Arrays.asList(new ExternalImage("externalPath", "uchupura"),
                            new InternalImage("internal1", true),
                            new InternalImage("internal2", false)));
            product.getCategoryIds().add(new CategoryId(1l));
            productRepository.save(product);
        }
    
        @Test
        @Order(3)
        public void 특정_카테고리에_존재하는_상품리스트_검색() {
            List<Product> products = productQueryRepository.findByCategoryId(new CategoryId(1l));
            products.forEach(product -> System.out.println(product.getName()));
        }
    
        @Test
        @Order(4)
        public void 특정_상품_검색() {
            Product product = productQueryRepository.findById(new ProductId("prod-999"));
            System.out.println(product.getName());
        }
    }

    위 테스트를 실행 시 데이터베이스에 입력 된 내용입니다.

    이상으로 ID 참조를 이용해서 엔티티 간 단방향 M:N 연관 관계를 매핑하는 방법에 대해서 알아보았습니다.

    댓글

Designed by Tistory.