simDev1234
심플하고 차분하게
simDev1234
전체 방문자
오늘
어제
  • 분류 전체보기
    • Computer Science
      • Basic Math
      • Data Structure
      • Algorithm
      • Database
      • OS
    • Language
      • Java
      • Kotlin
      • SQL
    • Framework
      • Spring
      • Orm&Mapper
      • 프로젝트로 스프링 이해하기
      • 스프링 라이브러리
    • Infra
      • Cloud
      • Docker
      • Redis
      • AWS, Azure
      • Device
    • Etc
      • CleanCoding
    • Git,Github

블로그 메뉴

  • 홈
  • 태그
  • 방명록

공지사항

인기 글

태그

  • null
  • scanner #next() #nextLine()
  • controllerTest
  • 자바프로그램
  • 404
  • 자바
  • JVM메모리구조
  • 참조타입
  • 스프링
  • 참조변수
  • 컨트롤러
  • 자바메모리구조
  • 자바프로그래밍

최근 댓글

최근 글

티스토리

hELLO · Designed By 정상우.
simDev1234

심플하고 차분하게

Framework/Orm&Mapper

[JPA] 특정 상황에서 Lazy Fetch Type 변경하기 (@EntityGraph)

2022. 11. 28. 03:32

|  스프링 부트 Test 중, 아래와 같이 오류가 나타났다.

C:\sebinSample\cms\order-api\src\main\java\org\zerobase\cms\order\domain\model\Product.java:33: warning: @Builder will ignore the initializing expression entirely. If you want the initializing expression to serve as default, add @Builder.Default. If it is not supposed to be settable during building, make the field final.
    private List<ProductItem> productItems = new ArrayList();
                              ^
Note: C:\sebinSample\cms\order-api\src\main\java\org\zerobase\cms\order\domain\model\Product.java uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.

- 테스트 코드 

@Test
void addProduct() {

    // given
    Long sellerId = 1L;

    AddProductForm form = makeProductForm("나이키 에어포스", "신발", 3);

    // when
    Product p = productService.addProduct(sellerId, form);

    // then
    Product result = productRepository.findById(p.getId()).get();

    Assertions.assertNotNull(result);
    Assertions.assertEquals(result.getSellerId(), 1L);
    Assertions.assertEquals(result.getName(), "나이키 에어포스");
    Assertions.assertEquals(result.getDescription(), "신발");
    Assertions.assertEquals(result.getProductItems().get(0).getName(), "나이키 에어포스0");
    Assertions.assertEquals(result.getProductItems().get(0).getPrice(), 10000);

}

private static AddProductForm makeProductForm(String name, String description, int itemCount) {
    List<AddProductItemForm> addProductItemForms = new ArrayList<>();
    for (int i = 0; i < itemCount; i++) {
        addProductItemForms.add(makeProductItemForm(null, name + i));
    }
    return AddProductForm.builder()
            .name(name)
            .description(description)
            .addProductItemForms(addProductItemForms)
            .build();
}

> 원인 :

- @OneToMany의 default fetch type이 LazyLoading이기 때문에, Proxy로 id 값만 담은 ProductItem들을 가져오고, 실제 내용은 들어있지 않았기 때문이다.

@Entity
@Getter
@Setter
@AllArgsConstructor
@NoArgsConstructor
@Builder
@AuditOverride(forClass = BaseEntity.class)
@Audited  // Entity가 변할 때마다, 변화된 내용을 저장
public class Product extends BaseEntity{

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

    private String name;
    private String description;

    @OneToMany(cascade = CascadeType.ALL)
    @JoinColumn(name = "product_id")
    private List<ProductItem> productItems = new ArrayList();


    public static Product of(Long sellerId, AddProductForm form) {
        return Product.builder()
                .sellerId(sellerId)
                .name(form.getName())
                .description(form.getDescription())
                .productItems(form.getAddProductItemForms().stream()
                        .map(p -> ProductItem.of(sellerId, p)).collect(Collectors.toList())
                ).build();
    }
}

> 해결 :

이를 해결하기 위해서는 두가지 방법을 사용할 수 있는데

(1) fetch type을 EAGER로 변경한다. --> 이 방법은 그러나 불필요하게 매번 DB 조회 시 모든 데이터를 한 번에 가져오게 함으로 좋지 않다.

(2) JPA의 @EntityGraph와 findWith 함수를 통해 속성을 지정(ex. productItems)할 때, fetch type을 변경시킨다.

EntityGraphType.LOAD attributePaths가 지정된 경우 EAGER로, 지정되지 않으면 default fetch type으로
EntityGraphType.FETCH attributePaths가 지정된 경우 EAGER로, 지정되지 않으면 LAZY로
@Repository
public interface ProductRepository extends JpaRepository<Product, Long> {

    @EntityGraph(attributePaths = {"productItems"}, type = EntityGraph.EntityGraphType.LOAD)
    Optional<Product> findWithProductItemsById(Long id);

}

 

[ 출처 ]

부트캠프 수업 내용 정리

'Framework > Orm&Mapper' 카테고리의 다른 글

[JPA] CascadeType : 상위 -> 하위 엔터티 전파 타입  (0) 2022.11.28
[JPA] Lazy Loading 개념  (0) 2022.11.11
[Entity] 중복데이터 저장 방지 (Unique Key, Index)  (0) 2022.11.11
[Transaction] Transaction에 대한 이해 (& 스프링의 @Transactionl)  (1) 2022.10.25
[JPA] 인텔리J에서 JPA Entity 기반 ERD 그리기  (0) 2022.10.19
    'Framework/Orm&Mapper' 카테고리의 다른 글
    • [JPA] CascadeType : 상위 -> 하위 엔터티 전파 타입
    • [JPA] Lazy Loading 개념
    • [Entity] 중복데이터 저장 방지 (Unique Key, Index)
    • [Transaction] Transaction에 대한 이해 (& 스프링의 @Transactionl)
    simDev1234
    simDev1234
    TIL용 블로그. * 저작권 이슈가 있는 부분이 있다면 댓글 부탁드립니다.

    티스토리툴바