본문 바로가기
Java/ORM

JAVA ORM - JPA(연관관계 매핑2)

by 티코딩 2024. 8. 3.

연관관계를 맺기전 고려해야할 사항 으로는 방향성, 연관관계의 주인 설정, 데이터베이스 설계와 일치하는지 등

여러가지 있다.

 

방향성

단방향 : 하나의 엔티티만 다른 엔티티를 참조하는 경우. 순환 참조 문제 피할 수 있음.

양방향 : 두 엔티티가 서로를 참조하는 경우. 주인과 비주인을 명확히 구분해야함.

직전 포스팅에서 말했듯이 DB에서 테이블은 외래키 하나로 양쪽으로 조인가능함.(방향성이 딱히 존재하지 않음.)

하지만 객체는 참조용 필드가 있어야만 있는쪽으로 참조가 가능해서 방향성이 존재함.

양방향으로 객체를 설계하기 위해선 양쪽에 서로의 레퍼런스가 존재해야함.

 

 

주인 설정

주인 : 외래키를 관리하는 엔티티, 외래 키 컬럼을 실제로 변경할 수 있음. @JoinColumn사용

비주인: mapped by 속성 사용

양방향 시 객체는 A->B B->A 로 참조를 2번하는데, 여기서 A,B 둘 다 외래키를 관리하게되면 꼬인다. 그래서 한곳만 관리할 수 있게 해줘야 하는데, 관리하는쪽이 주인이 된다. 비주인은 외래키에 영향을 주지않고, 조회만 되게 해야한다.

 

설계 일치

DB의 설계(외래 키 제약 조건 등)와 JPA연관 관계 매핑이 일치하도록 설정해야 함.

1:1 , N:1, 1:M 설계에 맞게 매핑해야함.

실무에서는 N:M 사용 X

 

다대일

항상 설계를 다쪽에 외래키가 가야한다. 

다대일 단방향 매핑

Member객체 : id, Team team, username

Member테이블 : MEMBERID(PK), TEAM_ID(FK), USERNAME

Team객체 : id, name

Team테이블 : TEAM_ID(PK), NAME

Member객체의 Team team과 Member테이블의 TEAM_ID와 매핑시킨다.

 

다대일 양방향매핑

Member객체 : id, Team team, username

Team객체 : id, name, List members(@OneToMany(mapped by="team"))

Member테이블 : MEMBERID(PK), TEAM_ID(FK), USERNAME

Team테이블 : TEAM_ID(PK), NAME

 

다대일의 반대는 일대다

 

일대다

일대다 단방향 예시

Team객체 : id, name, List members

Member테이블 : MEMBERID(PK), TEAM_ID(FK), USERNAME

Team테이블 : TEAM_ID(PK), NAME,

Member객체 : id, Team team, username

Team객체의 List members와 Member테이블의 TEAM_ID와 매핑시킨다.

1이 연관관계의 주인이 되고, 다쪽에 외래키가 있음. @JoinColumn을 꼭 써야함. 안쓰면 중간테이블이 생겨버림/

하지만, 엔티티가 관리하는 외래키가 다른테이블에 있다는게 엄청난 단점. 왜냐하면 추가로 UPDATE SQL발생하기 때문.  그냥 다대일 양방향 매핑 사용하자.

 

일대다 양방향 예시

Team객체 : id, name, List members

Member객체 : id, username, Team team(@ManyToOne @JoinColumn(insertable = false, updatable = false))

Member테이블 : MEMBERID(PK), TEAM_ID(FK), USERNAME

Team테이블 : TEAM_ID(PK), NAME,

Team객체의 List members와 Member테이블의 TEAM_ID와 연관관계 매핑, Member객체의 team과 Member테이블의 TEAM_ID는 읽기전용 매핑

@JoinColumn(insertable = false, updatable = false 를 안쓰게되면 둘다 주인이되어 큰일남.

그냥 쓰지말자!

 

일대일

두개의 테이블중에 아무테이블에 외래키 선택가능하다. 외래키에 유니크제약조건을 추가해야한다.

일대일 단방향 예시

Member객체 : id, username, Locker locker

Locker객체 : id, name

Member테이블 : MEMBERID(PK), LOCKER_ID(FK, UNI), USERNAME

Locker테이블 : LOCKER_ID(PK), NAME,

locker과 LOCKER_ID를 연관관계 매핑함.

 

일대일 양방향 예시

Member객체 : id, username, Locker locker

Locker객체 : id, name, Member member(mapped by)

Member테이블 : MEMBERID(PK), LOCKER_ID(FK, UNI), USERNAME

Locker테이블 : LOCKER_ID(PK), NAME

외래키가있는곳이 주인, 비주인에서는 mappedBy

 

주 테이블에 외래키가 존재하는 경우 값이 없으면 외래키에 NULL을 허용하는 치명적인 단점이있다.

대상 테이블에 외래키가 존재하는 경우 주 테이블과 대상 테이블을 1:1에서 1:N으로 변경할때 테이블 구조는 유지된다.

하지만 지연로딩으로 설정해도 즉시로딩되고, 양방향으로 구현해야함.

 

다대다

그만알아보도록 하자.

중간에 조인테이블을 새로만들어 조인테이블과 다대일 관계를 맺는것이다. 비효율적이므로 쓰지말자!

 

 

 

 

 

 

 

 

'Java > ORM' 카테고리의 다른 글

JAVA ORM - JPA(proxy, loading)  (0) 2024.08.06
JAVA ORM - JPA(상속을 매핑?)  (0) 2024.08.05
JAVA ORM - JPA(연관관계 매핑)  (0) 2024.08.01
JAVA ORM - JPA(엔티티 매핑)  (0) 2024.07.31
JAVA ORM - JPA(영속성 컨텍스트)  (0) 2024.07.31