[JPA] OneToMany

타미·2020년 9월 29일
1

JPA실험실

목록 보기
2/8

참고하면 좋은 글 :>

결론

OneToMany를 지양하는 이유

many를 insert할 때 update query가 추가적으로 발생한다.
entity를 관리하는 외래키가 다른 table(many)에 존재한다.

  • 예를 들어 연관관계를 끊으려고 one이 가지고 있는 List에서 삭제했을 때 바뀐 건 one인데 many쪽으로 query가 발생하면서 헷갈리 수 있다.

그럼에도 OneToMany를 쓸 때

부모 Entity에서 자식 Entity로 메세지를 보내는 객체 관계일 때


OneToMany에서 Many는 미리 저장 시켜줘야 한다.

미리 저장 안했을 때 ❌

    @Test
    void name() {
        Student student = new Student();
        Book book1 = new Book();
        Book book2 = new Book();
        student.books = Arrays.asList(book1,book2);
        studentRepository.save(student);
    }
Exception 발생 : save the transient instance before flushing

미리 저장했을 때 ⭕

   @Test
   void name() {
       Student student = new Student();
       Book book1 = bookRepository.save(new Book());
       Book book2 = bookRepository.save(new Book());
       student.books = Arrays.asList(book1,book2);
       studentRepository.save(student);
   }

(참고) 여기에 트랜잭션이 붙으면 정상작동한다. 왜 그럴까.

    @Transactional
    @Test
    void name() {
        Many many1 = new Many();
        Many many2 = new Many();
        Many many3 = new Many();
        One one = new One();

        one.add(many1);
        one.add(many2);
        one.add(many3);

        One save = oneRepository.save(one);
    }

디폴트로 JoinTable 사용

👎 불필요한 Table 추가적으로 사용

class Stundet {
	...
    
    @OneToMany
    public List<Book> books = new ArrayList<>();
Hibernate: 
    insert 
    into
        book
        (id, name) 
    values
        (null, ?)
Hibernate: 
    insert 
    into
        book
        (id, name) 
    values
        (null, ?)
Hibernate: 
    insert 
    into
        student
        (id, name) 
    values
        (null, ?)
Hibernate: 
    insert 
    into
        student_books
        (student_id, books_id) 
    values
        (?, ?)
Hibernate: 
    insert 
    into
        student_books
        (student_id, books_id) 
    values
        (?, ?)

JoinColumn

many(book)에 column id를 update 해준다.

class Stundet {
	...
    
    @OneToMany
    @JoinColumn(name="book_id")
    public List<Book> books = new ArrayList<>();
Hibernate: 
    insert 
    into
        book
        (id, name) 
    values
        (null, ?)
Hibernate: 
    insert 
    into
        book
        (id, name) 
    values
        (null, ?)
Hibernate: 
    insert 
    into
        student
        (id, name) 
    values
        (null, ?)
Hibernate: 
    update
        book 
    set
        book_id=? 
    where
        id=?
Hibernate: 
    update
        book 
    set
        book_id=? 
    where
        id=?

JoinTable에서 Many 삭제

join된 Many를 단독으로 지울 수 없다.

연관관계를 끊고 Many를 지워야 한다.

    @Transactional
   public void practice(Student student) {
       List<Book> books = student.books;
       bookRepository.delete(books.get(0));
   }
constraint ["FKMGR4X6DGXPDKWAF421Q0F7ETK: PUBLIC.STUDENT_BOOKS FOREIGN KEY(BOOKS_ID) REFERENCES PUBLIC.BOOK(ID) (1)"; SQL statement:

join된 many와 연관관계 끊기

  1. 해당 one에 대한 join table deleteAll
  2. 연관관계 끊은 many를 제외하고 다시 join_table을 insert한다.
    ☠ 굉장히 위험하다! many가 1000개일 때 단 하나를 지우기 위해 1000개를 delete하고, 999개를 insert한다. 참고
// Student가 Book 2권 가지고 있는 상태

    @Transactional
    public void practice() {
        Student student = studentRepository.findById(1L).get();
        student.removeBookById(1L);
   }
Hibernate: 
    delete 
    from
        student_books 
    where
        student_id=?
Hibernate: 
    insert 
    into
        student_books
        (student_id, books_id) 
    values
        (?, ?)

JoinColumn에서 Many 삭제

연관관계 있는 상태에서 Many 지울 수 있다.

    @Transactional
    public void practice() {
        bookRepository.deleteById(1L);
    }
Hibernate: 
    delete 
    from
        book 
    where
        id=?

주의

Many를 삭제하는 게 아니라 연관관계를 끊는다고 생각하면 연관관계를 null로 update한다.

profile
IT's 호기심 천국

0개의 댓글