-
JPA 양방향 연관관계, 왜 편의 메서드를 써야 할까?Jpa 2025. 7. 30. 00:55
양방향 연관관계란?
예를 들어, 하나의 주문(Order)은 여러 개의 주문 상품(OrderItem)을 가질 수 있습니다. 그리고 각 주문 상품은 하나의 주문에 속하게 됩니다. 이를 JPA로 표현하면 다음과 같습니다.
// Order.java @OneToMany(mappedBy = "orders", cascade = CascadeType.ALL, orphanRemoval = true) private List<OrderItem> orderItems = new ArrayList<>(); // OrderItem.java @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "order_id") private Order order;- Order → OrderItem: 주문이 가진 주문 항목들
- OrderItem → Order: 이 항목이 속한 주문
이 구조는 양방향 연관관계입니다. 양쪽에서 서로를 참조하고 있는 구조입니다.
연관관계 주의사항: 양방향이면 둘 다 설정해야함
JPA에서는 실제 데이터베이스에 반영되는 외래 키의 주체를 ‘연관관계의 주인’이라고 합니다.
양방향 관계에서는 반드시 한쪽이 주인이고, 다른 쪽은 거울(Mapped) 역할을 합니다.- 위 예제에서 OrderItem.orders가 연관관계의 주인입니다. (@ManyToOne 쪽)
- Order.orderItems는 mappedBy 속성을 통해 단순히 반대 방향을 표현하는 비주인입니다.
즉, DB의 order_id 컬럼은 OrderItem 객체의 orders 필드를 기준으로 설정됩니다.
둘 중 하나만 설정하면 생기는 문제
Order order = new Order(); OrderItem item = new OrderItem(); // Order → OrderItem만 설정 order.getOrderItems().add(item);위 코드처럼 order 쪽 리스트에 item을 추가했다고 해서, 실제로 관계가 완성된 건 아닙니다.
- OrderItem.order는 여전히 null이므로,
- DB에 저장될 때 외래 키(order_id) 값도 null이 됩니다.
- 이는 ConstraintViolationException 또는 관계가 끊어진 객체로 인한 NullPointerException의 원인이 됩니다.
그래서 필요한 것이 "양방향 연관관계 편의 메서드"
양쪽 관계를 한 번에 설정하는 메서드를 만들어 실수를 방지합니다.
// Order.java public void addOrderItem(OrderItem item) { this.orderItems.add(item); // order → item item.setOrders(this); // item → order }- 자바 객체 간의 관계도 정확히 연결
- JPA도 정상적으로 외래 키를 인식해 DB에 저장
생성자 내부에서도 편의 메서드를 사용하자
public Order(User user, int totalPrice, List<OrderItem> orderItems, OrderStatus orderStatus) { this.user = user; this.totalPrice = totalPrice; this.orderItems = new ArrayList<>(); this.orderStatus = orderStatus; for (OrderItem item : orderItems) { addOrderItem(item); // 연관관계 편의 메서드 } }이처럼 생성 시점에 양방향을 정확히 설정해두면, 추후 서비스 로직이나 테스트 코드에서 관계 오류를 방지할 수 있습니다.
편의 메서드 없이 생기는 문제 요약
사용 문제 order.getOrderItems().add(item)만 호출 item.setOrders(order) 생략으로 관계 누락 외래 키 누락 order_id가 null로 저장됨 객체 그래프 불일치 order.getOrderItems()로 조회 불가능 예외 발생 가능성 삭제·조회 시 NullPointerException, ConstraintViolationException
실무에서는 어떻게 할까?
- 연관관계의 주인이 아닌 쪽(대개 OneToMany)에 addXXX() 편의 메서드를 두는 것이 일반적입니다.
- 도메인 모델 생성자 내부에서 편의 메서드를 사용하여 양쪽 관계를 동시에 설정합니다.
- 한 쪽만 세팅하고 나머지를 잊는 실수를 방지합니다.
결론
- JPA에서는 연관관계의 주인만 DB에 반영되지만, 자바 객체 간의 관계까지 완전하게 만들려면 양쪽 모두 설정
- 이를 자동화한 것이 양방향 연관관계 편의 메서드
- 코드의 일관성, 디버깅 편의성, 예외 방지를 위해 반드시 사용
'Jpa' 카테고리의 다른 글
@Transactional에 대해서 (0) 2025.07.30 Spring Data JPA에서 동적 검색 해결: 사용자 정의 리포지토리와 Querydsl의 도입기 (3) 2025.07.21 연관관계 엔티티 직렬화 오류와 해결 (DTO 패턴) (6) 2025.07.07