Spring Data JPA

Spring JPA - 연관관계 매핑

Stark97 2023. 8. 13. 02:16
반응형

저번 포스트에서 Entity에 대해서 알아봤으니 이번엔 연관관계에 대한 매핑을 알아보자

 

1. 엔티티의 연관관계 매핑이란?


  • 엔티티의 연관관계 매핑은 객체 간의 관계를 데이터베이스 테이블에 매핑하는 작업을 의미한다. 이를 통해 객체지향적인 프로그래밍 모델을 유지하면서 데이터베이스와의 관계를 표현할 수 있다. JPA에서는 다양한 연관관계 매핑 어노테이션을 제공하여 이를 구현할 수 있다.

연관관계 매핑에는 다음과 같은 어노테이션들이 사용된다.
  1. @OneToOne:
    • 일대일 관계를 매핑한다. 양방향 매핑이 가능하며, 대상 엔티티와 매핑할 때는 @JoinColumn 어노테이션을 사용한다.

  2. @OneToMany:
    • 일대다 관계를 매핑한다. 단방향 매핑 또는 양방향 매핑으로 설정할 수 있다. 대상 엔티티에는 @ManyToOne 어노테이션을 사용하여 매핑한다.

  3. @ManyToOne:
    • 다대일 관계를 매핑한다. 대상 엔티티와 매핑할 때는 @JoinColumn 어노테이션을 사용한다.

  4. @ManyToMany:
    • 다대다 관계를 매핑한다. 양방향 매핑이 가능하며, 연결 테이블을 사용하여 매핑한다.

추가적인 매핑 옵션
  • 지연 로딩/즉시 로딩 설정: 연관된 엔티티를 언제 로딩할지 결정한다.
  • 연관관계의 소유자 설정: 양방향 매핑에서 연관관계의 주인을 지정한다.
  • 연관관계의 캐스케이드 설정: 연관된 엔티티에 대한 오퍼레이션을 전파한다.
  • 연관관계의 페치 전략 설정: 연관된 엔티티를 어떻게 조회할지 전략을 설정한다.

 


 

2. 연관관계 매핑 예시


  • 다음은 Author 엔티티와 Book 엔티티 간의 일대다 관계를 매핑하는 예시이다.
@Entity
public class Author {
    @Id
    private Long id;
    
    private String name;
    
    @OneToMany(mappedBy = "author")
    private List<Book> books;
    
    // Getters, Setters, Constructors ...
}

@Entity
public class Book {
    @Id
    private Long id;
    
    private String title;
    
    @ManyToOne
    @JoinColumn(name = "author_id")
    private Author author;
    
    // Getters, Setters, Constructors ...
}
  • 위의 예시에서 Author 엔티티는 @OneToMany 어노테이션을 사용하여 books 필드와 Book 엔티티 간의 일대다 관계를 매핑하였다. Book 엔티티는 @ManyToOne 어노테이션과 @JoinColumn 어노테이션을 사용하여 author 필드와 Author 엔티티 간의 다대일 관계를 매핑하였다.

 


 

3. 연관관계 매핑의 중요성


  • 연관관계 매핑은 데이터베이스 테이블 간의 관계를 객체로 표현하기 위한 중요한 작업이다. 이를 통해 객체 그래프를 효율적으로 구성하고 데이터베이스와의 일관성을 유지할 수 있으며, 코드의 가독성과 유지보수성을 향상시키고, 객체 지향적인 설계를 가능하게 한다.

객체 지향 프로그래밍과 관계형 데이터베이스의 차이 극복
  • 연관관계 매핑을 통해 객체 지향 프로그래밍의 관계와 관계형 데이터베이스의 관계를 일치시킬 수 있다. 이로 인해 개발자는 객체 지향적인 코드 작성에 집중할 수 있으며, 데이터베이스와의 연동 부분은 JPA가 처리하게 된다.

예시 코드
  • 다음은 Student와 Course 엔티티 간의 다대다 관계를 매핑하는 예시이다.
@Entity
public class School {
    @Id
    private Long id;
    
    private String name;
    
    // 일대다 관계: 하나의 학교에 여러 학생이 있을 수 있습니다.
    @OneToMany(mappedBy = "school")
    private List<Student> students;
    
    // Getters, Setters, Constructors ...
}

@Entity
public class Student {
    @Id
    private Long id;
    
    private String name;
    
    // 다대일 관계: 여러 학생이 하나의 학교에 소속될 수 있습니다.
    @ManyToOne
    @JoinColumn(name = "school_id")
    private School school;
    
    // Getters, Setters, Constructors ...
}
  • 위의 코드에서 School 엔티티는 @OneToMany 어노테이션을 사용하여 students 필드와 Student 엔티티 간의 일대다 관계를 매핑하였다.

  • Student 엔티티는 @ManyToOne 어노테이션과 @JoinColumn 어노테이션을 사용하여 school 필드와 School 엔티티 간의 다대일 관계를 매핑하였다.


 

4. 주의사항


양방향 매핑
  • 양방향 매핑은 서로 참조하는 두 엔티티 사이의 관계를 정의한다. 이를 통해 양쪽 엔티티에서 서로의 정보를 쉽게 가져올 수 있다. 하지만, 주의하지 않으면 무한 루프에 빠질 수 있으므로 연관관계의 주인을 명확히 지정해야 한다.
@Entity
public class Parent {
    @Id
    private Long id;
    
    // 일대다 관계: 하나의 부모에 여러 자식이 있을 수 있습니다.
    @OneToMany(mappedBy = "parent")
    private List<Child> children;
    
    // Getters, Setters, Constructors ...
}

@Entity
public class Child {
    @Id
    private Long id;
    
