개발블로그

HHH000502 warning :: entity was modified, but it won't be updated because the property is immutable. 원인 해결 본문

Spring

HHH000502 warning :: entity was modified, but it won't be updated because the property is immutable. 원인 해결

개발자수니 2021. 6. 26. 14:48

해당 경고는 영속성 컨텍스트가

"엔티티가 변경되었는데, 그 엔티티의 속성이 updatable = false 라서 못바꿔~ " 라고 알려주는 경고이다. 


상황

1. Product 엔티티와 User 엔티티가 연관관계의 상태

@Entity
data class Product(

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id", nullable = false)
    override var id: Long? = null,
    
    @Column(name = "uid", nullable = false)
    val uid: Long
    
    ...생략...
) {

    @JsonIgnore
    @OneToTone(targetEntity = ProductExtra::class, fetch = FetchType.LAZY)
    @JoinColumn(
        name = "id",
        referencedColumnName = "id",
        insertable = false,
        updatable = false,
        foreignKey = ForeignKey(ConstraintMode.NO_CONSTRAINT)
    )
    lateinit var extra: ProductExtra

    @JsonIgnore
    @ManyToOne(targetEntity = User::class, fetch = FetchType.LAZY, optional = false)
    @JoinColumn(
        name = "uid",
        referencedColumnName = "id",
        insertable = false,
        updatable = false,
        foreignKey = ForeignKey(ConstraintMode.NO_CONSTRAINT)
    )
    lateinit var user: User
  }

2. Product 수정 로직에서 변경 전 데이터와 변경 후 데이터를 비교하여 Kinesis Stream을 보내야해서 아래와 같은 순서의 로직을 구성했다.

    1) Product 조회 (prev)

    2) 조회된 Product Copy (next)

    3) next에 변경되어야할 데이터 반영

    4) next save

    5) prev, next 비교 후 Stream 전송


문제는 Copy 로직에 있었다. 

kotlin에 내장되어있는 copy function은 생성자에 있는 프로퍼티만 copy해주기 때문에 연관관계에 있는 프로퍼티는 null이 된다.

따라서 별도의 copy function을 만들고 있었다. 

    companion object {
        fun copy(
            product: Product,
            name: String? = null
        ): Product {
            return product.copy(
                name = name ?: product.name
            ).apply {
                ..생략..
                this.extra = product.extra
                this.user = product.user           #### 누락시킨 것이 원인 ####
            }
        }
    }

 

그런데 user를 copy하는 코드를 누락시켰던 것이다.

this.user = product.user

 


위 코드를 누락시키면 어떤 일이 발생하는지 생각해보자. 
  • Product 조회시 영속성 컨텍스는 user 데이터를 Proxy 객체로 가지고 있었다. 
  • 그런데 Copy 하고나니 user가 null이 되었고, 영속성 컨텍스트 입장에서는 user 프로퍼티가 proxy 객체에서 null로 변경된 것이다.
  • 그래서 변경점을 반영하려고 하는데, updatable = false 속성으로 인해 변경할 수가 없어서 경고가 발생한 것이다.
    @JsonIgnore
    @ManyToOne(targetEntity = User::class, fetch = FetchType.LAZY, optional = false)
    @JoinColumn(
        name = "uid",
        referencedColumnName = "id",
        insertable = false,
        updatable = false,
        foreignKey = ForeignKey(ConstraintMode.NO_CONSTRAINT)
    )
    lateinit var user: User

 

Comments