본문 바로가기
웹개발/JPA

다양한 연관관계

by 철없는민물장어 2023. 7. 3.
728x90

연관관계 매핑시 고려사항

  • 다중성
  • 단/양방향
  • 연관관계의 주인
다중성
  • @ManyToOne
  • @OneToMany
  • @OneToOne
  • @ManyToMany

(이 중 다대다는 실무에서 쓰지 않는다.)

 

단방향과 양방향

테이블은 외래키 하나로 양쪽 조인 가능(사실상 양방향)

그러나 객체는 참조용 필드가 있어야 참조가능하다. 

한쪽만 참조하면 단방향, 양쪽 서로 참조하면 양방향이다.(사실 각각 단방향인것이긴 하지만..)

 

연관관계의 주인

테이블은 외래 키가 하나인데, 객체 양방향 관계는 참조가 두군데 있다.

둘 중 테이블의 외래 키를 관리할 곳을 지정해야한다.

 

연관관계의 주인은 외래키를 관리할 수 있고, 주인의 반대편은 단순 조회만 가능하며 값을 관리할 수 없다.

 


다대일

이전 포스트를 참고.

다(Many)가 연관관계의 주인이 된다.

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

	...

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

...
}

Order엔티티와 Member엔티티가 다대일 관계일 때,

Order내에 member필드를 만들면 된다.

 

만약, Member측에서도 연관된 order들을 참조하고싶다면..

public class Member {
...
    @OneToMany(mappedBy = "member")
    private List<Order> orders = new ArrayList<>();
    ...
   }

Member에 List<Order> 필드를 추가하고,

@OneToMany(mappedBy="")해주면 된다.

(Member는 Order클래스에서 member변수에 매핑되므로 mappedBy="member"임)

 

추가로, 한 엔티티 내에서 계층적인 구조를 가질수도 있다.

@Entity
public class Category {
   ...
    @ManyToOne
    @JoinColumn(name="PARENT_ID")
    private Category parent;

    @OneToMany(mappedBy = "parent")//셀프로 연관관계를 가짐
    private List<Category> child = new ArrayList<>();
    ...
}

카테고리가 계층적으로 이루어진 경우 등을 생각해보면 된다.


일대다

일이 연관관계의 주인이 됨.

테이블 일대다 관계는 다쪽에 외래키가 있어서 구조가 특이해짐..

@JoinColumn을 꼭 사용해야함. 그렇지 않으면 JoinTable이 생성됨.

 

엔티티가 관리하는 외래 키가 다른 테이블에 있음. 따라서 일대다 단방향 매핑보다 다대일 양방향 매핑을 사용하는것을 추천

 

일대일

두 테이블 중 한쪽에 외래키가 있으면 된다.(어느쪽에 외래키를 넣느냐는 장단이 있다)

다대일과 사용법이 비슷함.

양방향 사용시 반대편을 mappedBy해주면 된다.

 

예를들어 Order, Delivery가 일대일 관계이고 Order가 외래키를 가지고있다고 하면.

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

	...

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

이렇게 표현할 수 있다.

만약 양방향 관계로 하고싶어서 Delivery에서도 Order를 참조할 수 있도록 하고싶다면

@Entity
public class Delivery {

	...

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

Delivery측에 Order참조 필드를 만들고 @OneToOne(mappedBy="delivery")해주면 된다.

(mappedBy에 쓴 delivery는 Order클래스에서 delivery를 참조하는 변수명)


 

다대다

관계형 데이터베이스는 정규화된 테이블 2개로 다대다 관계를 표현할 수 없다.

연결 테이블을 추가해서 일대다, 다대일 관계로 풀어 표현해야한다.

(객체는 컬렉션을 이용해서 객체 2개로 다대다 관계를 표현할 수 있다.)

 

@ManyToMany, @JoinTable을 이용하면 된다.

더보기

Member, Product가 다대다 관계일 때

class Member{
	...
    @ManyToMany
    @JoinTable(name="MemberProduct")
    List<Product> products = new ArrayList<>();
}

class Product{
	...
    @ManyToMany
    @JoinTable(name="MemberProduct")
    List<Member> members = new ArrayList<>();
}

이렇게하면 MemberProduct라는 중간테이블이 생긴다.

그러나 ManyToMany  실무에서 사용하면 안 된다.

연결 테이블에 주문시간, 수량 등의 추가적인 정보를 넣을 수 없다는 단점이 있다.

(또, 중간테이블이 숨겨져있어 쿼리가 이상하게 나온다)

사용예시는 더보기를 클릭

더보기
@Entity
public class Category {
   ...
    @ManyToMany
    @JoinTable(name="CATEGORY_ITEM",
                joinColumns = @JoinColumn(name="CATEGORY_ID"),
                inverseJoinColumns = @JoinColumn(name="ITEM_ID"))
    private List<Item> items = new ArrayList<>();

    ...
    }

중간테이블명을 지정하고, JoinColumn명을 지정해주어야한다.

마찬가지로 역방향 참조가 필요하다면 Item측에 리스트를 추가하고, @ManyToMany(mappedBy="items")해주면 된다.

 

따라서 중간테이블 엔티티를 직접 만들어서 일대다,다대일로 표현해야한다.

class Member{
	...
    @ManyToOne(mappedBy="member")
    List<MemberProduct> memberProducts = new ArrayList<>();
}
class Product{
	...
    @ManyToOne(mappedBy="product")
    List<MemberProduct> memberProducts = new ArrayList<>();
}
class MemberProduct{
	...
    @OneToMany
    @JoinColumn(name="MEMBER_ID")
    Member member;
    
    @OneToMany
    @JoinColumn(name="MEMBER_ID")
    Product product;
    
    //추가적인 정보들
    LocalDate date;
    
}

위와 같이 표현하자.

728x90

'웹개발 > JPA' 카테고리의 다른 글

@MappedSuperclass  (0) 2023.07.07
상속관계 매핑  (0) 2023.07.07
연관관계 매핑  (0) 2023.06.30
엔티티 매핑  (0) 2023.06.29
영속성 컨텍스트  (0) 2023.06.29

댓글