프로그래밍/JPA
QueryDSL JPA 1:N 관계에서 N의 조건 추가
Seop
2024. 3. 13. 21:54
프로젝트에서 데이터의 삭제를 물리적 삭제가 아닌 논리적 삭제로 처리를 하고 있다.
그렇기에 데이터를 조회할 때 해당 데이터의 삭제일자 값을 통해 삭제 여부를 확인하는데 1:N 관계의 entity에서 고민이 생겼다.
문의내역에는 답변이 존재하는데 이는 1:N 관계이고 엔티티는 아래와 같이 생겼다.
public class Question extends BaseEntity {
@Comment("문의사항 작성자")
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "member_id", columnDefinition = "BIGINT", foreignKey = @ForeignKey(ConstraintMode.NO_CONSTRAINT))
private Member member;
@Comment("문의사항 제목")
@Column(name = "title", columnDefinition = "VARCHAR(200)")
private String title;
@Comment("문의사항 내용")
@Column(name = "content", columnDefinition = "MEDIUMTEXT")
private String content;
@Comment("답변 여부")
@Column(name = "status", columnDefinition = "VARCHAR(20)")
@Convert(converter = QuestionStatusConverter.class)
private QuestionStatus status;
@Builder.Default
@OneToMany(fetch = FetchType.LAZY, mappedBy = "question")
private List<Answer> answers = new ArrayList<>();
public void addMember(Member member) {
this.member = member;
member.getQuestions().add(this);
}
public void updateQuestion(String title, String content) {
this.title = title;
this.content = content;
}
public void updateStatus(QuestionStatus status) {
this.status = status;
}
}
public class Answer extends BaseEntity {
@Comment("문의사항 답변 작성자")
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "member_id", columnDefinition = "BIGINT", foreignKey = @ForeignKey(ConstraintMode.NO_CONSTRAINT))
private Member member;
@Comment("답변이 속한 문의사항")
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "question_id", columnDefinition = "BIGINT", foreignKey = @ForeignKey(ConstraintMode.NO_CONSTRAINT))
private Question question;
@Comment("답변 내용")
@Column(name = "content", columnDefinition = "MEDIUMTEXT")
private String content;
public void addQuestion(Question question) {
this.question = question;
this.question.updateStatus(QuestionStatus.COMPLETE);
question.getAnswers().add(this);
}
public void updateContent(String updateContent) {
this.content = updateContent;
}
}
Answer은 직접 조회하는게 아닌 대게 Question 을 통해서 조회가 되는데
쉽게 생각한다면 아래와 같이 쿼리메서드를 통해서 처리를 할 수 있을거다.
Optional<Question> findByIdAndDeletedAtIsNullAndAnswersDeletedAtIsNull(Long id);
하지만 이는 JPA 쿼리메서드 규칙을 위반한 것으로 동작이 되지 않는다.
JPQL을 작성해도 되지만 이것 또한 프로젝트에서 최대한 QueryDSL JPA 를 활용하기로 하여 아래와 같이 작성을 하였다.
@Override
public Optional<Question> findQuestion(Long id) {
BooleanExpression conditions =
question.id.eq(id)
.and(question.deletedAt.isNull())
.and(answer.deletedAt.isNull());
return Optional.of(jpaQueryFactory
.selectFrom(question)
.leftJoin(question.answers, answer).fetchJoin()
.where(conditions)
.fetchFirst());
}
나는 where에서 사용을 하는 조건 절을 BooleanExpression 을 통해서 미리 생성을 하고 최대한 queryFactory를 보기 쉽게 가져가는 것이 가독성에 좋다고 생각하여 이러한 선택을 했다.