본문 바로가기

트러블슈팅

[JPA] OneToMany 에서 child 를 지웠는데 update 쿼리가 날아간다고?

현재 코드

단방향 OneToMany 매핑, AccountGroupDetails 에서는 매핑관계 없음

부모 클래스에서 자식 클래스 CRUD 를 모두 하려고 함

식별관계 - 부모키가 자식PK 에 포함

 

@Entity
data class AccountGroup(
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    var accountGroupId: Long? = null
    ...
    ...
    ...
) {
    @OneToMany(fetch = FetchType.LAZY, targetEntity = AccountGroupDetails::class, cascade = [CascadeType.ALL], orphanRemoval = true)
    @JoinColumn(name = "accountGroupId", referencedColumnName = "accountGroupId")
    var accountGroupDetails: MutableList<AccountGroupDetails> = mutableListOf()
}

 

문제점

입력은 잘됨

수정도 잘됨

삭제가 안됨!!!

삭제했더니 update 쿼리가 날아간다~~~~~~~~~

/* delete one-to-many row ..... */ update account_group_detail........

 

원인

일대다 단방향 매핑에서 parent.children.remove(child)는 사실 child 자체를 삭제하라는 게 아니라 child가 parent의 children의 하나로 존재하는 관계를 remove 하라는 것이다. 따라서 child 자체를 delete 하는 게 아니라 child 의 parent_id에 null 값을 넣는 update를 실행하는 게 정확히 맞다. 이 부분의 코드도 신동민 님이 알려주셨는데 여기에서 확인할 수 있다.
https://github.com/hibernate/hibernate-orm/blob/master/hibernate-core/src/main/java/org/hibernate/persister/collection/OneToManyPersister.java

참고 : homoefficio.github.io/2019/04/28/JPA-%EC%9D%BC%EB%8C%80%EB%8B%A4-%EB%8B%A8%EB%B0%A9%ED%96%A5-%EB%A7%A4%ED%95%91-%EC%9E%98%EB%AA%BB-%EC%82%AC%EC%9A%A9%ED%95%98%EB%A9%B4-%EB%B2%8C%EC%96%B4%EC%A7%80%EB%8A%94-%EC%9D%BC/

 

JPA 일대다 단방향 매핑 잘못 사용하면 벌어지는 일

JPA 일대다 단방향 매핑 잘못 사용하면 벌어지는 일Parent : Child = 1 : N 의 관계가 있으면 일대다 단방향으로 매핑하는 것보다 일대다 양방향으로 매핑하는 것이 좋다. 왜 그런지 구체적으로 살펴보

homoefficio.github.io

 

해결법

양방향 매핑으로 바꾸면 된다.

// 부모 클래스 매핑
@Entity
data class AccountGroup(
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    var accountGroupId: Long? = null
    ...
    ...
    ...
) {
    @OneToMany(fetch = FetchType.LAZY, targetEntity = AccountGroupDetails::class, mappedBy = "accountGroup" cascade = [CascadeType.ALL], orphanRemoval = true)
    var accountGroupDetails: MutableList<AccountGroupDetails> = mutableListOf()
}

 

// 자식클래스 매핑
@Entity
data class AccountGroupDetail(
    @EmbeddedId
    val accountGroupDetailId: AccountGroupDetailId
    ...
    ...
) {
    @MapsId("accountGroupId")
    @ManyToOne(fetch = FetchType.LAZY, optional = false)
    @JoinColumn(name = "accountGroupId")
    lateinit var accountGroup: AccountGroup
}

 

// 입력
accountGroup.accountGroupDetails.add(
    AccountGroupDetail(AccountGroupDetailId(...)).apply {
        this.accountGroup = accountGroup // 주인관계 설정된 곳에 부모 엔티티 입력
    }
)