EntityGraph를 이용해서 쿼리를 조금이라도 더 줄여보자
Reservation Entity
@Entity
@Getter
@NoArgsConstructor
public class Reservation extends BaseEntity {
@ManyToOne(fetch = FetchType.LAZY)
private Product product;
private String uniqueId;
@ManyToOne(fetch = FetchType.LAZY)
private Member member;
private String phoneNumber;
private LocalDateTime checkIn;
private LocalDateTime checkOut;
private String status;
private int isCancel;
@OneToOne(fetch = FetchType.LAZY, cascade = CascadeType.ALL)
@JoinColumn(name = "review_id")
private Review review;
@OneToOne
@JoinColumn(name = "cancel_id")
private Cancel cancel;
@Builder
public Reservation(Product product, Member member,
String phoneNumber, LocalDateTime checkIn, LocalDateTime checkOut,
String status, int isCancel) {
this.product = product;
this.member = member;
this.uniqueId = makeUniqueId();
this.phoneNumber = phoneNumber;
this.checkIn = checkIn;
this.checkOut = checkOut;
this.status = status;
this.isCancel = isCancel;
}
public void setReview(Review review) {
this.review = review;
}
public void deleteReview() {
this.review = null;
}
public void setIsCancelOn(Cancel cancel) {
this.isCancel = 1;
this.cancel = cancel;
}
public String makeUniqueId() {
DecimalFormat decimalFormat1 = new DecimalFormat("0000");
DecimalFormat decimalFormat2 = new DecimalFormat("00");
String uniqueId = LocalDate.now().getYear() + "-" +
decimalFormat2.format(LocalDate.now().getMonthValue()) +
decimalFormat2.format(LocalDate.now().getDayOfMonth()) + "-" +
decimalFormat1.format(Math.random() * 10000);
return uniqueId;
}
}
Review Entity
@Entity
@Getter
@NoArgsConstructor
@DynamicInsert
public class Review extends BaseEntity {
@OneToOne(fetch = FetchType.LAZY, mappedBy = "review")
private Reservation reservation;
@ManyToOne(fetch = FetchType.LAZY)
private Product product;
@Column(columnDefinition = "TEXT", nullable = false)
@NotBlank
private String content;
@NotNull
private Double totalStar; // 총 평점, 소수 1자리까지
@NotNull
private Double starCleanliness; // 청결도, 소수 1자리까지
@NotNull
private Double starAccuracy; // 정확도, 소수 1자리까지
@NotNull
private Double starLocation; // 위치, 소수 1자리까지
@NotNull
private Double starCostEffective; // 가격 대비 만족도, 소수 1자리까지
@Builder
public Review(Reservation reservation,
Product product,
String content, Double totalStar,
Double starCleanliness, Double starAccuracy, Double starLocation, Double starCostEffective) {
this.reservation = reservation;
this.product = product;
this.content = content;
this.totalStar = totalStar;
this.starCleanliness = starCleanliness;
this.starAccuracy = starAccuracy;
this.starLocation = starLocation;
this.starCostEffective = starCostEffective;
}
public void modify(String content, Double totalStar, Double starCleanliness,
Double starAccuracy, Double starLocation, Double starCostEffective) {
this.content = content;
this.totalStar = totalStar;
this.starCleanliness = starCleanliness;
this.starAccuracy = starAccuracy;
this.starLocation = starLocation;
this.starCostEffective = starCostEffective;
}
}
현재 상황
- 현재 Reservation Entity와 Review Entity는 주종 관계입니다.
- review에도 product와의 연관관계를 다대일로 맵핑해두었습니다.
- ReviewRepository의 findAllByProductId 메서드의 조회 결과를 보면 left outer join이 두 번 발생합니다. 아래는 발생한 조회 결과입니다.
@EntityGraph(attributePaths = {"reservation"})
Page<Review> findAllByProductId(long productId, Pageable pageable);
Hibernate:
select
review0_.id as id1_9_0_,
reservatio2_.id as id1_8_1_,
review0_.created_at as created_2_9_0_,
review0_.modified_at as modified3_9_0_,
review0_.content as content4_9_0_,
review0_.product_id as product10_9_0_,
review0_.star_accuracy as star_acc5_9_0_,
review0_.star_cleanliness as star_cle6_9_0_,
review0_.star_cost_effective as star_cos7_9_0_,
review0_.star_location as star_loc8_9_0_,
review0_.total_star as total_st9_9_0_,
reservatio2_.created_at as created_2_8_1_,
reservatio2_.modified_at as modified3_8_1_,
reservatio2_.cancel_id as cancel_10_8_1_,
reservatio2_.check_in as check_in4_8_1_,
reservatio2_.check_out as check_ou5_8_1_,
reservatio2_.is_cancel as is_cance6_8_1_,
...
from review review0_
left outer join product product1_ on review0_.product_id=product1_.id
left outer join reservation reservatio2_ on review0_.id=reservatio2_.review_id
where product1_.id=? order by review0_.id desc limit ?
해결해 보기
- Reservation에 중복은 없는 구조이고 Review와 일대일 주종 관계이기 때문에 Reservation에 있는 product를 이용하기로 했습니다.
- Review에 다대일로 맵핑된 product를 제거하고 Repository에 메서드를 @Query 어노테이션까지 사용해서 검색 조건을 설정해 주었다.
- 조회 쿼리를 보니 무려 2줄이 줄었다!!
@Query("SELECT r FROM Review r JOIN r.reservation rv WHERE rv.product.id = :productId")
@EntityGraph(attributePaths = {"reservation"})
Page<Review> findAllByReservationProductId(long productId, Pageable pageable);
Hibernate:
select
review0_.id as id1_9_0_,
reservatio1_.id as id1_8_1_,
review0_.created_at as created_2_9_0_,
review0_.modified_at as modified3_9_0_,
review0_.content as content4_9_0_,
review0_.star_accuracy as star_acc5_9_0_,
review0_.star_cleanliness as star_cle6_9_0_,
review0_.star_cost_effective as star_cos7_9_0_,
review0_.star_location as star_loc8_9_0_,
review0_.total_star as total_st9_9_0_,
reservatio1_.created_at as created_2_8_1_,
reservatio1_.modified_at as modified3_8_1_,
reservatio1_.cancel_id as cancel_10_8_1_,
...
from review review0_ inner join reservation reservatio1_ on review0_.id=reservatio1_.review_id
where reservatio1_.product_id=? order by review0_.id desc limit ?
참고 : https://jojoldu.tistory.com/165#recentEntries(기억보단 기록을)
'SpringBoot' 카테고리의 다른 글
| [JPA] @OneToOne 관계에서 EntityGraph 사용하기 (0) | 2023.01.14 |
|---|