[TIL] 23.06.01 low level 의 연관관계 개선하기

hyewon jeong·2023년 6월 1일
0

TIL

목록 보기
129/138

1 . 문제점

low level 로 연관관계 매핑을 하지 않고 일일히 필요한 객체의 데이터를 가지고 와서 연관관계 된것처럼 사용했다. 이번에는 매핑을 시켜보고 차이점을 느껴보려고 한다.


2 . 시도한 점

2-1 . 1차시도

ContactCommentService
기존 코드에서 inquiryId 채로 ContactComment 객체를 생성했는데
ContactComment와 inquiry를 다대일 매핑시킴으로써

변경 전

 ContactComment contactComment = createContactCommentRequest.toEntity(inquiryId, username,
            nickName, parent, depth);

변경 후

 ContactComment contactComment = createContactCommentRequest.toEntity(inquiry, username,
            nickName, parent, depth);
  /**
   * ㄴ 부모댓글이 있는 경우    -> 대댓글 저장 ㄴ 자식댓글(대댓글) 경우     -> 대대댓글을 저장 ㄴ 부모댓글이 없는 경우.   -> 댓글 저장
   * <p>
   * 프론트엔드를 고려하여 자식 댓글의 계층구조로 보여주기 위해  depth 로 계층구조 나눔
   */

  @Override
  @Transactional
  public void saveInquiryComment(Long inquiryId,
      CreateContactCommentRequest createContactCommentRequest,
      String username, String nickName) {

    if (!inquiryRepository.existsById(inquiryId)) {
      throw new CustomException(ExceptionStatus.BOARD_NOT_EXIST);
    } else {
      /**부모댓글이 있는 경우 - 대댓글. 즉 자식 댓글이 됨
       * 자식 댓글인 경우 -대대댓글  저장
       */
      ContactComment parent = null;
      if (createContactCommentRequest.getParentId() != null) {
        parent = contactCommentRepository.findById(createContactCommentRequest.getParentId())
            .orElseThrow(
                () -> new CustomException(ExceptionStatus.COMMENT_NOT_EXIST)
            );
        /** 부모 댓글과 자식 댓글의 게시글 아이디가 같은지 확인*/
        //v2 객체 지향 entity 에게 역할을 줌
        parent.isInquiryId(inquiryId);
        int depth = parent.getDepth() + 1; //  자식댓글의 depth 설정 : 부모댓글의 자식 댓글이므로 + 1 함
        Inquiry inquiry = findInquiryById(inquiryId);
        ContactComment contactComment = createContactCommentRequest.toEntity(inquiry, username,
            nickName, parent, depth);
        contactComment.setParent(parent); // parent = null 값이므로 현재 부모댓글을 지정해줌
        contactCommentRepository.save(contactComment);

        /**부모댓글이 없는 경우 - 댓글 등록*/
      } else {
        int depth = 1;
        Inquiry inquiry = findInquiryById(inquiryId);
        ContactComment contactComment = createContactCommentRequest.toEntity(inquiry, username,
            nickName, parent, depth);
        contactCommentRepository.save(contactComment);
      }
    }
  }

  private Inquiry findInquiryById(Long inquiryId) {
    return inquiryRepository.findById(inquiryId).orElseThrow(
        () -> new CustomException(ExceptionStatus.BOARD_NOT_EXIST)
    );
  }

inquiryService 변경후

  @Transactional(readOnly = true)
  @Override
  public InquiryResponse getSelectedInquiry(Long id, String nickName, UserRoleEnum role) {
    Inquiry inquiry = findById(id);
    if (inquiry.getSecret()) {
        // 건당 조회시 작성자 닉네임이 보이기위해 이것만 nickName 으로
      if (inquiry.isNickName(nickName) || role.equals(UserRoleEnum.MANAGER)) {
 //부모댓글를 조회하면 자식댓글도 함께 조회 됨
 //변경 함(주석처리)
//  List<ContactComment> parentComments = contactCommentService.findAllByInquiryIdAndParentIsNull(
//            id);
        return new InquiryResponse(inquiry);
      } else {
        throw new CustomException(ExceptionStatus.SECRET_POST);
      }
    } else {
    //변경 함(주석처리)
  //List<ContactComment> parentComments = contactCommentService.findAllByInquiryIdAndParentIsNull(
      //    id);
      return new InquiryResponse(inquiry);
    }

  }

