이지은님의 블로그
250214 - Java Spring 숙련: 효율적인 다대다 연관관계 매핑(@ManyToOne) 본문
▷ 오늘 배운 것
늘 마찬가지로 배운 것은 늘 똑같이 까먹기 마련이다. 다시 리마인드 하기 위해서 JPA로 연관관계를 구현하는 방법에 대해 다시 블로그로 정리해볼 예정이다.
<<목차>>
1. 연관관계
1) 1:N
2) @ManyToOne, @OneToMany
3) N:M 다대다 단/양방향 구현방법1 - @OneToMany + @ManyToOne
4) N:M 다대다 단/양방향 구현방법2 - @ManyToOne
1. 연관관계
사실 연관관계는 하나밖에 없다.
엑셀시트를 생각해본다면 데이터는 오로지 하나밖에 들어간다.
결론은 테이블의 필드값으로 ‘리스트’는 본질적으로 들어가는 것이 불가능하다라는 것이다.
1) 1:N
@Entity
@Getter
@Table(name = "schedules")
@NoArgsConstructor
public class Schedules extends BaseEntity{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@Setter
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "user_id")
private Users users;
@OneToMany(mappedBy = "schedules", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private List<Comments> comments = new ArrayList<>();
@Column(nullable = false)
private String todoTitle;
@Column(nullable = false, columnDefinition = "longtext")
private String todoContents;
}
@OneToMany(mappedBy = "users", cascade = CascadeType.ALL, fetch = FetchType.LAZY)
private List<Schedules> schedules = new ArrayList<>();
다음과 같은 코드를 보면
원래 데이터의 필드값으로 리스트를 넣는게 본질적으로 불가능한 것임에도 entity에 리스트를 작성하고 있다.(원래 데이터 베이스에는 없는 개념!)
2) @ManyToOne(fetch = FetchType.LAZY), @OneToMany를 어떻게 사용할 수 있을까?
@OneToMany는 @ManyToOne(fetch = FetchType.LAZY)이 없으면 존재할 수 없다. —> @ManyToOne(fetch = FetchType.LAZY)
@ManyToOne(fetch = FetchType.LAZY) 더 개수가 많은 엔티티에 건다.(댓글)
N:M은 중간테이블 필요하다.
중간테이블에 @ManyToOne(fetch = FetchType.LAZY) 2개 선언하는 방법을 사용 —> 잘 사용하지 않는 방법(대체 할 수 있다.)
해야하는 설정
@ManyToOne | @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = “상대방id”) |
@OneToMany | @OneToMany(mappedBy = “나자신”) |
3) N:M 다대다 단/양방향 구현방법1 - @OneToMany + @ManyToOne
@Entity
public class Member {
@Id @GeneratedValue
@Column(name = "member_id")
private Long id;
private String name;
@ManyToMany
@JoinTable(name = "member_product")
private List<Product> products = new ArrayList<>();
}
@Entity
public class Product {
@Id @GeneratedValue
@Column(name = "product_id")
private Long id;
private String name;
// 양방향의 경우 추가
// @ManyToMany(mappedBy = "products")
// private List<Member> members = new ArrayList<>();
}
여러명의 member가 여러개의 product와 연결되는 다대다 상황이다.
@ManyToMany를 사용해주어 여러개의 products list를 연결해준다.
위에서 일대다를 사용한 @ManyToOne은 @JoinColumn(name = “{}_id”)를 사용한데 반해,
@ManyToMany는 테이블과 조인을 해야하기 때문에 @JoinTable(name = “{}_{}”)로 테이블을 연결해야 한다.
하지만 실무에서는 이를 사용하지 않는다.
@ManyToMany 다대다를 사용해서 중간테이블을 만들었다가 복잡한 조인쿼리가 발생하게 된다.(사이드 이팩트)
그렇다면 어떻게 해결할 수 있을까?
—> @OneToMany, @ManyToOne 를 적절히 사용하자.
—> 중간테이블 역할을 하는 중간 엔티티를 만들어주자.
@Entity
public class Member {
@Id @GeneratedValue
@Column(name = "member_id")
private Long id;
private String name;
@OneToMany(mappedBy = member)
private List<MemberProduct> memberProducts = new ArrayList<>();
}
@Entity
public class MemberProduct {
@Id @GeneratedValue
@Column(name = "member_product_id")
private Long id;
@ManyToOne
@JoinColumn(name = "member_id")
private Member member;
@ManyToOne
@JoinColumn(name = "product_id")
private Product product;
}
@Entity
public class Product {
@Id @GeneratedValue
@Column(name = "product_id")
private Long id;
private String name;
@OneToMany(mappedBy = "product")
private List<MemberProduct> memberProducts = new ArrayList<>();
}
위 코드의 구조는 다음과 같다.
Member ➡️ MemberProduct ⬅️ Product
MemberProduct라는 중간 테이블을 엔티티로 만들어 관리하는 것이다. 다대다의 단점을 극복하기 위해서 좀 더 관리하기 편한 @OneToMany + @ManyToOne의 중간엔티티를 만들어서 관리 해보도록 하자.
4) N:M 다대다 단/양방향 구현방법2 - @ManyToOne
import jakarta.persistence.*;
import lombok.Getter;
import lombok.NoArgsConstructor;
@Entity
@Getter
@NoArgsConstructor
@Table(name = "book_authors")
public class BookAuthor {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "book_id", nullable = false)
private Book book;
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "author_id", nullable = false)
private Author author;
public BookAuthor(Book book, Author author) {
this.book = book;
this.author = author;
}
}
Book과 Author의 중간테이블인 BookAuthor를 만들고,
BookAuthor 테이블에 Book과 Author를 @ManyToOne으로 매핑하면
오직 순수하게 @ManyToOne만 사용하고도 중간엔티티를 만들 수 있으며, 더 효율적으로 관리할 있다.