외래키를 사용한 n:m 매핑 JPA

recordsbeat·2020년 4월 27일
0

legacy DB를 사용하다 보면 엔티티와 필드를 매핑하는게 쉽지 않을 때가 많다.
ex) conveter를 사용하여 Enum 객체와 일일히 매핑,
null체크를 하여 insert 혹은 update 진행

이번에는 저번 주부터 지지부진하게 계속 묶여있던 외래키로 매핑되는 n:m 테이블에 대한 엔티티 구성이다.

해결이 안되서 stackoverflow에 글 남겼었다..

https://stackoverflow.com/questions/61412282/mapping-manytomany-without-join-table

상황은 이러했다.

Reservation     ExchangeRate
-----------     ------------
id              id          
...             ...         
exc_set_id      exc_set_id  
------------    ------------

예약 테이블(Reservation)과 환율 테이블(ExchangeRate)가 존재하고 두 테이블은 각각의 외래키 exc_set_id로 n:m 구조의 매치가 이루어진다.

이미 stackoverflow에 같은 상황으로 보이던 글을 참조하여 시도를 해봤다.
(https://stackoverflow.com/questions/5409560/manytomany-without-join-table-legacy-database)


@Entity
@Table(name = "TB_RESERVATION")
public class Reservation {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "res_idx")
    private Long id;

    ...
    @OneToMany
    @JoinColumn(name = "exc_set_idx", referencedColumnName = "exc_set_idx",insertable = false,updatable = false)
    private Set<ExchangeRate> exchangeRateSet = new LinkedHashSet<>();
}


@Entity
@Table(name="TB_EXCHANGE_RATE")
public class ExchangeRate {


    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name="exc_idx")
    private Long id;

    //no need bidirectional.
}

예약 엔티티는 환율 엔티티를 단방향으로 참조하며 @joinColumn의 name과 referencedColumnname을 통해 대상 테이블(TB_EXCHANGE_RATE)과 주인 테이블(TB_RESERVATION)의 매핑 키를 지정한다.

하지만 쉽게 될리 없지

Caused by: org.hibernate.cfg.RecoverableException: Unable to find column with logical name: EXC_SET_IDX in org.hibernate.mapping.Table(TB_RESERVATION) and its related supertables and secondary tables
    at org.hibernate.cfg.Ejb3JoinColumn.checkReferencedColumnsType(Ejb3JoinColumn.java:837)
    at org.hibernate.cfg.BinderHelper.createSyntheticPropertyReference(BinderHelper.java:256)
    at org.hibernate.cfg.annotations.CollectionBinder.bindCollectionSecondPass(CollectionBinder.java:1634)
    ... 56 more
Caused by: org.hibernate.MappingException: Unable to find column with logical name: EXC_SET_IDX in org.hibernate.mapping.Table(TB_RESERVATION) and its related supertables and secondary tables
    at org.hibernate.cfg.Ejb3JoinColumn.checkReferencedColumnsType(Ejb3JoinColumn.java:832)
    ... 58 more

이 익셉션 때문에 계속 고민 했다. 내가 오타를 낸 건지 주종관계를 잘못알고 있는건지..

저번 금요일에 올려서 주말 내내 답변을 기다리다 오늘 오전에 시도해보고서야 해답을 찾았다.

답은 간단했다.


@ToString(exclude = "exchangeRateSet")
@NoArgsConstructor
@Getter
@Entity
@Table(name = "TB_RESERVATION")
public class Reservation implements Serializable {
    private static final long serialVersionUID = 1L;

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "res_idx")
    private Long id;
	
    ...

    @Column(name="exc_set_idx")
    private Long setIdx;

    @OneToMany
    @JoinColumn(name = "exc_set_idx", referencedColumnName ="exc_set_idx" ,insertable = false,updatable = false)
    private Set<ExchangeRate> exchangeRateSet = new LinkedHashSet<>();

}

OneToMany 관계 중 One에 해당하는 엔티티의 외래키 필드를 정의해야 했다. (여기 같은 경우는 @Column(name="exc_set_idx") 부분)

익셉션

Unable to find column with logical name: EXC_SET_IDX in
org.hibernate.mapping.Table(TB_RESERVATION) and its related supertables and secondary tables

이 부분이 나를 무한정 테이블만 쳐다보게 만들었다...

나와 같은 경우는 legacy DB를 매핑하는 경우가 아니라면 많지 않은 케이스로 보인다.

가장 대표적인 N:M 매핑 방법은
join table을 두고 두 테이블이 연결되는 것.
(각 테이블의 기본키를 매핑하는 형태)

https://leoheo.github.io/JPA-ManyToMany/

위 링크에서 자세히 설명해줌..

velog 처음 써보는데 좋네효 흑흑슨

profile
Beyond the same routine

0개의 댓글