강의

멘토링

로드맵

인프런 커뮤니티 질문&답변

진우님의 프로필 이미지
진우

작성한 질문수

QueryDSL + leftJoin + on + fetchJoin 오류 문의 드립니다.

작성

·

1.2K

0

@Entity
@Table(name = "tbl_board")
class Board (
    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    val bdSeq: Int? = null,

    var bdTitle: String?,

    var bdContents: String?,

    var bdRegdt: LocalDateTime? = LocalDateTime.now(),

    @OneToMany(fetch = FetchType.LAZY, mappedBy = "board")
    @Filter(name = "filterTest", condition = "bdcSeq = :bdcSeq")
    var boardCmts: MutableSet<BoardCmt> = mutableSetOf(),

    @OneToMany(fetch = FetchType.LAZY, mappedBy = "board")
    var boardTags: MutableSet<BoardTag> = mutableSetOf()
)

@Entity
@Table(name = "tbl_board_cmt")
class BoardCmt(
    @Id @GeneratedValue(strategy = GenerationType.IDENTITY)
    val bdcSeq: Int? = null,

    @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "bd_seq")
    var board: Board?,

    var bdcContents: String?,

    @OneToMany(fetch = FetchType.LAZY, mappedBy = "boardCmt")
    var boardCmtTags: MutableSet<BoardCmtTag> = mutableSetOf()
)

두개의 엔티티가 있는데

val board = QBoard.board
val boardTag = QBoardTag.boardTag
val boardCmt = QBoardCmt.boardCmt

val rows = query.select(board, boardCmt)
    .from(board)
    .leftJoin(board.boardCmts, boardCmt).on(boardCmt.bdcSeq.notIn(100)).fetchJoin()
    .fetch()

// 오류
// org.hibernate.query.SemanticException: with-clause not allowed on fetched associations; use filters

오류가 발생합니다.

fetchJoin을 쓰면 on을 못쓰고 on을 쓰면 fetchJoin을 못쓰는 상황입니다.

이와 관련해서 솔루션이 없는게 이해가 안되요. github나 stackoverflow나...

제가 유일하게 찾은 솔루션은 두개

// case 1 (query에서 on 조건을 빼고 kotlin에서 filter를 이용해서 처리)
// comment 데이터가 많을수록 db성능 최악

val board = QBoard.board
val boardCmt = QBoardCmt.boardCmt

var rows = query.selectFrom(board)
    .leftJoin(board.boardCmts, boardCmt).fetchJoin()
    .fetch()        

rows = rows.map { 
    it.boardCmts.filter { f -> f.bdcSeq != 100 }
    it
}

 

// case 2 (Tuple로 각각 받아와서 board 엔티티에 밀어넣기
// 쿼리성능에 이슈가 없지만 매핑하는데 피로도 상승
val rows = query.select(board, boardCmt)
    .from(board)    
    .leftJoin(board.boardCmts, boardCmt).on(boardCmt.bdcSeq.notIn(100))
    .fetch()

return rows.fetchTest(board) { entity, fetchData ->
    entity.boardCmts = mutableSetOf()
    fetchData.forEach {
        it.get(boardCmt)?.let { item -> entity.boardCmts.add(item) }
    }
}.map { it.toDto() }

테이블마다 DEL_YN 필드가 들어가는 바람에

leftjoin시 필수로 on(board.delYn.eq("Y)) 가 들어가야 되는 상황인데

fetchJoin은 성능상 꼭 쓰고싶고, on은 반드시 들어갸야되고
참 어렵습니다.

답변 1

0

안녕하세요, 인프런 AI 인턴이에요.

fetchJoin과 on 절을 동시에 사용하면 with-clause not allowed on fetched associations; use filters 오류가 발생하게 됩니다. 이 오류는 Hibernate 성능과 일관성을 보장하기 위한 제한입니다. 두 가지를 함께 사용하려면 하나를 필터로 변경해야 합니다. 따라서, case 1에서는 query에서 on 조건을 제거하고, Kotlin의 filter를 사용해서 처리할 수 있고, case 2에서는 각각의 값을 Tuple 로 받아와 board 엔티티에 밀어넣는 방법으로 해결할 수 있습니다.

데이터의 양이 많아지면 성능 이슈가 발생할 수 있는데, 이 경우에는 쿼리문이 복잡해질 수밖에 없습니다.

마지막으로, DEL_YN 필드가 들어가서 반드시 on(board.delYn.eq(“Y”)) 가 들어가야 하는 상황이라면, on 절을 잘 작성하여 fetchJoin을 성공적으로 수행하실 수 있습니다.

도움이 되었기를 바라며, 추가적으로 궁금하신 사항이 있으면 언제든지 문의해주세요. 감사합니다.

진우님의 프로필 이미지
진우

작성한 질문수

질문하기