본문 바로가기

JPA

[JPA] JPA 연관관계 매핑 (1)

 

 

 

"객체를 테이블에 맞추어 데이터 중심으로 모델링하면, 협력 관계를 만들 수 없다."는 말은 객체 지향 프로그래밍과 관계형 데이터베이스 설계 간의 근본적인 차이점을 설명합니다. 이를 더 자세히 이해하려면, 객체 지향 프로그래밍과 관계형 데이터베이스 설계의 차이점을 고려해야 합니다.

객체 지향 프로그래밍 (OOP)

  1. 객체와 협력 관계:
    • 객체 지향 프로그래밍에서 객체들은 서로 협력하여 기능을 수행합니다. 예를 들어, Member 객체와 Team 객체는 서로 참조하고 협력하여 데이터를 처리합니다.
    • 객체 간의 관계는 참조 (reference)를 통해 직접 연결됩니다.
  2. 상태와 행위:
    • 객체는 상태(state)와 행위(behavior)를 가지며, 메서드를 통해 다른 객체와 상호작용합니다.

관계형 데이터베이스 (RDB)

  1. 테이블과 외래 키:
    • 관계형 데이터베이스에서는 데이터를 테이블 형식으로 저장하며, 테이블 간의 관계는 외래 키 (foreign key)로 정의됩니다.
    • 예를 들어, Member 테이블은 team_id 외래 키 컬럼을 통해 Team 테이블과 관계를 맺습니다.
  2. 데이터 중심 설계:
    • 관계형 데이터베이스에서는 데이터의 저장과 효율적인 검색이 중심입니다. 테이블 간의 관계를 통해 데이터를 조회하고 조인 (JOIN) 연산을 사용하여 관련 데이터를 결합합니다.

근본적인 차이점과 문제점

  1. 참조 vs. 외래 키:
    • 객체 지향 프로그래밍에서는 객체가 다른 객체를 참조합니다. 예를 들어, Member 객체는 Team 객체를 직접 참조합니다.
    • 관계형 데이터베이스에서는 테이블이 다른 테이블을 외래 키로 참조합니다. 예를 들어, Member 테이블은 team_id 외래 키로 Team 테이블을 참조합니다.
    • 이 차이로 인해, 객체 지향 설계를 관계형 데이터베이스에 맞추어 모델링하면 객체 간의 직접 참조가 사라지고, 대신 외래 키를 통한 간접 참조가 되면서 객체 지향적 협력 관계가 손상됩니다.
  2. 행위와 협력 관계의 부재:
    • 데이터 중심 설계는 데이터를 저장하고 조회하는 데 초점을 맞추지만, 객체 지향 설계는 객체 간의 협력과 행위에 초점을 맞춥니다. 데이터베이스 테이블로 모델링하면 객체 간의 협력 관계를 자연스럽게 표현하기 어려워집니다.
  3. 비즈니스 로직의 손실:
    • 객체 지향 모델에서는 객체 간의 협력을 통해 비즈니스 로직을 구현할 수 있지만, 테이블 중심의 모델에서는 이러한 협력 관계를 표현하기 어렵습니다. 결과적으로 비즈니스 로직이 데이터베이스의 제약이나 구조에 종속될 수 있습니다.

결론

객체 지향 설계를 관계형 데이터베이스 테이블에 맞추어 데이터 중심으로 모델링하면 객체 지향 설계의 주요 이점인 협력 관계와 행위 중심의 설계가 손상됩니다. 따라서 JPA와 같은 ORM(Object-Relational Mapping) 도구를 사용하여 객체와 테이블 간의 간극을 메우고, 객체 지향 설계를 유지하면서 관계형 데이터베이스와 상호작용할 수 있습니다.

 

 

단방향 연관관계

설명

단방향 연관관계는 한쪽 방향으로만 참조하는 관계입니다. 예를 들어, Member 객체가 Team 객체를 참조하지만, Team 객체는 Member 객체를 참조하지 않는 경우입니다.

 

Member 클래스

import javax.persistence.*;
import lombok.Getter;
import lombok.Setter;

@Entity
@Getter
@Setter
public class Member {
    
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    private String name;
    
    @ManyToOne
    @JoinColumn(name = "team_id")
    private Team team;
}

 

Team 클래스

import javax.persistence.*;
import lombok.Getter;
import lombok.Setter;

@Entity
@Getter
@Setter
public class Team {
    
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    private String name;
}

 

양방향 연관관계

설명

양방향 연관관계는 두 객체가 서로를 참조하는 관계입니다. 예를 들어, Member 객체가 Team 객체를 참조하고, Team 객체도 Member 객체를 참조하는 경우입니다. 양방향 관계에서는 한쪽을 주인(Owner)으로 설정해야 합니다. JPA에서는 주인만이 외래 키를 관리합니다.

 