    // 다대일 관계: 여러 자식이 하나의 부모에 소속될 수 있습니다.
    @ManyToOne
    @JoinColumn(name = "parent_id")
    private Parent parent;
    
    // Getters, Setters, Constructors ...
}

 

단방향 매핑
  • 단방향 매핑은 한 엔티티에서 다른 엔티티로만 접근이 가능한 관계를 정의한다. 단방향 매핑은 구현이 간단하고 명확하지만, 반대 방향으로의 접근이 필요한 경우 양방향 매핑을 고려해야 한다.
@Entity
public class Teacher {
    @Id
    private Long id;
    
    private String name;
    
    // Getters, Setters, Constructors ...
}

@Entity
public class Student {
    @Id
    private Long id;
    
    // 다대일 관계: 여러 학생이 하나의 선생님에 소속될 수 있습니다.
    @ManyToOne
    @JoinColumn(name = "teacher_id")
    private Teacher teacher;
    
    // Getters, Setters, Constructors ...
}

 


 

5. 연관관계 매핑의 고급 기능


상속 관계 매핑
  • JPA는 엔티티 간의 상속 관계도 매핑할 수 있다. 이를 통해 객체 지향의 상속 개념을 데이터베이스에도 적용할 수 있으며, 코드의 재사용성과 확장성을 높일 수 있다.
@Entity
@Inheritance(strategy = InheritanceType.JOINED)
public class Vehicle {
    @Id
    private Long id;
    
    private String manufacturer;
    
    // Getters, Setters, Constructors ...
}

@Entity
public class Car extends Vehicle {
    private String model;
    
    // 차량의 모델을 정의합니다.
    // Getters, Setters, Constructors ...
}

@Entity
public class Bike extends Vehicle {
    private int gearNumber;
    
    // 자전거의 기어 수를 정의합니다.
    // Getters, Setters, Constructors ...
}

 

임베디드 타입 사용
  • JPA는 임베디드 타입을 통해 엔티티 내부에 복합 값 타입을 정의할 수 있습니다. 이를 통해 코드의 중복을 줄이고, 도메인 모델의 표현력을 높일 수 있습니다.
@Embeddable
public class Address {
    private String street;
    private String city;
    private String state;
    private String zipCode;
    
    // 주소를 정의하는 복합 값 타입입니다.
    // Getters, Setters, Constructors ...
}

@Entity
public class Person {
    @Id
    private Long id;
    
    private String name;
    
    @Embedded
    private Address address;
    
    // 임베디드 타입을 사용하여 주소를 매핑합니다.
    // Getters, Setters, Constructors ...
}

 


 

6. 연관관계 매핑 시 주의사항


성능 최적화
  • 연관관계 매핑은 편리하지만, 성능 문제를 일으킬 수 있다. N+1 문제와 같은 성능 이슈를 방지하기 위해 페치 전략을 적절히 설정해야 한다.
@Entity
public class Department {
    @Id
    private Long id;
    
    private String name;
    
    // 일대다 관계: 하나의 부서에 여러 직원이 있을 수 있습니다.
    // FetchType.LAZY를 사용하여 N+1 문제를 방지합니다.
    @OneToMany(mappedBy = "department", fetch = FetchType.LAZY)
    private List<Employee> employees;
    
    // Getters, Setters, Constructors ...
}

@Entity
public class Employee {
    @Id
    private Long id;
    
    private String name;
    
    // 다대일 관계: 여러 직원이 하나의 부서에 소속될 수 있습니다.
    @ManyToOne
    @JoinColumn(name = "department_id")
    private Department department;
    
    // Getters, Setters, Constructors ...
}

 

데이터 무결성 유지
  • 연관관계를 잘못 설정하면 데이터 무결성이 깨질 수 있습니다. 연관관계의 방향, 다중성, 제약 조건 등을 정확히 이해하고 적용해야 합니다.
@Entity
public class Order {
    @Id
    private Long id;
    
    // 다대일 관계: 여러 주문이 하나의 고객에 소속될 수 있습니다.
    // NotNull 제약 조건을 사용하여 데이터 무결성을 유지합니다.
    @ManyToOne
    @JoinColumn(name = "customer_id", nullable = false)
    private Customer customer;
    
    // Getters, Setters, Constructors ...
}

@Entity
public class Customer {
    @Id
    private Long id;
    
    private String name;
    
    // 일대다 관계: 하나의 고객에 여러 주문이 있을 수 있습니다.
    @OneToMany(mappedBy = "customer")
    private List<Order> orders;
    
    // Getters, Setters, Constructors ...
}
  • 위의 예시 코드에서 성능 최적화 부분에서는 FetchType.LAZY를 사용하여 N+1 문제를 방지하였다. 데이터 무결성 유지 부분에서는 nullable = false를 사용하여 NotNull 제약 조건을 적용하였다. 이를 통해 연관관계 매핑 시 성능과 데이터 무결성을 적절히 관리할 수 있다.

 


 

7. 결론


 

연관관계 매핑은 JPA를 사용하는 개발에서 중요한 개념이다.
객체 지향적인 설계와 데이터베이스 설계를 일치시키는 역할을 하며, 이를 통해 풍부하고 유연한 도메인 모델을 구축할 수 있다.
하지만, 성능 최적화와 데이터 무결성 유지 등의 주의사항을 염두에 두어야 하며, 프로젝트의 요구사항에 맞게 적절한 매핑 전략을 선택해야 한다.

 

 

 

 

2023.08.13 - [JPA] - Spring JPA - Entity

 

Spring JPA - Entity

코딩은 글쓰기라고 생각한다. 나는 이 블로그에 나의 모든 개발일상을 적을것이다.

curiousjinan.tistory.com

 

반응형