섭섭한 개발일지

QueryDSL JPA 1:N 관계에서 N의 조건 추가 본문

프로그래밍/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를 보기 쉽게 가져가는 것이 가독성에 좋다고 생각하여 이러한 선택을 했다.

Comments