최근 진행하는 프로젝트는 DB 관련 기술로 JPA를 사용하고 있는데, 연동 대상은 레거시 DB이다. 레기서 DB답게 복합키를 갖는 테이블이 다수 존재한다. 아래는 한 예이다.
이 테이블은 특정 업무의 점검 결과를 저장할 때 사용하는데(간결함을 위해 이름을 변경하고 칼럼수도 줄였다), CHECK_H는 점검 결과에 대한 마스터 테이블이고, CHECK_D는 각 세부 점검 항목의 결과를 저장하는 테이블이다. CHECK_H와 CHECK_D는 1:N의 관계를 갖는다.
그림에서 보는 것처럼 CHECK_H의 PK는 네 개의 칼럼을 구성되어 있으며, CHECK_D는 이 네 칼럼을 참조한다.
검사 항목은 20여개 정도 되는데, 각 항목을 그룹으로 나눠서 표현한다. 각 항목이 속한 그룹을 저장하는 칼럼이 GROUP이고 검사 항목을 저장하는 칼럼이 ITEM이며, 그 결과를 저장한 칼럼이 RSLT이다. 화면에 결과를 표시할 때에는 GROUP과 ITEM을 오름차순으로 정렬해서 출력한다.
CHECK_H와 CHECK_D는 개념적으로 하나의 검사 결과를 의미하므로, 이 둘과 매핑되는 모델은 하나의 애그리거트에 포함된다. 매핑할 애그리거트를 다음과 같이 만들었다.
CHECK_D는 별도 라이프사이클이 없고 CHECK_H에 종속되어 있으므로 CHECK_D에 매핑되는 Detail을 밸류로 표현했고, Check를 애그리거트의 루트로 했다. 복합키를 사용하므로 복합키에 해당하는 식별자 클래스인 CheckId도 따로 만들었다.
Detail 클래스와 CHECK_D 테이블의 매핑 설정
Detail은 밸류이므로 CHECK_D의 주요키와 매핑할 필요가 없으므로 밸류가 가져야 할 속성만 정의했다.
@Embeddable
public class Detail {
private String group;
private String item;
private String rslt;
...
}
Check 클래스와 CHECK_H 테이블의 매핑 설정
복합키를 위한 CheckId는 다음과 같다.
@Embeddable
public class CheckId implements Serializable {
@Column(name = "JOIN_NUM")
private String joinNum;
@Column(name = "PATH_FLAG")
private String pathFlag;
@Column(name = "JOIN_YMD")
private String joinYmd;
@Column(name = "RSLT_FLAG")
private String rsltFlag;
}
다음은 Check 클래스 설정이다.
@Entity
@Table(name = "CHECK_H")
public class Check {
@EmbeddedId
private CheckId id;
@Column(name = "FROM_TIME")
private String fromTime;
@Column(name = "TO_TIME")
private String toTime;
@ElementCollection(fetch = FetchType.EAGER)
@CollectionTable(name = "CHECK_D", joinColumns = {
@JoinColumn(name = "JOIN_NUM", referencedColumnName = "JOIN_NUM"),
@JoinColumn(name = "PATH_FLAG", referencedColumnName = "PATH_FLAG"),
@JoinColumn(name = "JOIN_YMD", referencedColumnName = "JOIN_YMD"),
@JoinColumn(name = "RSLT_FLAG", referencedColumnName = "RSLT_FLAG") })
@org.hibernate.annotations.OrderBy(clause = "GROUP asc, ITEM asc")
private Set<CheckDetail> details = new LinkedHashSet<>();
@CollectionTable의 joinColumns 속성을 사용해서 CHECK_D에서 CHECK_H를 참조할 때 사용하는 조인 칼럼을 지정했다. Check가 필요한 기능에서 CheckDetail도 함께 사용하기에 @ElementCollection의 fetch 속성을 EAGER로 설정했다. 화면에서 GROUP과 ITEM을 오름차순 기준으로 정렬해서 보여주기 때문에, 하이버네이트의 @OrderBy 애노테이션을 사용해서 값을 정렬했다.