반응형
Notice
Recent Posts
Recent Comments
관리 메뉴

간단한 개발관련 내용

JPA @Id 를 멤버변수로 선언 VS 생성자로 선언 본문

Framework/JPA

JPA @Id 를 멤버변수로 선언 VS 생성자로 선언

vincenzo.dev.82 2024. 12. 9. 23:17
반응형

코틀린 언어 기반으로 JPA 엔티티의 id 필드를 생성자에 포함시키는 방식과 별도로 필드로 선언하고 protected set을 사용하는 방식은 몇 가지 차이점이 있습니다. 각각의 장단점과 사용 사례를 비교해보겠습니다.


1. id를 생성자에 포함시키는 방식

@Entity
data class Car(
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    val id: Long? = null,
    val brand: String,
    val model: String
)

특징

  • 불변성: val로 선언되므로 생성 후 값이 변경되지 않아 객체가 불변(immutable)에 가까워집니다.
  • 초기화 간결성: id 필드도 생성자에서 초기화되므로 Kotlin의 데이터 클래스 특성을 그대로 활용할 수 있습니다.
  • 가독성: 코드가 더 간결하고 읽기 쉽습니다.
  • 제약 사항:
    • JPA는 기본 생성자와 객체 상태를 수정 가능한 상태로 두는 것을 기본으로 설계되었습니다. val로 설정된 id는 JPA 내부적으로 값을 변경할 수 없으므로(불변성) JPA 구현체가 이를 처리하는 데 어려움을 겪을 수 있습니다.
    • Hibernate와 같은 JPA 구현체는 종종 리플렉션을 사용하여 필드 값을 설정하기 때문에, 생성자 기반 초기화를 사용할 경우 일부 기능과 충돌할 가능성이 있습니다.

 

2. 별도 필드 선언 + protected set 사용

@Entity
class Car(
    val brand: String,
    val model: String
) {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    var id: Long? = null
        protected set
}

특징

  • JPA 친화적: JPA 구현체가 리플렉션을 통해 id 값을 설정할 수 있도록 필드의 가시성을 protected로 제한합니다. 이는 JPA 스펙과 잘 맞습니다.
  • 변경 가능성: var로 선언되었기 때문에, 초기화 후에도 값이 변경될 가능성이 있지만, protected set을 통해 외부에서의 변경을 방지합니다.
  • 유연성: JPA의 라이프사이클과 객체 초기화 요구 사항을 모두 만족시킵니다.
  • 객체 불변성 저하: 데이터 클래스처럼 불변 객체로 설계하려는 경우 불변성 유지가 어렵습니다.

 

차이점 요약

특성 생성자 포함 방식 protected set 방식

불변성 불변 객체로 설계 가능 (val) 부분적으로만 불변 (var)
JPA 호환성 JPA와 일부 구현체에서 예상치 못한 동작 발생 가능성 있음 JPA와 완벽히 호환
코드 간결성 간결하고 읽기 쉬움 다소 장황할 수 있음
외부 접근 가능성 id에 대한 외부 접근 불가능 외부에서 읽기 가능하지만, 쓰기는 제한 (protected set)
객체 생명주기 제어 생성자 기반으로 초기화가 명확 JPA 구현체에 의해 객체 생명주기가 제어됨

언제 어떤 방식을 사용할까?

  1. 생성자 포함 방식
    • JPA 사용 시 초기화 후 id 값이 변경되지 않도록 설계하고 싶을 때.
    • 엔티티를 다른 시스템(예: DDD와 같은 도메인 중심 설계)에서 주로 활용하려고 할 때.
    • 데이터베이스 매핑보다는 도메인 객체로서의 역할이 더 중요한 경우.
  2. protected set 방식
    • JPA 호환성을 최우선으로 고려할 때.
    • JPA가 엔티티 생명주기를 관리하는 데 완전한 제어권을 가져야 할 때.
    • id 값이 외부에서 변경되지 않으면서도, JPA 구현체가 내부적으로 값을 설정할 수 있어야 할 때.

결론

  • JPA 친화적이고 일반적으로 사용할 때는 protected set 방식이 더 안전하고 널리 사용되는 방식입니다.
  • 하지만 JPA 구현체의 동작을 잘 이해하고 있으며 불변성 유지와 도메인 객체로서의 역할을 중시한다면, 생성자 포함 방식도 사용할 수 있습니다.

두 방식을 혼용하는 것도 가능합니다. 예를 들어, id를 val로 두면서 리플렉션과 기본 생성자를 활용해 JPA와 호환성을 확보할 수 있는 방법을 선택할 수도 있습니다.

 

반응형