본문 바로가기
  • Let's study
BackEnd/Spring

[Spring] @OneToMany와 @ManyToOne

by 코딩고수이고파 2026. 8. 5.

@ManyToOne

public class Answer {
    @ManyToOne
    private Question question;
}
 
  • Answer가 Question을 참조한다.
  • DB에서는 question_id 외래키가 생성된다.
  • 외래키는 항상 자식(N쪽) 에 생성된다.

@OneToMany

public class Question{
    @OneToMany(mappedBy = "question")
    private List<Answer> answers = new ArrayList<>();
}

 

Question에서 답변 목록을 바로 조회할 수 있다.

mappedBy = "question" 의 의미

mappedBy = "question"은 연관관계의 주인이 Answer.question 필드라는 의미이다.

 

@ManyToOne
private Question question;

 

여기 있는 question 필드를 가리키는 것이다.

따라서 Question은 관계를 관리하지 않고 조회만 담당한다.

 

@ManyToOne이 실제 외래키를 관리하는 연관관계의 주인이고, @OneToMany(mappedBy = "...")는 그 관계를 조회하기 위한 반대편 필드이다. 따라서 연관관계의 변경은 항상 ManyToOne 쪽에서 이루어진다.

왜 new ArrayList<>()를 해야 할까?

private List<Answer> answers = new ArrayList<>();

 

초기화를 하지 않으면 answers가 null 상태가 된다. 그러면

 

question.getAnswers().add(answer);

 

를 실행했을 때 NullPointerException이 발생한다.

미리 빈 리스트를 만들어 두면 언제든 안전하게 add()를 사용할 수 있다.

또한 JPA에서도 컬렉션 필드는 항상 초기화하는 것이 권장되는 방식이다.

OneToMany  vs  ManyToOne

구분 OneToMany ManyToOne
관계 1:N N:1
위치 부모 엔티티에 위치 자식 엔티티에 위치
필드 타입 Collection 타입 (List, Set 등) 단일 엔티티 타입
외래키 자식 테이블에 생성 자식 테이블에 생성
예시 Question 엔티티의 answers 필드 Answer 엔티티의 question 필드
조회 방식 부모에서 자식들을 바로 조회 가능 자식에서 부모를 바로 조회 가능
사용 목적 부모 엔티티에서 자식 엔티티들을 관리할 때 자식 엔티티에서 부모 엔티티를 참조할 때

답변 조회 방법

1. Repository를 통해 직접 조회하는 방식

List<Answer> answers = answerRepository.findByQuestion(q5); 
List<Answer> answers = answerRepository.findByQuestionId(5);

2. 객체지향 방식

List<Answer> answers = q5.getAnswers();

 

이미 Question 객체를 가지고 있다면 Repository를 다시 호출하지 않고 바로 답변 목록을 조회할 수 있다.

Repository보다 객체를 이용하는 방식

기존에는 Answer를 직접 생성하고 연관관계를 연결해야 했다.

 

Question question2 = questionRepository.findById(2).get();

Answer answer = new Answer();
answer.setContent("답변 내용");
answer.setQuestion(question2);
answerRepository.save(answer);

 

이를 Question 내부에서 처리하도록 변경할 수 있다.

 

Question question5 = questionRepository.findById(5).get();

question5.addAnswer("답변 내용");

 

Question 내부

public class Question {
    @OneToMany(mappedBy = "question", cascade = {CascadeType.PERSIST, CascadeType.REMOVE})
    private List<Answer> answers = new ArrayList<>();

    // 이렇게 Question 내부에 메서드를 생성
    public void addAnswer(String content) {
        Answer answer = new Answer();
        answer.setContent(content);
        answer.setQuestion(this);
        answers.add(answer);
    }
}

 

이렇게 만들면 Answer 생성, Question 연결, 컬렉션 추가를 모두 Question이 책임지게 된다.

객체가 자신의 데이터를 스스로 관리하므로 책임이 명확해지고 캡슐화도 향상된다.

댓글