반응형
이전에 작성한 내용을 중간테이블을 만들어서 사용하는 방법
N대1로 변경하여 작성하였다.
BookAndAuthor 클래스 작성
package com.example.bookmanager.domain;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.ToString;
import javax.persistence.*;
@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 클래스 수정
package com.example.bookmanager.domain;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.ToString;
import javax.persistence.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@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;
// N대N 관계 설정
// stack 오버 플로우 처리
// null 예외처리 방지 설정
// @ManyToMany
@OneToMany
@JoinColumn(name = "author_id")
@ToString.Exclude
private List<BookAndAuthor> bookAndAuthor = new ArrayList<>();
// ... => 배열로 받는다는 의미
// Book 정보가 여러개 존재하면 모두 처리
public void addBookAndAuthors(BookAndAuthor... bookAndAuthors){
Collections.addAll(this.bookAndAuthor, bookAndAuthors);
// if (book != null){
// for (Book book1 : book){
// this.books.add(book1);
// }
// }
}
}
Book 클래스 수정
package com.example.bookmanager.domain;
import com.example.bookmanager.domain.listener.Auditable;
import com.example.bookmanager.domain.listener.MyEntityListener;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.NoArgsConstructor;
import lombok.ToString;
import javax.persistence.*;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
@Entity
@NoArgsConstructor
@Data
// 상속받은 BaseEntity를 사용하기 위해서 ToString, EqualsAndHashCode 재정의
@ToString(callSuper = true)
@EqualsAndHashCode(callSuper = true)
// 해당 객체에 사용자가 정의한 Entity Listener가 수행되도록 선언해준다.
public class Book extends BaseEntity {
@Id
// 테이블마다 ID값이 증가하도록 설정
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String category;
private Long authorId;
// private Long publisherId;
@OneToOne(mappedBy = "book")
// toString에서 제외, 설정하지 않으면 스택오버플로우 에러가 발생
@ToString.Exclude
private BookReviewInfo bookReviewInfo;
@OneToMany
@JoinColumn
@ToString.Exclude
private List<Review> reviews = new ArrayList<>();
@ManyToOne
@ToString.Exclude
private Publisher publisher;
// N대N 관계 설정
// stack 오버 플로우 처리
// null 예외처리 방지 설정
// @ManyToMany
@OneToMany
@JoinColumn(name = "book_id")
@ToString.Exclude
private List<BookAndAuthor> bookAndAuthor = new ArrayList<>();
// ... => 배열로 받는다는 의미
// Author 정보가 여러개 존재하면 모두 처리
public void addBookAndAuthor(BookAndAuthor... bookAndAuthors) {
Collections.addAll(this.bookAndAuthor, bookAndAuthors);
}
// private String author;
// private LocalDateTime createdAt;
//
// private LocalDateTime updatedAt;
//
// //@PrePersist
// public void prePersist(){
// this.createdAt = LocalDateTime.now();
// this.updatedAt = LocalDateTime.now();
// }
//
// //@PreUpdate
// public void preUpdate(){
// this.updatedAt = LocalDateTime.now();
// }
}
BookAndAuthorRepository 인터페이스 생성 (JPA 이용)
package com.example.bookmanager.repository;
import com.example.bookmanager.domain.BookAndAuthor;
import org.springframework.data.jpa.repository.JpaRepository;
public interface BookAndAuthorRepository extends JpaRepository<BookAndAuthor, Long> {
}
Test 코드 수정
package com.example.bookmanager.repository;
import com.example.bookmanager.domain.Author;
import com.example.bookmanager.domain.Book;
import com.example.bookmanager.domain.BookAndAuthor;
import org.assertj.core.util.Lists;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import javax.transaction.Transactional;
import static org.junit.jupiter.api.Assertions.*;
@SpringBootTest
class AuthorRepositoryTest {
@Autowired
private AuthorRepository authorRepository;
@Autowired
private BookRepository bookRepository;
@Autowired
private BookAndAuthorRepository bookAndAuthorRepository;
@Test
@Transactional
// LazyInitializationException 에러 처리를 위해서 설정
void manyToManyTest(){
Book book1 = givenBook("책 1");
Book book2 = givenBook("책 2");
Book book3 = givenBook("개발책1");
Book book4 = givenBook("개발책2");
Author author1 = givenAuthor("martin");
Author author2 = givenAuthor("steve");
/* 주문 구현을 위해 추가 */
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);
book1.addBookAndAuthor(bookAndAuthor1);
book2.addBookAndAuthor(bookAndAuthor2);
book3.addBookAndAuthor(bookAndAuthor3, bookAndAuthor4);
book4.addBookAndAuthor(bookAndAuthor5, bookAndAuthor6);
author1.addBookAndAuthors(bookAndAuthor1, bookAndAuthor3, bookAndAuthor5);
author2.addBookAndAuthors(bookAndAuthor2, bookAndAuthor4, bookAndAuthor6);
// book1.addAuthor(author1);
// book2.addAuthor(author2);
// 공동저자로 설정
// book3.addAuthor(author1,author2);
// book4.addAuthor(author1,author2);
// book3.setAuthors(Lists.newArrayList(author1, author2));
// book4.setAuthors(Lists.newArrayList(author1, author2));
// author1.addBook(book1, book3, book4);
// author2.addBook(book2, book3, book4);
// author1.setBooks(Lists.newArrayList(book1, book3, book4));
// author2.setBooks(Lists.newArrayList(book2, book3, book4));
// 연관 관계 설정 종료
bookRepository.saveAll(Lists.newArrayList(book1,book2,book3,book4));
authorRepository.saveAll(Lists.newArrayList(author1, author2));
bookRepository.findAll().get(2).getBookAndAuthor().forEach(o -> System.out.println("3번째 책 가져오기: " + o.getAuthor()));
authorRepository.findAll().get(0).getBookAndAuthor().forEach(o -> System.out.println("martin이 쓴 책 출력: " + o.getBook()));
// System.out.println("3번째 책 가져오기: " + bookRepository.findAll().get(2).getAuthors());
// System.out.println("martin이 쓴 책 출력: " + 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);
}
private BookAndAuthor givenBookAndAuthor(Book book, Author author){
BookAndAuthor bookAndAuthor = new BookAndAuthor();
bookAndAuthor.setBook(book);
bookAndAuthor.setAuthor(author);
return bookAndAuthorRepository.save(bookAndAuthor);
}
}
콘솔창 확인
3번째 책 가져오기: Author(super=BaseEntity(createdAt=2021-08-29T16:46:49.093, updatedAt=2021-08-29T16:46:49.093), id=1, name=martin, country=null)
3번째 책 가져오기: Author(super=BaseEntity(createdAt=2021-08-29T16:46:49.103, updatedAt=2021-08-29T16:46:49.103), id=2, name=steve, country=null)
martin이 쓴 책 출력: Book(super=BaseEntity(createdAt=2021-08-29T16:46:49.018, updatedAt=2021-08-29T16:46:49.018), id=1, name=책 1, category=null, authorId=null)
martin이 쓴 책 출력: Book(super=BaseEntity(createdAt=2021-08-29T16:46:49.076, updatedAt=2021-08-29T16:46:49.076), id=3, name=개발책1, category=null, authorId=null)
martin이 쓴 책 출력: Book(super=BaseEntity(createdAt=2021-08-29T16:46:49.080, updatedAt=2021-08-29T16:46:49.080), id=4, name=개발책2, category=null, authorId=null)
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)
)
반응형
'Spring > JPA' 카테고리의 다른 글
영속성 구성을 위한 mysql 설정 (0) | 2021.09.12 |
---|---|
N 대 N 연관관계 설정 (0) | 2021.08.29 |
1대N 연관관계 (0) | 2021.08.06 |
1 대 1 관계 설정하는 방법 (0) | 2021.07.24 |
연관 관계 설정 -1 (0) | 2021.07.24 |