다양한 연관관계 매핑

OneTwoThree·2023년 7월 25일
0

출처


연관관계 매핑 시 고려해야 할 사항 3가지가 있다
1. 다중성
2. 단방향, 양방향

  • 테이블은 외래 키 하나로 양쪽 조인이 가능하다
  • 방향이라는 개념이 없다
  • 객체는 참조용 필드가 있는 쪽으로만 참조 가능
  • 한쪽만 참조하면 단방향
  • 양쪽이 서로 참조하면 양방향
  1. 연관관계의 주인

@JoinColumn

외래 키를 매핑할 때 사용한다.
name 속성은 매핑할 외래 키 이름이다.
기본값은 필드명+_+참조하는 테이블의 기본 키 컬럼명 이다.

다대일 N:1

JPA에서 가장 많이 사용한다.

다대일 단방향


다 쪽에 외래키가 가야 함.
외래 키가 있는 객체에 참조를 넣어주면 된다.
외래 키가 있는 객체에
@ManyToOne@JoinColumn(name="테이블에 생성될 FK 필드명") 을 넣어준다.

다대일 양방향


연관관계의 주인 : Member(다)
양방향으로 바꾸더라도 테이블에는 전혀 변경이 없다.
외래 키가 있는 쪽이 연관관계의 주인이다.
양쪽을 서로 참조하도록 개발한다.
일 쪽에서는 양방향이므로
@OneToMany(mappedby="다 쪽의 컬럼명") 애노테이션을 달아준다.

일대다 1:N

일이 연관관계의 주인이다.
권장하지 않는 모델이다.

DB 입장에서는 무조건 다 쪽에 FK가 있어야 한다.

@Entity
public class Team {
    @Id @GeneratedValue
    @Column(name="TEAM_ID")
    private Long id;
    private String name;

    @OneToMany(mappedBy = "team")
    @JoinColumn(name="TEAM_ID")
    private List<Member> members = new ArrayList<>();

@OneToMany로 매핑한다.
@JoinColumn을 써줘야 한다. 안쓰면 조인 테이블 방식을 사용한다.

  • 엔티티가 관리하는 왜래 키가 다른 테이블에 있음
  • 일대다 단방향 매핑보다는 다대일 양방향 매핑을 사용하자

일대다 양방향도 사용하지 말자

일대일 1:1

일대일 관계는 반대도 일대일이다.
주 테이블이나 대상 테이블 중에 외래 키 선택 가능하다.
외래 키에 데이터베이스 유니크 제약조건 추가된다.

@Entity
public class Locker {

    @Id @GeneratedValue
    private Long id;

    private String name;
    

}
@Entity
public class Member {

    @Id @GeneratedValue
    @Column(name="MEMBER_ID")
    private Long id;

    @Column(name="USERNAME")
    private String username;

    @OneToOne
    @JoinColumn(name="LOCKER_ID")
    private Locker locker;

}

@OneToOne 사용 , @JoinColumn 사용

양방향으로 하고 싶다면

@Entity
public class Locker {

    @Id @GeneratedValue
    private Long id;

    private String name;

    @OneToOne(mappedBy = "locker")
    private Member member;


}

위와 같이 mappedBy를 걸어주면 된다.


주 테이블에 외래 키가 있는 경우

  • 주 객체가 대상 객체의 참조를 갖는 것
  • 객체지향 개발자 선호
  • JPA 매핑 편리

대상 테이블에 외래 키가 있는 경우

  • DBA 선호

다대다 N:M

관계형 DB는 정규화된 테이블 2개로 다대다 관계 표현 불가능하다.
연결 테이블을 추가해서 일대다, 다대일 관계로 풀어내야한다.

반면에 객체는 컬렉션을 사용해서 객체 2개로 다대다 관계가 가능하다.

실무에서 사용 X

연결 테이블용 엔티티를 추가해라
@ManyToMany -> @OneToMany , @ManyToOne

예제

@Entity
public class Category {

    @Id
    @GeneratedValue
    private Long id;

    private String name;

    @ManyToOne
    @JoinColumn(name="PARENT_ID")
    private Category parent;

    @OneToMany(mappedBy = "parent")
    private List<Category> child = new ArrayList<>();

}

Category에서 스스로 연관관계를 ManyToOne이랑 OneToMany로 양방향으로 걸었다.

@Entity
@Table(name = "ORDERS")
public class Order {

    @Id
    @GeneratedValue
    @Column(name="ORDER_ID")
    private Long id;

    @ManyToOne
    @JoinColumn(name="MEMBER_ID")
    private Member member;

    @OneToOne
    @JoinColumn(name="DELIVERY_ID")
    private Delivery delivery;
    
    ...

Order에서 FK를 갖고 있어서 @OneToOne으로 매핑하고 @JoinColumn으로 연관관계의 주인으로 지정한다.

@Entity
public class Delivery {

    @Id
    @GeneratedValue
    private Long id;

    private String city;
    private String street;
    private String zipcode;

    private DeliveryStatus status;

    @OneToOne(mappedBy = "delivery")
    private Order order;

}

Delivery에서는 @OneToOnemappedBy로 Order에서 Delivery의 필드명을 지정해준다.

    @ManyToMany
    @JoinTable( name="CATEGORY_ITEM",
            joinColumns = @JoinColumn(name="CATEGORY_ID"),
            inverseJoinColumns = @JoinColumn(name="ITEM_ID")
    )
    private List<Item> items = new ArrayList<>();

Category 엔티티에 다음과 같이 추가해준다. 매핑을 위한 중간 테이블인 CATEGORY_ITEM 을 만든 것이다. 내 쪽의 JoinCOlumn은 CATEGORY_ID이고 상대 쪽의 inverseJoinColumn은 ITEM_ID이다.

    @ManyToMany(mappedBy = "items")
    private List<Category> category = new ArrayList<>();

양방향으로 매핑하고 싶으면 Item 엔티티에 다음과 같이 추가해준다. 연관관계의 주인이 아니기 때문에 mappedBy를 써준다.

  • 실전에서는 @ManyToMany 사용하지 말 것
  • 테이블의 M:N은 중간 테이블 활용해서 1:N, N:1로 바꿀 것

0개의 댓글