low level 로 연관관계 매핑을 하지 않고 일일히 필요한 객체의 데이터를 가지고 와서 연관관계 된것처럼 사용했다. 이번에는 매핑을 시켜보고 차이점을 느껴보려고 한다.
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 이부분에서 부모댓글과 자식댓글이 잘나오지만 , 자식댓글들을 한번씩 더 가져오는 현상이 발생한다.
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);
연관관계 후 성능 최적화시
1. 컬렉션 최적화 경우