@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());
}
}
//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());
}
}
단일 키로 구현했을 때 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;
}
이렇게 설정해야 제대로 동작하는 것을 확인할 수 있다.