DB 접근/JPA ( Java Persistence API )

[JPA] 연관관계 Mapping

JABHACK 2025. 1. 6. 10:03

단방향

📌 단방향 연관관계는 객체 간의 관계가 한쪽에서만 참조 = 일방통행될 수 있는 관계를 말한다. 설정이 단순하고 유지 관리가 쉬우며 불필요한 데이터 접근을 방지할 수 있다.

 

 

 

데이터베이스 중심 객체 설계

  • FK 값은 Tutor가 가지고 있다.
    • Tutor만 참조할 수 있다.
    • N:1, 다대일 연관관계, 가장 많이 사용된다.
    • 여러명(N)의 Tutor가 어떤 Company(1)에 소속 되어있는지 설정할 수 있다.
@Entity
@Table(name = "tutor")
public class Tutor {
		@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
		private Long id;
		
		private String name;
		
		@Column(name = company_id)
		private Long companyId;
		
		// 기본 생성자, getter/setter
}
@Entity
@Table(name = "company")
public class Company {
		@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
		private Long id;
		
		private String name;
		
		// 기본 생성자, getter/setter
}
// Company 생성 및 persist
Company company = new Company("sparta");
em.persist(company);

// Tutor 생성, setCompanyId, persist
Tutor tutor = new Tutor("wonuk");
tutor.setCompanyId(company.getId());
em.persist(tutor);

// IDENTITY 전략을 사용하면 persist()이후 PK를 바로 조회할 수 있다.
Tutor findTutor = em.find(Tutor.class, tutor.getId());

// 조회한 Tutor의 CompanyId로 Company 조회
Long companyId = findTutor.getCompanyId();
Company findCompany = em.find(Company.class, companyId);
  • 객체 지향적인 코드를 작성할 수 없다.
  • Java Collection을 사용하는 것처럼 tutor.getCompany() 를 사용하지 못한다.

 

객체 지향 객체 설계

  • 객체는 다른 객체를 참조한다.
  • N:1 관계는 @ManyToOne, @JoinColumn을 사용한다.
  • 코드예시
@Entity
@Table(name = "tutor")
public class Tutor {
		@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
		private Long id;
		
		private String name;
		// N:1 단방향 연관관계 설정
		@ManyToOne
		@JoinColumn(name = "company_id")
		private Company company;
		
		// 기본 생성자, getter/setter
}
// Company 생성 및 persist
Company company = new Company("sparta");
em.persist(company);

// Tutor 생성, setCompany, persist
Tutor tutor = new Tutor("wonuk");
tutor.setCompany(company);
em.persist(tutor);

// IDENTITY 전략을 사용하면 persist()이후 PK를 바로 조회할 수 있다.
Tutor findTutor = em.find(Tutor.class, tutor.getId());

// 조회한 Tutor의 Company 조회
Company findCompany = findTutor.getCompany();
  • Tutor의 FK와 Company의 PK를 @JoinColumn으로 매핑한다.
  • Java Collection을 사용하는 것처럼 tutor.getCompany() 를 사용할 수 있다.

 

 

양방향

📌 양방향 연관관계는 객체 간의 관계가 양쪽에서 서로를 참조할 수 있는 관계를 의미한다. 이를 통해 양쪽에서 데이터를 쉽게 접근할 수 있지만 관계를 관리할 때 한쪽에서만 연관관계를 설정하거나 삭제하지 않도록 주의가 필요하다.

테이

  • 테이블에 변화는 없다.
    • Tutor 테이블의 FK로 Company 테이블에 JOIN
    • Company 테이블의 PK로 Tutor 테이블에 JOIN
  • 사실상 테이블의 연관관계에는 방향의 개념이 없다.

객체

@Entity
@Table(name = "tutor")
public class Tutor {
		@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
		private Long id;
		
		private String name;
		// N:1 단방향 연관관계 설정
		@ManyToOne
		@JoinColumn(name = "company_id")
		private Company company;
		
		// 기본 생성자, getter/setter
}
@Entity
@Table(name = "company")
public class Company {
		@Id @GeneratedValue(strategy = GenerationType.IDENTITY)
		private Long id;
		
		private String name;
		
		// null을 방지하기 위해 ArrayList로 초기화 한다.(관례)
		@OneToMany(mappedBy = "company")
		private List<Tutor> tutors = new ArrayList<>();
		
		// 기본 생성자, getter/setter
}
  • 양방향 연관관계 설정을 위해 mappedBy 속성을 설정한다.
    • Tutor의 company 필드와 매핑된다.
// Company 생성 및 persist
Company company = new Company("sparta");
em.persist(company);

// Tutor 생성, setCompany, persist
Tutor tutor = new Tutor("wonuk");
tutor.setCompany(company);
em.persist(tutor);

// IDENTITY 전략을 사용하면 persist()이후 PK를 바로 조회할 수 있다.
Tutor findTutor = em.find(Tutor.class, tutor.getId());

// 조회한 Tutor의 Company 조회
Company findCompany = findTutor.getCompany();

// Company에 속한 Tutor List 조회
List<Tutor> tutors = findCompany.getTutors();
  • 반대 방향으로 객체 그래프를 탐색할 수 있다.

 

 

양방향 연관관계의 주인

📌 mappedBy는 JPA 양방향 연관관계 설정 시 사용되는 속성으로 두 엔티티 간의 관계에서 연관관계의 주인이 아닌 쪽에 선언한다. 이를 통해 외래 키 관리 책임을 주인 엔티티에 두고 매핑이 중복되지 않도록 한다.

 

테이블 연관관계

  • Tutor ↔ Company (양방향)
  • 테이블은 방향이 없다

객체 연관관계

  • Tutor → Company N:1 연관관계 (단방향)
  • Company → Tutor 1:N 연관관계 (단방향)
  • 객체 연관관계는 결국 단방향 연관관계 두개로 양방향이 설정된다.

양방향 연관관계의 주인

  1. Tutor의 Company를 수정할 때 FK가 수정
  2. Company의 Tutor를 수정할 때 FK가 수정
  • Tutor가 새로운 Company를 간다면?
    • Tutor의 참조값 Company 수정
    • Company의 참조값 List tutors 수정
    • DB 입장에서는 FK만 수정되면 된다. = mappedBy가 없는 쪽이 수정되면 된다.
  • 결국, 둘 중 하나로만 외래 키를 관리해야 한다.
  • 연관관계의 주인 선정 기준
    • 항상 FK가 있는 곳을 연관관계의 주인으로 지정한다.
    • Company가 주인인 경우
      • Company를 수정할 때 Tutor를 Update하는 SQL이 실행
      • 두번의 SQL이 실행되어야 한다. 혼동되기 쉽다.

'DB 접근 > JPA ( Java Persistence API )' 카테고리의 다른 글

연관관계  (0) 2025.01.12
[JPA] Spring Data JPA  (0) 2025.01.07
[JPA] Entity  (1) 2025.01.05
[JPA] 영속성 컨텍스트  (2) 2025.01.04
[JPA] 페러다임 불일치 문제 [객체 관계형 데이터베이스]  (1) 2025.01.02