[Spring] 다대일 매핑

WOOK JONG KIM·2022년 11월 2일
0
post-thumbnail

다대일 단방향 매핑

공급 업체 엔티티 클래스

@Entity
@Getter
@Setter
@NoArgsConstructor
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)
@Table(name = "provider")
public class Provider extends BaseEntity{

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

    private String name;
}

Product entity에 공급업체 번호를 받기 위해 필드 추가

    @OneToOne(mappedBy = "product")
    @ToString.Exclude
    ProductDetail productDetail;

    @ManyToOne
    @JoinColumn(name = "provider_id")
    @ToString.Exclude
    private Provider provider;

일반적으로 외래키를 가지고 있는 쪽에서 Owner 역할을 함
-> Product entity가 Provider의 주인

공급 업체 아이디가 추가 된것을 볼 수 있음

public interface ProviderRepository extends JpaRepository<Provider, Long> {
}

엔티티의 주인인 Product의 Repository를 활용해 테스트 진행

	@Autowired
    ProductRepository productRepository2;

    @Autowired
    ProviderRepository providerRepository;

    @Test
    void relationshipTest1(){
        // 테스트 데이터 생성
        Provider provider = new Provider();
        provider.setName("삼성물산");

        providerRepository.save(provider);

        Product product = new Product();
        product.setName("가위");
        product.setPrice(5000);
        product.setStock(500);
        product.setProvider(provider);

        productRepository2.save(product);

        //테스트
        System.out.println(
                "product : " + productRepository2.findById(2L)
                        .orElseThrow(RuntimeException::new));

        System.out.println("provider :" + productRepository2.findById(2L)
                .orElseThrow(RuntimeException::new).getProvider());

    }
product : Product(super=BaseEntity(createdAt=2022-11-02T19:29:06.223346, updatedAt=2022-11-02T19:29:06.223346), number=2, name=가위, price=5000, stock=500)
provider :Provider(super=BaseEntity(createdAt=2022-11-02T19:29:06.220650, updatedAt=2022-11-02T19:29:06.220650), id=1, name=삼성물산)

다대일 양방향 매핑

공급업체에서 등록된 상품을 조회하기 위한 일대다 연관관계 설정해보자

공급업체 entity 에 추가

@OneToMany(mappedBy = "provider", fetch = FetchType.EAGER)
@ToString.Exclude
private List<Product> productList = new ArrayList<>();

일대다 관게의 경우 여러 상품의 엔티티가 포함될 수 있어 컬렉션 형식으로 필드 작성

@OneToMany가 붙은쪽에서 @JoinColumn 사용 시 상대 엔티티에 외래키가 설정됨

@OneToMany의 기본 fetch 전략 Lazy 대신 즉시 로딩으로 수정하였음

이렇게 Provider 엔티티 클래스를 수정해도 애플리케이션을 가동하면 칼럼은 변경되지 않음

mappedBy로 설정된 필드는 칼럼에 적용되지 않음!
-> 양쪽에서 연관관계 설정하고 있을 때 RDMS 형식으로 사용하기 위해 mappedBy를 통해 한쪽으로 외래키 관리를 위임한 것!

	@Autowired
    ProductRepository productRepository3;

    @Autowired
    ProviderRepository providerRepository3;

    @Test
    void relationshipTest(){

        // 테스트 데이터 생성
        Provider provider = new Provider();
        provider.setName("삼성상사");

        providerRepository3.save(provider);

        Product product1 = new Product();
        product1.setName("펜");
        product1.setPrice(2000);
        product1.setStock(100);
        product1.setProvider(provider);

        Product product2 = new Product();
        product2.setName("가방");
        product2.setPrice(2000);
        product2.setStock(200);
        product2.setProvider(provider);

        Product product3 = new Product();
        product3.setName("노트");
        product3.setPrice(3000);
        product3.setStock(1000);
        product3.setProvider(provider);

        productRepository3.save(product1);
        productRepository3.save(product2);
        productRepository3.save(product3);

        List<Product> products = providerRepository.findById(provider.getId()).get()
                .getProductList();

        for(Product product : products){
            System.out.println(product);
        }
   }

Provider 엔티티 클래스는 Product 엔티티와 연관관계에서 주인이 아니기 때문에 외래키 관리 불가

그래서 Provider를 등록한 후 각 Product에 객체를 설정하는 작업을 통해 DB에 저장

ProductList 필드에 Product 엔티티를 추가하는 방식으로 레코드 저장시 Provider 엔티티 클래스는 연관관게의 주인이 아니기에 DB에 반영이 안됨

provider.getProductList.add(product1); // 무시
provider.getProductList.add(product2); // 무시
provider.getProductList.add(product3); // 무시
Hibernate: 
    select
        provider0_.id as id1_2_0_,
        provider0_.created_at as created_2_2_0_,
        provider0_.updated_at as updated_3_2_0_,
        provider0_.name as name4_2_0_,
        productlis1_.provider_id as provider7_0_1_,
        productlis1_.number as number1_0_1_,
        productlis1_.number as number1_0_2_,
        productlis1_.created_at as created_2_0_2_,
        productlis1_.updated_at as updated_3_0_2_,
        productlis1_.name as name4_0_2_,
        productlis1_.price as price5_0_2_,
        productlis1_.provider_id as provider7_0_2_,
        productlis1_.stock as stock6_0_2_,
        productdet2_.id as id1_1_3_,
        productdet2_.created_at as created_2_1_3_,
        productdet2_.updated_at as updated_3_1_3_,
        productdet2_.description as descript4_1_3_,
        productdet2_.product_number as product_5_1_3_ 
    from
        provider provider0_ 
    left outer join
        product productlis1_ 
            on provider0_.id=productlis1_.provider_id 
    left outer join
        product_detail productdet2_ 
            on productlis1_.number=productdet2_.product_number 
    where
        provider0_.id=?
profile
Journey for Backend Developer

0개의 댓글