π[Spring] JPA μ°κ΄κ΄κ³μ λν μΆκ°μ μΈ κΈ°λ₯λ€μλ 무μμ΄ μμκΉμ? - N:M κ΄κ³
- JPAμμ N:M κ΄κ³λ λ μν°ν°κ° λ€λλ€(Many-to-Many)λ‘ μ°κ²°λ κ΄κ³λ₯Ό μλ―Έν©λλ€.
- μλ₯Ό λ€μ΄, νμ(Student)κ³Ό κ°μ(Course) κ΄κ³μμ νλμ νμμ΄ μ¬λ¬ κ°μλ₯Ό μκ°ν μ μκ³ , λμμ νλμ κ°μμ μ¬λ¬ νμμ΄ μκ°ν μ μλ κ²½μ°μ N:M κ΄κ³κ° μ±λ¦½λ©λλ€.
1οΈβ£ N:M κ΄κ³μ 맀ν λ°©μ.
- JPAμμλ
@ManyToMany
μ΄λ Έν μ΄μ μ μ¬μ©νμ¬ N:M κ΄κ³λ₯Ό 맀νν μ μμ΅λλ€.- N:M κ΄κ³μμλ μ°κ²° ν μ΄λΈ(Join Table)μ΄ νμνλ©°, JPAλ μ°κ²° ν μ΄λΈμ μλμΌλ‘ μμ±νκ±°λ κ°λ°μκ° μ§μ μ μν μ μμ΅λλ€.
2οΈβ£ N:M κ΄κ³μ κΈ°λ³Έ 맀ν.
- N:M κ΄κ³λ λ¨μν
@ManyToMany
μ΄λ Έν μ΄μ μ μ¬μ©νλ λ°©μκ³Ό, μ°κ²° ν μ΄λΈμ μν°ν°λ‘ λΆλ¦¬νμ¬ μ¬μ©νλ λ°©μ λ κ°μ§κ° μμ΅λλ€.
1οΈβ£ κΈ°λ³Έμ μΈ @ManyToMany
맀ν
@Entity
public class Student {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
@ManyToMany
@JoinTable(
name = "student_course", // μ°κ²° ν
μ΄λΈ μ΄λ¦
joinColumns = @JoinColumn(name = "student_id"), // νμ¬ μν°ν°(Student)μ μΈλ ν€
inverseJoinColumns = @JoinColumn(name = "course_id") // λ°λ μν°ν°(Course)μ μΈλ ν€
)
private List<Course> courses = new ArrayList<>();
}
@Entity
public class Course {
@Id
@GeneratedValue(strategy = GeneratioonType.IDENTITY)
private Long id;
private String title;
@ManyToMany(mappedBy = "course") // λ°λμͺ½ μν°ν°μμ μλ°©ν₯ κ΄κ³ μ€μ .
private List<Student> students = new ArrayList<>();
}
π μ€λͺ .
-
@ManyToMany
μ΄λ Έν μ΄μ μ μ¬μ©ν΄ Studentμ Course μν°ν° κ°μ N:M κ΄κ³λ₯Ό 맀νν©λλ€. -
@JoinTable
μ μ¬μ©νμ¬ μ°κ²° ν μ΄λΈ(student_course)μ μ§μ νκ³ , κ° μν°ν°μ μΈλ ν€λ₯Ό joinColumnsμ inverseJoinColumnsμΌλ‘ μ€μ ν©λλ€. - Studentμ Course κ°μ μλ°©ν₯ κ΄κ³λ‘ μ€μ λμμΌλ©°, mappedByλ₯Ό μ¬μ©ν΄ λ°λμͺ½μ 맀ν νλλ₯Ό μ§μ ν©λλ€.
3οΈβ£ μ°κ²° μν°ν°λ₯Ό μ¬μ©ν N:M 맀ν.
-
@ManyToMany
κ΄κ³λ κ°λ¨ν κ²½μ°μλ§ μ¬μ©νλ κ²μ΄ μ’μ΅λλ€.- κ΄κ³κ° 볡μ‘νκ±°λ μΆκ°μ μΈ μμ±μ΄ νμν κ²½μ° μ°κ²° ν
μ΄λΈμ λ³λμ μν°ν°λ‘ λΆλ¦¬νμ¬ N:1 λ° 1:N κ΄κ³λ‘ 맀ννλ λ°©μμ΄ μ νΈλ©λλ€.
- μλ₯Ό λ€μ΄, νμκ³Ό κ°μ μ¬μ΄μ νμ (Grade)κ³Ό κ°μ μμ±μ΄ νμνλ€λ©΄, μ°κ²° μν°ν°μΈ Enrollmentλ₯Ό μΆκ°ν©λλ€.
```java
@Entity
public class Student {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
- μλ₯Ό λ€μ΄, νμκ³Ό κ°μ μ¬μ΄μ νμ (Grade)κ³Ό κ°μ μμ±μ΄ νμνλ€λ©΄, μ°κ²° μν°ν°μΈ Enrollmentλ₯Ό μΆκ°ν©λλ€.
private String name;
@OneToMany(mappedBy = βstudentβ)
private Listenrollments = new ArrayList<>(); // getter, setter
} - κ΄κ³κ° 볡μ‘νκ±°λ μΆκ°μ μΈ μμ±μ΄ νμν κ²½μ° μ°κ²° ν
μ΄λΈμ λ³λμ μν°ν°λ‘ λΆλ¦¬νμ¬ N:1 λ° 1:N κ΄κ³λ‘ 맀ννλ λ°©μμ΄ μ νΈλ©λλ€.
@Entity
public class Course {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String title;
@OneToMany(mappedBy = "course")
private List<Enrollment> enrollments = new ArrayList<>();
// getter, setter }
@Entity
public class Enrollment {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String grade;
@ManyToOne
@JoinColumn(name = "student_id")
private Student student;
@ManyToOne
@JoinColumn(name = "course_id")
private Course course;
// getter, setter } ```
π μ€λͺ .
- Enrollment μν°ν°λ₯Ό μΆκ°νμ¬ Studentμ Course κ°μ μ°κ²°μ ννν©λλ€.
- μ΄μ Studentμ Courseλ Enrollmentμ N:1 κ΄κ³λ₯Ό κ°μ§λλ€.
- μ΄ λ°©μμ μ°κ²° μν°ν°μ μΆκ°μ μΈ νλ(μ: grade)λ₯Ό ν¬ν¨ν μ μμ΄ μ μ°ν©λλ€.
4οΈβ£ N:M κ΄κ³ μ¬μ© μ μ£Όμμ¬ν.
- μ§μ μ μΈ
@ManyToMany
κ΄κ³λ λ¨μν κ΄κ³μμλ§ μ¬μ©νλ©°, 볡μ‘ν λΉμ¦λμ€ μꡬμ¬νμ΄ μλ κ²½μ° μ°κ²° ν μ΄λΈμ μν°ν°λ‘ λ§λ€μ΄ μ²λ¦¬ν©λλ€. - N:M κ΄κ³λ μ‘°μΈ ν
μ΄λΈμ μ΄μ©νλ―λ‘, λ°μ΄ν°μ μμ΄ λ§μμ§λ©΄ μ±λ₯ μ νλ₯Ό μΌμΌν¬ μ μμ΅λλ€.
- μ§μ° λ‘λ©(Lazy Loading) μ€μ μ ν΅ν΄ μ±λ₯μ μ΅μ νν©λλ€.
- 볡μ‘ν κ΄κ³μμμ Cascade μ΅μ μ μ μ€νκ² μ€μ ν΄μΌ λΆνμν μ°κ΄ μν°ν°μ μ μ₯/μμ λ₯Ό λ°©μ§ν μ μμ΅λλ€.
5οΈβ£ μμ½.
- N:M κ΄κ³λ
@ManyToMany
μ΄λ Έν μ΄μ μΌλ‘ μ½κ² 맀νν μ μμ§λ§, μΆκ°μ μΈ μμ±μ΄ νμνκ±°λ κ΄κ³κ° 볡μ‘ν΄μ§λ©΄ μ°κ²° ν μ΄λΈμ λ³λ μν°ν°λ‘ λΆλ¦¬νμ¬ μ²λ¦¬νλ κ²μ΄ μ’μ΅λλ€.- μ°κ²° μν°ν°λ₯Ό λΆλ¦¬νλ©΄ μΆκ° μμ±μ ν¬ν¨ν μ μμΌλ©°, λ μ μ°ν λ°μ΄ν° λͺ¨λΈλ§μ΄ κ°λ₯ν©λλ€.