Reference. 한 번에 끝내는 Java/Spring 웹 개발 마스터 초격차 패키지 Online
이전 글
N:N
- 실무에선 거의 사용되지 않음
@ManyToMany(N:N)
는One(N:1 or 1:N)
이 존재하지 않으면 FK로 쓰일 PK를 구하기가 어려움
@ManyToMany
를 설정하면 중간 테이블이 생성 됌
→ ex)author
-book
→author_books
1. @ManyToMany
적용 (author - book)
<ERD>
Author.java 생성
@Entity
@NoArgsConstructor
@Data
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)
public class Author extends BaseEntity{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String country;
@ManyToMany
@ToString.Exclude
private List<Book> books = new ArrayList<>();
public void addBook(Book... book) {
Collections.addAll(this.books, book); //콜렉션 add 배열
}
}
Book.java 수정
...
public class Book extends BaseEntity{
...
@ManyToMany
@ToString.Exclude
private List<Author> authors = new ArrayList<>();
public void addAuthor(Author... author) {
Collections.addAll(this.authors, author); //콜렉션 add 배열
}
}
테스트 코드
@SpringBootTest
class AuthorRepositoryTest {
@Autowired
private AuthorRepository authorRepository;
@Autowired
private BookRepository bookRepository;
@Test
@Transactional
void manyToManyTest(){
//Book 객체 생성 및 저장
Book book1 = givenBook("책1");
Book book2 = givenBook("책2");
Book book3 = givenBook("개발책1");
Book book4 = givenBook("개발책2");
//Author 객체 생성 및 저장
Author author1 = givenAuthor("martin");
Author author2 = givenAuthor("steve");
//Book 객체에 List<Author>에 add
book1.addAuthor(author1);
book2.addAuthor(author2);
book3.addAuthor(author1, author2);
book4.addAuthor(author1, author2);
//Author 객체에 List<Book>에 add
author1.addBook(book1, book3, book4);
author2.addBook(book2, book3, book4);
//해당 객체를 데이터베이스에 저장 -> flush()
bookRepository.saveAll(Arrays.asList(book1, book2, book3, book4));
authorRepository.saveAll(Lists.newArrayList(author1, author2));
System.out.println("authors through book : " + bookRepository.findAll().get(2).getAuthors());
System.out.println("books through author : " + authorRepository.findAll().get(0).getBooks());
}
private Book givenBook(String name){
Book book = new Book();
book.setName(name);
return bookRepository.save(book);
}
private Author givenAuthor(String name){
Author author = new Author();
author.setName(name);
return authorRepository.save(author);
}
}
실행결과 (DDL, 결과)
Hibernate:
create table author_books (
author_id bigint not null,
books_id bigint not null
)
//결과 콘솔
authors through book : [Author(super=BaseEntity(createdAt=2021-07-29T20:26:42.025524100, updatedAt=2021-07-29T20:26:42.025524100), id=1, name=martin, country=null), Author(super=BaseEntity(createdAt=2021-07-29T20:26:42.036527500, updatedAt=2021-07-29T20:26:42.036527500), id=2, name=steve, country=null)]
books through author : [Book(super=BaseEntity(createdAt=2021-07-29T20:26:41.846525300, updatedAt=2021-07-29T20:26:41.846525300), id=1, name=책1, category=null), Book(super=BaseEntity(createdAt=2021-07-29T20:26:41.999525400, updatedAt=2021-07-29T20:26:41.999525400), id=3, name=개발책1, category=null), Book(super=BaseEntity(createdAt=2021-07-29T20:26:42.006524300, updatedAt=2021-07-29T20:26:42.006524300), id=4, name=개발책2, category=null)]
2. @ManyToMany
→ @OneToMany
, @ManyToOne
으로 변경 (book -bookAndAuthor - author)
<ERD>
Book.java
@Entity
@NoArgsConstructor
@Data
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)
public class Book extends BaseEntity{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
...
@OneToMany
@JoinColumn(name = "book_id")
@ToString.Exclude
private List<BookAndAuthor> bookAndAuthors = new ArrayList<>();
public void addBookAndAuthors(BookAndAuthor... bookAndAuthors) {
Collections.addAll(this.bookAndAuthors, bookAndAuthors);
}
}
BookAndAuthor.java
@Entity
@NoArgsConstructor
@Data
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)
public class BookAndAuthor extends BaseEntity{
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne
private Book book;
@ManyToOne
private Author author;
}
Author.java
@Entity
@NoArgsConstructor
@Data
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)
public class Author extends BaseEntity{
...
@OneToMany
@JoinColumn(name="author_id")
@ToString.Exclude
private List<BookAndAuthor> bookAndAuthors = new ArrayList<>();
public void addBookAndAuthors(BookAndAuthor... bookAndAuthors) {
Collections.addAll(this.bookAndAuthors, bookAndAuthors);
}
}
BookAndAuthorRepository.java
@Repository
public interface BookAndAuthorRepository extends JpaRepository<BookAndAuthor, Long> {
}
테스트 코드
@SpringBootTest
class AuthorRepositoryTest {
@Autowired
private AuthorRepository authorRepository;
@Autowired
private BookRepository bookRepository;
@Autowired
private BookAndAuthorRepository bookAndAuthorRepository;
@Test
@Transactional
void manyToManyTest(){
//Book 객체 생성 및 저장
Book book1 = givenBook("책1");
Book book2 = givenBook("책2");
Book book3 = givenBook("개발책1");
Book book4 = givenBook("개발책2");
//Author 객체 생성 및 저장
Author author1 = givenAuthor("martin");
Author author2 = givenAuthor("steve");
//BookAndAuthor 객체 생성 및 저장
BookAndAuthor bookAndAuthor1 = givenBookAndAuthor(book1, author1);
BookAndAuthor bookAndAuthor2 = givenBookAndAuthor(book2, author2);
BookAndAuthor bookAndAuthor3 = givenBookAndAuthor(book3, author1);
BookAndAuthor bookAndAuthor4 = givenBookAndAuthor(book3, author2);
BookAndAuthor bookAndAuthor5 = givenBookAndAuthor(book4, author1);
BookAndAuthor bookAndAuthor6 = givenBookAndAuthor(book4, author2);
//Book 객체에 List<BookAndAuthor>에 add
book1.addBookAndAuthors(bookAndAuthor1);
book2.addBookAndAuthors(bookAndAuthor2);
book3.addBookAndAuthors(bookAndAuthor3, bookAndAuthor4);
book4.addBookAndAuthors(bookAndAuthor5, bookAndAuthor6);
//Author 객체에 List<BookAndAuthor>에 add
author1.addBookAndAuthors(bookAndAuthor1, bookAndAuthor3, bookAndAuthor5);
author2.addBookAndAuthors(bookAndAuthor2, bookAndAuthor4, bookAndAuthor6);
//해당 객체를 데이터베이스에 저장 -> flush()
bookRepository.saveAll(Arrays.asList(book1, book2, book3, book4));
authorRepository.saveAll(Lists.newArrayList(author1, author2));
bookRepository.findAll().get(2).getBookAndAuthors().forEach(o -> System.out.println(o.getAuthor()));
authorRepository.findAll().get(0).getBookAndAuthors().forEach(o -> System.out.println(o.getBook()));
}
private Book givenBook(String name){
Book book = new Book();
book.setName(name);
return bookRepository.save(book);
}
private Author givenAuthor(String name){
Author author = new Author();
author.setName(name);
return authorRepository.save(author);
}
private BookAndAuthor givenBookAndAuthor(Book book, Author author){
BookAndAuthor bookAndAuthor = new BookAndAuthor();
bookAndAuthor.setBook(book);
bookAndAuthor.setAuthor(author);
return bookAndAuthorRepository.save(bookAndAuthor);
}
}
실행결과 (DDL, 결과)
Hibernate:
create table author (
id bigint generated by default as identity,
created_at timestamp,
updated_at timestamp,
country varchar(255),
name varchar(255),
primary key (id)
)
Hibernate:
create table book (
id bigint generated by default as identity,
created_at timestamp,
updated_at timestamp,
category varchar(255),
name varchar(255),
publisher_id bigint,
primary key (id)
)
Hibernate:
create table book_and_author (
id bigint generated by default as identity,
created_at timestamp,
updated_at timestamp,
author_id bigint,
book_id bigint,
primary key (id)
)
//실행 결과
Author(super=BaseEntity(createdAt=2021-08-01T15:16:30.329579800, updatedAt=2021-08-01T15:16:30.329579800), id=1, name=martin, country=null)
Author(super=BaseEntity(createdAt=2021-08-01T15:16:30.343577600, updatedAt=2021-08-01T15:16:30.343577600), id=2, name=steve, country=null)
Book(super=BaseEntity(createdAt=2021-08-01T15:16:30.186577400, updatedAt=2021-08-01T15:16:30.186577400), id=1, name=책1, category=null)
Book(super=BaseEntity(createdAt=2021-08-01T15:16:30.312579, updatedAt=2021-08-01T15:16:30.312579), id=3, name=개발책1, category=null)
Book(super=BaseEntity(createdAt=2021-08-01T15:16:30.315578900, updatedAt=2021-08-01T15:16:30.315578900), id=4, name=개발책2, category=null)
'백엔드 > JPA' 카테고리의 다른 글
[ JPA ] 6-2. Entity 캐시 (0) | 2021.08.07 |
---|---|
[ JPA ] 6-1. 영속성 컨텍스트(Persistence Context) (0) | 2021.08.07 |
[ JPA ] 5-4. Entity Relations ( N:1 @ManyToOne ) (0) | 2021.08.01 |
[ JPA ] 5-3. Entity Relations ( 1:N @OneToMany ) (0) | 2021.07.25 |
[ JPA ] 5-2. Entity Relations ( 1:1 @OneToOne ) (0) | 2021.07.25 |