[TIL] Spring JPA 복합키 설정하기

seaStamp·2023년 12월 14일
0

TIL

목록 보기
30/33
post-thumbnail

복합키를 사용하는 법

복합키란?

  • PrimaryKey없이 ForignKey가 2개인 경우
    (사용예시 : 중간 매핑 테이블)

@IdClass를 사용

@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)

// jpa
@Entity
@IdClass(UserChannelId.class) // 이 부분을 추가한다
public class UserChannel {

    @Builder
    public UserChannel(User user, Channel channel){
        this.user = user;
        this.channel = channel;
    }

    @Id
    @ManyToOne
    @JoinColumn(name = "user_id")
    private User user;

    @Id
    @ManyToOne
    @JoinColumn(name = "channel_id")
    private Channel channel;

}
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED) // 기본생성자 필요
public class UserChannelId implements Serializable {
    private Long user;   // UserChannel 의 user 필드명과 동일해야함
    private Long channel; // UserChannel 의 channel 필드명과 동일해야함

//equals와 hashcode를 구현해놔야한다
    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        UserChannelId userChannelId = (UserChannelId) o;
        return Objects.equals(getUser(), userChannelId.getUser()) && Objects.equals(getChannel(), userChannelId.getChannel());
    }

    @Override
    public int hashCode() {
        return Objects.hash(getUser(), getChannel());
    }
}

@EmbededId를 사용


//lombok
@Setter
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)

// jpa
@Entity
public class UserChannel {


    @EmbeddedId // 연결을 위해 추가
    private UserChannelId userChannelId;

    
    @Builder
    public UserChannel(User user, Channel channel) {
        this.user = user;
        this.channel = channel;
    }

    @ManyToOne
    @MapsId("userId") // !!복합키 필드에 대한 매핑
    @JoinColumn(name = "user_id") // !!실제 테이블의 외래키 컬럼
    User user;

    @ManyToOne
    @MapsId("channelId") // !!복합키 필드에 대한 매핑
    @JoinColumn(name = "channel_id") // !!실제 테이블의 외래키 컬럼
    Channel channel;

}
@Setter
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED) // 기본생성자 필요
@Embeddable // 연결을 위해 추가
public class UserChannelId implements Serializable { // Serializable 구현체

    @Column(name = "user_id") // 실제 테이블의 외래키 컬럼
    private Long userId;

    @Column(name = "channel_id") // 실제 테이블의 외래키 컬럼
    private Long channelId;

// 마찬가지로 equals와 hashcode 구현
    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }
        UserChannelId userChannelId = (UserChannelId) o;
        return Objects.equals(getUserId(), userChannelId.getUserId()) && Objects.equals(
            getChannelId(), userChannelId.getChannelId());
    }

    @Override
    public int hashCode() {
        return Objects.hash(getUserId(), getChannelId());
    }

}

Raw JPA로 구현시 사용법

단일 키로 구현했을 때 UserChannelRepository는

public UserChannel insertUserChannel(UserChannel userChannel) {
        entityManager.persist(userChannel);
        return userChannel;
    }

이렇게 하면 됐지만,

만약 위의 entity에 대한 Repository를 구현하면

public UserChannel insertUserChannel(UserChannel userChannel) {
        // UserChannelId 객체를 가져온다.
        UserChannelId userChannelId = userChannel.getUserChannelId();

        // 만약 UserChannelId가 없다면 새로 생성.
        if (userChannelId == null) {
            userChannelId = new UserChannelId();
            userChannel.setUserChannelId(userChannelId); // UserChannel에 UserChannelId를 설정합니다.
        }

        // 여기서 channelId를 설정
        userChannelId.setChannelId(userChannel.getChannel().getId());

        entityManager.persist(userChannel);
        return userChannel;
    }

이렇게 설정해야 제대로 동작하는 것을 확인할 수 있다.

profile
우선은 부딪히고 보자

0개의 댓글