Spring/Spring Boot

[Spring Boot] JPA @MapsId를 이용한 FK를 PK로 사용하기

JoonYong 2024. 7. 23. 14:35

 

이번 프로젝트에서 JPA 엔티티를 설계하면서 외래 키를 기본 키로 사용하는 경우를 마주하게 되었습니다. 이 과정에서 활용한 기능이 바로 @MapsId입니다. 이 글에서는 @MapsId 어노테이션을 사용하여 외래 키를 기본 키로 설정하는 방법과 그 이점에 대해 설명하고자 합니다.

1. 프로젝트 배경

이번 프로젝트에서는 Profile 엔티티와 ProfileImage 엔티티 간의 관계를 설정해야 했습니다. Profile 엔티티는 유저의 프로필 정보를 담고 있으며, ProfileImage 엔티티는 프로필 이미지 정보를 저장합니다. 이때, ProfileImage 엔티티의 기본 키로 Profile 엔티티의 기본 키를 사용하고자 했습니다. 이를 구현하기 위해 JPA의 @MapsId 어노테이션을 활용하게 되었습니다.

2. @MapsId 소개

@MapsId 어노테이션은 JPA에서 외래 키를 기본 키로 매핑할 때 사용됩니다. 이를 통해 특정 필드가 다른 엔티티의 기본 키와 동일하게 매핑되도록 지정할 수 있습니다. 예를 들어, ProfileImage 엔티티의 profile_id 필드를 Profile 엔티티의 기본 키로 설정할 수 있습니다.

3. 엔티티 설정

3.1) Profile 엔티티를 정의

이 엔티티는 기본적인 유저 프로필 정보를 포함합니다.

@Entity
@Table(name = "profile")
@Getter
@Setter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Profile {

  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  @Column(name = "profile_id", nullable = false)
  private Long profileId;

  @Column(nullable = false, unique = true)
  private String userId;

  @Column(nullable = false)
  private String nickname;

  @Column(nullable = false)
  private String introduce;

  @ManyToOne(fetch = FetchType.LAZY)
  @JoinColumn(name = "account_id", nullable = false)
  private Account account;

  @OneToOne(mappedBy = "profile", cascade = CascadeType.ALL, fetch = FetchType.LAZY, optional = false)
  private ProfileImage profileImage;

}

3.2) ProfileImage 엔티티를 정의

이 엔티티는 Profile 엔티티의 기본 키를 외래 키이자 기본 키로 사용합니다.

@Entity
@Table(name = "profile_image")
@Getter
@Setter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class ProfileImage {

  @Id
  @Column(name = "profile_id", nullable = false)
  private Long profileId;

  @OneToOne(fetch = FetchType.LAZY)
  @MapsId
  @JoinColumn(name = "profile_id")
  private Profile profile;

  @Column(name = "image_url", nullable = false)
  private String imageUrl;

}

4. @MapsId 사용 이유

@MapsId 어노테이션을 사용하면 다음과 같은 이점이 있습니다.

  1. 단순화된 식별 관계: 외래 키를 기본 키로 사용함으로써 엔티티 간의 관계를 더 단순하고 명확하게 정의할 수 있습니다. 이는 데이터 무결성을 보장하는 데 도움이 됩니다.
  2. 명확한 설계 의도 표현: @MapsId를 통해 특정 엔티티의 생명주기가 다른 엔티티에 종속적임을 명확히 할 수 있습니다. 예를 들어, ProfileImage는 Profile에 종속적이므로 Profile이 없으면 ProfileImage도 존재할 수 없습니다.
  3. JPA 프록시 지원: 기본 생성자의 접근 제어를 통해 JPA 구현체가 엔티티를 프록시로 생성할 수 있도록 합니다. 이는 지연 로딩을 사용할 때 중요한 역할을 합니다.

5. 결론

이번 프로젝트에서 @MapsId를 활용하여 외래 키를 기본 키로 설정함으로써 엔티티 간의 관계를 더 명확하게 정의하고, 데이터 무결성을 보장할 수 있었습니다. 이를 통해 JPA를 사용하는 Spring 애플리케이션에서 객체의 상태를 보다 효과적으로 관리할 수 있었습니다.