@Embeddable을 이용한 PK 테이블 생성
SNS 백엔드 서버의 팔로우 기능을 구현하면서 서로 다른 유저의 관계를 Follow 테이블로 묶어야 하는 일이 발생했다. 저번 프로젝트에서 멘토님이 이런 경우 복합키를 사용하는 것을 추천해주셨는데 이번에 적용해보기로 했다.
복합키는 아래와 같이 PK테이블을 별도로 만들어 사용하면 되는데 @Embeddable을 이용해 구성할 수 있다. 아래와 같이 관계를 엮을 두개의 키를 선언해주면 되고 해당 FollowPK를 이용하는 Follow 테이블은 기존 방식처럼 follow_id를 가지는 것이 아니라 아래처럼 두개의 id를 PK로 가지게 되는 것이다.
@Embeddable
@EqualsAndHashCode
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class FollowPK implements Serializable {
@Column(name = "following_id")
private Long followingId;
@Column(name = "follower_id")
private Long followerId;
@Builder
public FollowPK(Long followingId, Long followerId) {
this.followingId = followingId;
this.followerId = followerId;
}
}
FollowPK를 만들었으면 Follow테이블에서 @EmbeddedId를 이용해 FollowPK를 선언해주면 된다. 그리고 아래와 같이 원하는 객체를 매핑해준다. 이때 주의할점은 @MapsId를 이용할때 값으로 column 이름을 주는 것이 아니라 FollowPK테이블에 선언한 필드명을 넣어줘야한다는 것이다.
@Entity
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Follow extends Timestamped {
@EmbeddedId
private FollowPK followPK;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "following_id")
@MapsId("followingId")
private User following;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "follower_id")
@MapsId("followerId")
private User follower;
@Builder
public Follow(User following, User follower) {
this.following = following;
this.follower = follower;
this.followPK = FollowPK.builder()
.followingId(following.getId())
.followerId(follower.getId())
.build();
}
}
마지막으로, 아래와 같이 생성해서 사용한다. Follow객체를 생성할때, FollowPK를 이용해야할 것 같지만 그렇지 않다. 복합키 구조를 잘 만들어놓으면 spring에서 알아서 pk를 설정해주고 개발할때는 다른 객체들과 마찬가지로 필요한 데이터를 주입해 사용한다.
Follow follow = Follow.builder()
.following(user)
.follower(followUser)
.build();
hibernate의 ddl-auto를 이용해 생성된 테이블을 보면 아래와 같이 follow 테이블의 기본키 1개가 생성되는것이 아닌 복합키로 설정한 follower_id와 following_id가 PK로 2개가 설정되어 있는 것을 확인할 수 있다.