본 글은 JPA에서 엔티티 간의 단방향 관계와 양방향 관계에 대한 개념을 정리한 내용입니다.
JPA에서는 엔터티 간의 관계를 정의할 때 단방향과 양방향 관계를 설정할 수 있습니다. 이 관계 설정은 데이터베이스와의 매핑을 효율적으로 관리하는 데 중요한 역할을 합니다.
연관관계 매핑 어노테이션
@ManyToOne
@Entity
@Table(name = "food")
public class Food {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private double price;
@ManyToOne
@JoinColumn(name = "user_id") // 외래 키 컬럼
private User user;
// Getter 및 Setter
}
다대일 관계를 정의합니다. 하나의 엔티티가 여러 다른 엔티티와 관계를 맺을 때 사용됩니다.
@OneToMany
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
@OneToMany(mappedBy = "user") // 연관된 필드명
private List<Food> foodList = new ArrayList<>();
// Getter 및 Setter
}
일대다 관계를 정의합니다. 하나의 엔티티가 여러 다른 엔티티와 관계를 맺을 때 사용됩니다.
@OneToOne
@Entity
@Table(name = "address")
public class Address {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String street;
@OneToOne(mappedBy = "address")
private User user;
// Getter 및 Setter
}
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
@OneToOne
@JoinColumn(name = "address_id") // 외래 키 컬럼
private Address address;
// Getter 및 Setter
}
일대일 관계를 정의합니다. 한 엔티티가 다른 엔티티와 일대일 관계를 맺을 때 사용됩니다.
@ManyToMany
@Entity
@Table(name = "students")
public class Student {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
@ManyToMany
@JoinTable(name = "student_course",
joinColumns = @JoinColumn(name = "student_id"),
inverseJoinColumns = @JoinColumn(name = "course_id"))
private List<Course> courses = new ArrayList<>();
// Getter 및 Setter
}
@Entity
@Table(name = "courses")
public class Course {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String title;
@ManyToMany(mappedBy = "courses")
private List<Student> students = new ArrayList<>();
// Getter 및 Setter
}
다대다 관계를 정의합니다. 두 엔티티가 서로 여러 개의 관계를 맺을 때 사용됩니다. 중간 테이블이 필요합니다.
양방향 관계
외래키의 주인은 상대 Entity타입의 필드를 가지면서 @JoinColumn()을 활용하여 외래 키의 속성을 설정을 해줍니다.
반면, 상대 Entity는 외래 키의 주인 Entity 타입의 필드를 가지면서 외래 키의 주인을 지정할 때는 mappedBy 옵션을 사용합니다. 이 때 mappedBy의 속성값은 외래 키의 주인인 상대 Entity의 필드명을 의미합니다.
즉, 외래키의 주인이 아닌쪽에서 mappedBy옵션으로 외래키의 주인을 지정합니다.
음식
@Entity
@Table(name = "food")
public class Food {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private double price;
@OneToOne
@JoinColumn(name = "user_id")
private User user;
}
고객
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
@OneToOne(mappedBy = "user")
private List<Food> foodList = new ArrayList<>();
}
위 음식 Entity 클래스와 고객 Entity 클래스의 관계를 그림으로 표현하면 다음과 같습니다.
여기서는 Food 엔티티에서 @JoinColumn 어노테이션을 사용하여 외래 키(user_id)의 속성을 설정했습니다.
따라서 외래 키의 주인은 Food 테이블입니다. 반면, User 엔티티에서는 @OneToMany 어노테이션의 mappedBy 옵션을 사용하여 Food 테이블에서 외래 키의 주인 필드를 지정하였기 때문에, 외래 키의 주인 필드는 Food 테이블에 위치하게 됩니다.
한명의 고객은 여러번 주문이 가능한 상황입니다. 이를 Entity에서 여러번 가능함을 표현하기 위해서는 List를 사용해야합니다.
Entity에서 이렇게까지 해서 표현을 하는 이유가 무엇일까요?
SELECT u.name as username, f.name as foodname, o.order_date as orderdate
FROM users u
INNER JOIN orders o on u.id = o.user_id
INNER JOIN food f on o.food_id = f.id
WHERE o.user_id = 1;
DB 테이블에서는 고객 테이블 기준(users)으로 음식의 정보를 조회하려고 할 때 위와 같이 JOIN을 사용하여 바로 조회가 가능합니다.
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
}
만약 위와 같이 고객 Entity(User) 입장에서는 음식 Entity(Food)의 정보를 가지고 있지 않으면 음식의 정보를 조회할 방법이 없습니다.
따라서 DB 테이블에 실제 컬럼으로 존재하지는 않지만 Entity 상태에서 다른 Entity(ex: Food)를 참조하기 위해 이러한 방법을 사용합니다.
단방향 관계
단방향 관계에서는 외래 키의 주인이라는 개념이 존재하며, 이는 관계를 관리하는 쪽을 의미합니다.
외래 키 주인만이 외래 키 를 등록, 수정, 삭제할 수 있으며, 주인이 아닌 쪽은 오직 외래 키를 읽기만 가능하며, 외래 키의 주인이 되는 Entity에서 @JoinColum 어노테이션을 사용하여 외래 키를 지정합니다.
음식
@Entity
@Table(name = "food")
public class Food {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private double price;
@OneToOne
@JoinColumn(name = "user_id")
private User user;
}
고객
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
}
위 음식 Entity 클래스와 고객 Entity 클래스의 관계를 그림으로 표현하면 다음과 같습니다.
여기서는 음식 Entity 클래스가 외래키의 주인이되며, @JoinColumn 어노테이션으로 지정한 필드를 외래 키로 사용합니다.
음식 Entity에서만 고객 Entity를 참조할 수 있습니다. 이러한 관계를 단방향 관계라고 부릅니다. 단방향 관계에서는 고객 Entity가 음식 Entity를 참조할 수 없기 때문에, 고객 정보에서 음식 정보를 직접 조회할 수 없습니다.
정리하자면,
- 양방향 관계
- 두 Entity가 서로를 참조할 수 있는 관계입니다.
- 즉, 한 Entity가 다른 Entity를 참조하고, 반대로 다른 Entity도 첫 번째 Entity를 참조할 수 있는 관계입니다.
- 단방향 관계
- 한 Entity가 다른 Entity를 참조하지만, 반대쪽 Entity는
첫 번째 Entity를 참조하지 않는 관계입니다.
- 한 Entity가 다른 Entity를 참조하지만, 반대쪽 Entity는
'Framework > JPA' 카테고리의 다른 글
[JPA] 프록시(proxy)객체란 무엇일까❓ (1) | 2024.09.15 |
---|---|
[JPA] Spring Data JPA의 페이징과 정렬을 쉽게 구현하는 방법: Pageable과 PageRequest (0) | 2024.09.02 |
[JPA] JPA에서 낙관적 락(Optimistic Locking)을 통한 동시성 제어하기 (@Version) (0) | 2024.08.22 |
[JPA] 비관적 락(Pessimistic Lock)을 통한 동시성 제어 및 업데이트 손실(Lost Update)확인하기 (0) | 2024.08.21 |
[JPA] @Lock 어노테이션이란 무엇일까❓: 다양한 LockModeType 잠금 모드 (0) | 2024.08.21 |