Member클래스

import javax.persistence.*;
import lombok.Getter;
import lombok.Setter;

@Entity
@Getter
@Setter
public class Member {
    
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    private String name;
    
    @ManyToOne
    @JoinColumn(name = "team_id")
    private Team team;
    
    public void setTeam(Team team) {
        this.team = team;
        if (!team.getMembers().contains(this)) {
            team.getMembers().add(this);
        }
    }
}

 

Team 클래스

import javax.persistence.*;
import lombok.Getter;
import lombok.Setter;

import java.util.ArrayList;
import java.util.List;

@Entity
@Getter
@Setter
public class Team {
    
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    
    private String name;
    
    @OneToMany(mappedBy = "team", cascade = CascadeType.ALL, orphanRemoval = true)
    private List<Member> members = new ArrayList<>();
}

 

 

  • 연관관계의 주인 (Owner)
    • JPA에서 양방향 연관관계를 맺을 때, 두 객체가 서로를 참조합니다. 하지만 실제 데이터베이스의 외래 키는 하나만 관리됩니다.
    • JPA에서는 한쪽을 연관관계의 주인으로 설정하고, 이 주인만이 외래 키를 관리합니다.
    • 주인은 mappedBy 속성이 없고, 외래 키를 갖는 쪽입니다.
  • mappedBy
    • mappedBy 속성은 양방향 연관관계에서 사용됩니다.
    • 연관관계의 주인을 설정하지 않는 쪽에 사용되며, 주인이 아닌 쪽은 읽기 전용이 됩니다.
    • 주인이 아닌 쪽에서 외래 키를 변경해도 데이터베이스에 반영되지 않습니다.

양방향 연관관계 주의사항

1. 순수 객체 상태를 고려해서 항상 양쪽에 값을 설정하기

객체의 연관관계를 설정할 때는 양쪽 모두에 값을 설정해야 합니다. 예를 들어, Member 객체가 Team 객체를 참조하고, Team 객체가 Member 객체를 참조하도록 해야 합니다.

2. 연관관계 편의 메소드 생성하기

연관관계 편의 메소드를 사용하면 양방향 연관관계를 보다 쉽게 관리할 수 있습니다. 이를 통해 코드의 중복을 줄이고, 연관관계 설정을 일관성 있게 유지할 수 있습니다.

3. 양방향 매핑시 무한 루프 조심하기

양방향 연관관계를 설정할 때는 toString(), Lombok, JSON 생성 라이브러리 등을 사용할 때 무한 루프에 빠지지 않도록 주의해야 합니다.

 

양방향 매핑 정리

1. 단방향 매핑만으로도 연관관계 매핑 완료

단방향 매핑만으로도 연관관계 매핑을 완료할 수 있습니다. 즉, 한 쪽 방향에서의 연관관계 설정만으로도 대부분의 기능을 수행할 수 있습니다.

2. 양방향 매핑의 추가 기능

양방향 매핑은 반대 방향으로 객체를 조회(객체 그래프 탐색)하는 기능을 추가한 것입니다. 이를 통해 연관된 객체를 양쪽에서 탐색할 수 있습니다.

3. JPQL에서의 역방향 탐색

JPQL에서는 종종 역방향으로 탐색해야 할 일이 많습니다. 양방향 매핑을 통해 이런 탐색을 보다 쉽게 할 수 있습니다.

4. 필요할 때 양방향 매핑 추가

단방향 매핑을 먼저 잘 설정한 후, 필요할 때 양방향 매핑을 추가해도 됩니다. 이는 테이블 구조에 영향을 주지 않으므로 유연하게 적용할 수 있습니다.

연관관계의 주인을 정하는 기준

1. 비즈니스 로직이 아닌 외래 키 위치로 결정

연관관계의 주인을 결정할 때 비즈니스 로직을 기준으로 결정해서는 안 됩니다. 연관관계의 주인은 외래 키가 있는 위치를 기준으로 정해야 합니다.

2. 외래 키의 위치

외래 키가 있는 엔티티가 연관관계의 주인이 됩니다. 주인은 데이터베이스 연관관계의 주체가 되며, 주인이 아닌 엔티티는 연관관계의 종속자로서 주인을 참조하게 됩니다.

 

'JPA' 카테고리의 다른 글

[JPA] JPA 고급 매핑  (0) 2024.06.29
[JPA] JPA 연관관계 매핑 (2)  (0) 2024.06.29
[JPA] JPA 엔티티 매핑  (0) 2024.06.29
[JPA] JPA 영속성 관리  (0) 2024.06.29
[JPA] JPA 생성 및 개발  (0) 2024.06.29