ContactComment Entity 변경후

@Entity
public class ContactComment extends Timestamped {

  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  @Column(name = "id", nullable = false)
  private Long id;
  @Column(nullable = false)
  private String comments;
  @Column(nullable = false)
  private String username;

  @Column(nullable = false)
  private String nickName;
  
  @ManyToOne(fetch = FetchType.LAZY)
  @JoinColumn(name = "parent")
  private ContactComment parent;

  @OneToMany(mappedBy = "parent", orphanRemoval = true)
  private List<ContactComment> children = new ArrayList<>();
  @ManyToOne(fetch = FetchType.LAZY)
 ///변경된 부분 
  @JoinColumn(name = "inquiry_id", nullable = false)
  private Inquiry inquiry;
  
//변경된 부분
//  @Column(nullable = false)
//  private Long inquiryId;
  private int depth;

  @Builder
  public ContactComment(String comments, String username, Inquiry inquiry, String nickName,
      ContactComment parent, int depth) {
    this.comments = comments;
    this.username = username;
    this.inquiry = inquiry;
    this.nickName = nickName;
    this.parent = parent;
    this.depth = depth;
  }

inquiryEntity

  @OneToMany(mappedBy = "inquiry",cascade = {CascadeType.ALL},orphanRemoval = true)
  private List<ContactComment> contactComments = new ArrayList<>();

inquiryResponseDto

  public InquiryResponse(Inquiry inquiry) {
    this.id = inquiry.getId();
    this.title = inquiry.getTitle();
    this.content = inquiry.getContent();
    this.nickName = inquiry.getNickName();
    this.createdDate = inquiry.getCreatedDate();
    this.secret = inquiry.getSecret();
    this.comments = 
 //이부분을 변경함    inquiry.getContactComments().stream().map(ContactCommentResponse::new)
        .sorted(Comparator.comparing(ContactCommentResponse::getCreatedDate))
        .collect(Collectors.toList());

  }

inquiryResponseDto 이부분에서 부모댓글과 자식댓글이 잘나오지만 , 자식댓글들을 한번씩 더 가져오는 현상이 발생한다.


3 . 해결

2-2 2차 시도

inquiryResponseDto

  public InquiryResponse(Inquiry inquiry) {
    this.id = inquiry.getId();
    this.title = inquiry.getTitle();
    this.content = inquiry.getContent();
    this.nickName = inquiry.getNickName();
    this.createdDate = inquiry.getCreatedDate();
    this.secret = inquiry.getSecret();
    this.comments = inquiry.getContactComments().stream()
        .filter(comment -> comment.getParent() == null )//부모댓글만 조회 ( 이유 : 부모댓글이 자식댓글까지 포함하고있기 때문임)
        .map(ContactCommentResponse::new)
        .sorted(Comparator.comparing(ContactCommentResponse::getCreatedDate))
        .collect(Collectors.toList());

  }

부모댓글이 null 값인 것만 가져오기위해 inquiry service에서 처리 하던 이부분을

List<ContactComment> parentComments = contactCommentService.findAllByInquiryIdAndParentIsNull( id);

Stream().Filter()메소드를 이용하여 필터처리 해주었다.



inquiryService 중 연관관계 매핑후 inquiry 삭제시 자동으로 관련 comment 삭제가 가능하도록 옵션처리하여 아래처럼 불필요한 부분은 주석처리(삭제예정) 했다.

  @Transactional
  @Override
  public void deleteInquiry(Long id, String username, UserRoleEnum role) {
    Inquiry inquiry = findById(id);
    isWriterAndIsManager(inquiry, username, role);
    inquiryRepository.delete(inquiry);
    // 문의글 해당 댓글 삭제
   // contactCommentService.deleteAllByInquiryId(id);
    

4 . 알게 된점

연관관계 후 성능 최적화시
1. 컬렉션 최적화 경우

  • 페치조인 사용시 쿼리는 1번으로 줄어들지만 페이징을 할수 없으므로 페이징이 필요없을때 사용
  • 페이징이 필요하다면 -> bench_size 를 통해서 가능하다.
  1. 나머지는 페치조인으로 성능최적화가 거의 가능하다.
profile
개발자꿈나무

0개의 댓글