[JPA] 관계형 DB와 다대다

6720·2023년 12월 11일
0

이거 모르겠어요

목록 보기
32/38
post-custom-banner

객체와 관계형 DB와 다대다

객체의 경우 컬렉션이 존재하기 때문에 다대다 관계가 가능함.
하지만 관계형 DB는 컬렉션 관계를 양쪽에 가질 수 없기 때문에 다대다를 일대다 다대일로 풀어내는 중간 테이블이 필요함.

컬렉션

예를 들어서 Category 객체와 Item 객체를 자바로 작성한다고 하자.
Item은 여러 Category를 가질 수 있으며, Category는 여러 Item을 가질 수 있는 관계이므로 다대다 관계가 형성됨.

@Entity
public class Category {
	@Id @GeneratedValue
	private Long id;
	private String name;
	private List<Item> items = new ArrayList<>();
}
@Entity
public class Item {
	@Id @GeneratedValue
	private Long id;
	private String name;
	private List<Category> categories = new ArrayList<>();
}

컬렉션을 사용하면 하나의 Category에 여러 Item을 담을 수 있으며, 그 반대도 가능함.
그러므로 컬렉션이 존재하는 객체의 경우 다대다 관계 표현이 가능함.

관계형 DB에서의 다대다

단방향

@ManyToMany@JoinTable을 연관관계의 주인이라고 생각되는 곳에 넣으면 됨.

@Entity
public class Category {
	@Id @GeneratedValue
	private Long id;
	private String name;
	
	@ManyToMany
	@JoinTable(name = "item_id")
	private List<Item> items = new ArrayList<>();
}
@Entity
public class Item {
	@Id @GeneratedValue
	@Column(name = "item_id")
	private Long id;
	private String name;
}

양방향

@ManyToMany는 양쪽에 넣되, @JoinTable을 연관관계의 주인이라고 생각되는 곳에 넣고, 반대쪽에는 속성으로 mappedBy를 넣어주면 됨.

@Entity
public class Category {
	@Id @GeneratedValue
	private Long id;
	private String name;
	
	@ManyToMany
	@JoinTable(name = "item_id")
	private List<Item> items = new ArrayList<>();
}
@Entity
public class Item {
	@Id @GeneratedValue
	@Column(name = "item_id")
	private Long id;
	private String name;
	
	@ManyToMany(mappedBy = "items")
	private List<Category> categories = new ArrayList<>();
}

한계

연결 테이블이 연결'만' 하는 역할로 사용되며, 그 이상의 용도로 쓰이지 못함. -> 실무에서 쓸 이유가 없어짐.

연결 테이블(예시에서는 CategoryItem)은 연결에만 쓰이는 용도가 아닐 수 있음.
예를 들어서 등록한 날짜, 수정한 날짜 등 CategoryItem 고유로 쓰이는 컬럼이 존재할 수밖에 없음.

극복 방법

연결 테이블용 엔티티를 따로 설계하는 것, 즉 연결 테이블을 엔티티 취급하는 것.
CategoryItem의 다대다 관계가 아닌, CategoryCategoryItem의 일대다 관계, ItemCategoryItem의 일대다 관계로 보는 것.

@Entity
public class Category {
	@Id @GeneratedValue
	@Column(name = "category_id")
	private Long id;
	private String name;
	
	@OneToMany(mappedBy = "category")
	private List<Item> items = new ArrayList<>();
}
@Entity
public class CategoryItem {
	@Id @GeneratedValue
	@Column(name = "category_item_id")
	private Long id;
	
	@ManyToOne
	@JoinColumn(name = 'category_id')
	private Category category;
	
	@ManyToOne
	@JoinColumn(name = 'item_id')
	private Item item;
	private LocalDateTime createdDate;
}
@Entity
public class Item {
	@Id @GeneratedValue
	@Column(name = "item_id")
	private Long id;
	private String name;
	
	@OneToMany(mappedBy = "item")
	private List<Category> categories = new ArrayList<>();
}

반드시 엔티티화를 해야하나?

CategoryItem 엔티티를 설계하지 않아도 연결용으로만 연결하는 것이라면 @ManyToMany@JoinTable만으로 가능함.

@Entity
public class Category {  
    @Id  
    @GeneratedValue
    @Column(name = "category_id")  
    private Long id;  
    private String name;  
    
    @ManyToMany  
    @JoinTable(name = "category_item",  
        joinColumns = @JoinColumn(name = "category_id"),  
            inverseJoinColumns = @JoinColumn(name = "item_id")  
    )  
    private List<Item> items = new ArrayList<>();  
}
@Entity  
public abstract class Item {  
    @Id @GeneratedValue  
    @Column(name = "item_id")  
    private Long id;  
    private String name;
    
    @ManyToMany(mappedBy = "items")  
    private List<Category> categories = new ArrayList<>();  
}
@ManyToMany
@JoinTable(name = "category_item",  
	joinColumns = @JoinColumn(name = "category_id"),  
    inverseJoinColumns = @JoinColumn(name = "item_id")  
)  
private List<Item> items = new ArrayList<>(); 
  • @JoinTable: 데이터베이스 테이블 간의 관계를 정의할 때 사용됨.
    • name = "category_item": 생성될 테이블의 이름을 category_id로 지정하라.
    • joinColumns = @JoinColumn(name = "category_id"): CategoryItemcategory_id를 현재 클래스의 인스턴스와 CategoryItem 테이블이 조인될 때 사용할 열로 지정하라.
      • 쉽게 말해서 CategoryItem에 들어가는 category_id를 말하는 것.
    • inverseJoinColumns = @JoinColumn(name = "item_id"): Itemitem_id를 다른 클래스의 인스턴스와 CategoryItem 테이블이 조인될 때 사용할 열로 지정하라.
      • 쉽게 말해서 CategoryItem에 들어가는 item_id를 말하는 것.

하지만 지양해야 할 것은 @ManyToMany 그 자체이기 때문에 되도록이면 일대다 다대일로 풀어서 사용할 것.

참고 자료

https://seriouskang.tistory.com/7

profile
뭐라도 하자
post-custom-banner

0개의 댓글