[JPA] 연관관계 매핑 - 단방향 연관관계

Bam·2025년 5월 17일
0

Spring

목록 보기
55/73
post-thumbnail

엔티티는 독립적으로 존재하는 것이 아니라 대부분 다른 엔티티와 관계를 맺고 있습니다.

자바 객체는 참조를 이용하여 관계를 맺고, 릴레이션은 외래 키를 이용해서 관계를 맺기 때문에 이들을 잘 이해하고 매핑해야 합니다. 앞으로 몇 개의 포스트들을 통해서 연관관계 매핑을 하는 방법에 대해서 알아보도록 하겠습니다.


단방향 연관관계

한 쪽 엔티티만 상대를 알고 상대는 다른 쪽 엔티티를 전혀 모르는 관계를 단방향 연관관계라고 합니다.

한 쪽 엔티티에만 다른 쪽 엔티티의 참조 정보를 넣으면 되기 때문에 엔티티 구조가 간단해지지만 반대 방향의 참조가 필요한 경우에 추가적인 매핑 정보를 주어야하기도 합니다.

연관 관계 매핑에 사용되는 어노테이션은 @JoinColumn, @ManyToOne이 있습니다.

@ManyToOne

다대일(N:1) 연관관계를 매핑하기 위해 사용합니다.

1:1 관계에서는 @OneToOne을 사용합니다.

이 ERD를 보면 주문은 고객(주문자)의 정보를 가지고 있습니다. 반대로 고객은 주문에 대한 정보를 가지고 있지 않습니다.
그리고 하나의 고객은 여러 개의 주문을 가지도록 관계가 표현되었기 때문에 다대일(N:1, 주문 : 고객) 관계를 나타내고 있습니다.

위 ERD를 기반으로 단방향 연관관계를 매핑하면 다음과 같습니다.

@Entity
@Table(name = "customers_table")
public class Customer {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "c_id", nullable = false)
    private Long id;

    @Column(name = "name", nullable = false, length = 100)
    private String name;
    
    //생성자 및 getter
}
@Entity
@Table(name = "orders_table")
public class Order {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "o_id", nullable = false)
    private Long id;

    @Column(name = "order_date", nullable = false)
    private LocalDateTime orderDate;

    /**
     * 단방향 @ManyToOne
     * orders_table.c_id → customers_table.c_id 외래 키 매핑
     */
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "c_id", nullable = false)
    private Customer customer;
    
    //생성자 및 getter
}

주문 Order만이 Customer 엔티티의 정보를 알 고 있기 때문에 Order에 Customer 참조 필드를 추가하고 @ManyToOne을 사용했습니다.

@ManyToOne에서 사용가능한 속성은 다음과 같습니다.

속성설명
optionalfalse 설정 시 연관 엔티티를 항상 설정해야함
fetchfetch 전략 설정
cascade영속성 전이 설정
targetEntity연관 엔티티의 타입 정보를 설정

fetch 전략에는 다음 두 가지 방식이 있습니다.

  • FetchType.EAGER: 엔티티 조회 시 연관 엔티티까지 함께 조회
  • FetchType.LAZY: 연관 엔티티를 실제 사용 시점에 조회

Fetch 전략에 대한 더 자세한 내용은 추후에 따로 다룰 예정입니다.

영속성 전이는 특정 엔티티를 영속 상태로 만들 때 관계된 엔티티들도 함께 영속 상태로 만드는 기능입니다. Type에 따라 다양한 영속성 전이 옵션을 제공하고 있습니다.

마찬가지로 추후에 더 자세하게 다루려고 합니다.

@JoinColumn

@JoinColumn은 외래 키 컬럼을 매핑할 때 사용합니다. 위 예시에선 외래키인 Order의 Customer.c_id가 외래 키입니다.

/**
* 단방향 @ManyToOne
* orders_table.c_id → customers_table.c_id 외래 키 매핑
*/
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "c_id", nullable = false)
private Customer customer;

@JoinColumn에서 사용가능한 속성들은 다음과 같습니다.

속성설명
name매핑할 외래 키 이름
referencedColumnName외래 키가 참조하는 대상 테이블 컬럼 명
미사용 시 참조 대상 테이블의 기본 키 컬럼명을 사용
foreignKey(DDL)외래 키 제약조건 설정

이 외에도 @Column에서 사용 가능한 속성들을 사용할 수 있습니다.


연관관계 CRUD

연관관계 엔티티를 CRUD 하는 방법에 대해 알아보겠습니다.

  • Create
    생성은 위에서 본 방식대로 연관관계 매핑에 사용되는 어노테이션들을 붙여서 생성합니다.

  • Read
    읽기(조회)는 객체 그래프 탐색, JPQL 두 가지 방식으로 조회합니다.

    • 객체 그래프 탐색: 객체 연관관계를 이용하여 order.getCustomer()로 연관관계의 Customer를 조회할 수 있습니다.
    • JPQL: JOIN을 활용하여 SELECT 구문을 통해 조회합니다.
  • Update
    수정은 setter 등을 통해 트랜잭션에서 Order 연관관계에 있는 Customer에 변경 사항이 발생하면 변경 감지 Dirty Check를 사용해서 자동으로 UPDATE가 수행됩니다.

  • Delete
    연관관계가 포함된 엔티티를 삭제할 때는 연관관계를 먼저 제거해야합니다. 외래 키 제약조건이 걸려있기 때문에 그냥 삭제하면 오류가 발생합니다. 다음과 같이 연관관계 엔티티를 제거한 후 삭제를 수행해야합니다.

order.setCustomer(null);	//연관관계 먼저 삭제
em.remove(order);	//그 후 엔티티 삭제

0개의 댓글