트러블슈팅
[JPA] OneToMany 에서 child 를 지웠는데 update 쿼리가 날아간다고?
녹차와새우탕
2020. 11. 5. 14:08
현재 코드
단방향 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
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 // 주인관계 설정된 곳에 부모 엔티티 입력
}
)