PHP로 이루어진 사내 서버를 Spring으로 이전하는 작업중 상당수의 테이블이 복합키로 이루어진 것을 확인하고 JPA에서 복합키를 Entity로 풀어낼 수 있는 방법을 찾아보았습니다.
정확하지 않고 오류가 있는 부분이 있을 수 있습니다. 구현해보시면서 오류나는 부분 있으시면 같이 공유해서 알아가면 좋을 것 같습니다!
JPA에서 복합키는 두가지 방법을 표현할 수 있다고 합니다.
첫번째 방법이 @EmbededId
어노테이션을 사용하는 방법이고 다른 방법은 @IdClass
를 사용하는 방법입니다.
@EmbededId
는 @IdClass
에 비해 복합키 표현을 더 객체지향적으로 해주지만 복합키로 구성된 계층(복합키 안 FK가 존재할 때)이 복잡해질수록 표현이 어려워집니다.
예를 들어 복합키 안에 복합키 또 복합키... 같이 구성된 연관관계가 존재하면 아래와 같이 복잡한 그래프 탐색을 수행하게되어 구조가 복잡해집니다.
payShop.getId().getPayDetailId().getPayId().getPayNumber();
사내 서버는 복합키 자체는 많은데 두 뎁스 이상의 연결이 없어 충분히 @EmbededId
방식을 사용할 수 있을 것 같았습니다.
그래서 @EmbededId
방식으로 사내 테이블중 하나인 MapTables를 구현해보았습니다.
@EmbededId
@EmbededId
는 복합키를 하나의 객체로 묶은 후 해당 객체를 Entity에서 사용하는 방식으로 구현됩니다.
@Getter
@Embeddable
@NoArgsConstructor
public class MapTablesPK implements Serializable {
@Column(name = "map_id")
private Integer mapId;
@Column(name = "table_id")
private Integer tableId;
public MapTablesPK(Integer mapId, Integer tableId) {
this.mapId = mapId;
this.tableId = tableId;
}
}
다음과 같이 MapTablesPK 라는 클래스 안에 MapTables에서 사용되는 PK를 필드로 넣어줍니다.
해당 클래스는 Serializable
을 implements 하고 @Embeddable
어노테이션을 사용합니다.
이후 MapTables Entity에서는 다음과 같이 MapTablesPK 객체를 사용합니다.
@Getter
@Entity
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class MapTables {
@Id
@EmbeddedId
private MapTablesPK mapTablesPK;
@MapsId(value = "mapId")
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "map_id" , referencedColumnName = "map_id")
private Maps maps;
MapTablesPK 클래스에 @EmbededId
와 @Id
어노테이션을 사용하여 복합키로 구성된 PK임을 명시해줍니다.
이때 MapTables의 경우 복합키에서 사용되는 컬럼(map_id, table_id) 중 map_id는 Map과 연결된 FK입니다.
이를 구현하기 위해 해당 필드(mapId)를 연관관계 맵핑(N:1) 해줘야하는데 이때 MapTablesPK에 들어가있는 mapId와 연관관계를 맵핑하지 않고 MapTables Entity안에 Maps 객체를 새로 생성하여 연관관계를 맵핑해줍니다.
그래서 @ManyToOne
, @JoinColumn
어노테이션을 MapTablesPK 안 mapId 가 아닌 MapTables에 새로운 Maps를 생성 후 어노테이션을 명시해줬습니다.
여기서 기존 연관관계 맵핑과의 차이점은 @MapsId(value = "mapId")
부분입니다. 해당 어노테이션을 통해 Maps 객체의 'mapId' 라는 필드를 기준으로 FK를 연결해줄 수 있습니다.
@EmbededId
사용시 필수 조건@Embeddable
어노테이션을 붙여주어야 함Serializable
인터페이스 구현해야 함equals
, hashCode
구현해야함public
이어야 함https://techblog.woowahan.com/2595/
https://docs.jboss.org/hibernate/jpa/2.1/api/javax/persistence/MapsId.html