๋ค์ด๊ฐ๋ฉด์
๊ฐ์ธ์ ์ผ๋ก ๊ณต๋ถํ ๋ด์ฉ๊ณผ ์๊ฐํ ๋ด์ฉ์ ๋ด์ ์์ฑํ ํฌ์คํ
์
๋๋ค.
ํ๋ฆฐ ๋ด์ฉ์ด ์๋ค๋ฉด ๋๊ธ๋ก ๊ณต์ ํด์ฃผ์ธ์!
โ ๊ฐ๋ ์ฒดํฌ
- ๋ฐ์ดํฐ๋ฒ ์ด์ค์์๋ ์ธ๋ ํค๋ก ์ฐ๊ด ๊ด๊ณ๋ฅผ ๋ํ๋ด๊ณ , ๊ฐ์ฒด ์งํฅ ํ๋ก๊ทธ๋๋ฐ์์๋ ๊ฐ์ฒด ๊ฐ์ ์ฐธ์กฐ๋ก ๋ํ๋ธ๋ค.
- JPA๋ฅผ ํ์ฉํ๋ค๋ ๊ฒ์ RDB ์ธ๋ ํค๋ฅผ ๊ฐ์ฒด ๊ฐ ์ฐ๊ด๊ด๊ณ๋ก ๋งคํํ๋ค๋ ๊ฒ.
- ์ํฐํฐ: ๋ฐ์ดํฐ๋ฒ ์ด์ค์ ํ
์ด๋ธ๊ณผ 1:1๋ก ๋์๋๋ ๊ฐ๋
์ด๋ค.
- ํ ์ธ์คํด์ค๋ DB ํ ์ด๋ธ์ ํ row์ ํด๋นํ๋ค.
- JPA์์๋ ์์์ฑ ์ปจํ ์คํธ์ ์ํด ๊ด๋ฆฌ๋๋ค.
- ์ํฐํฐ ํด๋์ค์๋ ๋ฐ๋์ PK ์๋ณ์๊ฐ ์๋ค. (@Id ์ด๋ ธํ ์ด์ ์ผ๋ก ์ ์ํ๋ค.)
- ๊ธฐ๋ณธ ์์ฑ์๋ฅผ ํ์๋ก ๊ฐ์ ธ์ผ ํ๋ค. (@NoArgsConstructor ์ด๋ ธํ ์ด์ ์ ์ฌ์ฉํ๋ค.)
- ์ํฐํฐ์ ํ๋๋ ๋ฐ์ดํฐ๋ฒ ์ด์ค ํ ์ด๋ธ์ ์ปฌ๋ผ๊ณผ ๋์๋๋ค.
- ์๋ฐฉํฅ: ๋ ๊ฐ์ฒด๊ฐ ์๋ก ์ฐธ์กฐ์ฉ ํ๋๋ฅผ ๊ฐ์ง๊ณ ์๋ค.
- A → B, B → A ๋ ๋ค ์ฐธ์กฐ ๊ฐ๋ฅ
- ๋จ๋ฐฉํฅ: ๋ ๊ฐ์ฒด ์ฌ์ด์ ํ๋์ ๊ฐ์ฒด๋ง ์ฐธ์กฐ์ฉ ํ๋๋ฅผ ๊ฐ๊ณ ์ฐธ์กฐํ๋ค.
- A → B๋ ๊ฐ๋ฅํ์ง๋ง, B → A๋ ๋ถ๊ฐ๋ฅ
- DB ๊ตฌ์กฐ์ ๋จ๋ฐฉํฅ์ด๋ฉด ๋ฐ๋์ JPA Entity๋ ๋จ๋ฐฉํฅ์ผ๋ก ๊ตฌํํ๋๊ฐ?
- No
- DB ํ ์ด๋ธ์์๋ ํ ์ด๋ธ ์ฌ์ด์ ์ฐ๊ด๊ด๊ณ๋ฅผ FK๋ก ๋งบ์ ์ ์๊ณ ๋ฐฉํฅ ์๊ด์์ด ์กฐํ๊ฐ ๊ฐ๋ฅํ๋ค.
- JPA์์๋ ์๋ ์ํฐํฐ๋ฅผ ์ฐธ์กฐํ๊ณ ์์ด์ผ๋ง ์๋ ์ํฐํฐ๋ฅผ ์กฐํํ ์ ์๋ค. "๋น์ฆ๋์ค ๋ก์ง์ ๋ฐ๋ ๋ฐฉํฅ์ ์กฐํ๋ ํ์ํ ๋"์ฐ๊ด๋ ๋ฐ์ดํฐ๋ฅผ ๋ ์ฝ๊ฒ ์กฐํํ ์ ์๋๋ก ํ๊ธฐ ์ํด ์๋ฐฉํฅ์ผ๋ก ์ค์ ํ ์ ์๋ค.
- ์ฐ๊ด๊ด๊ณ์ ์ฃผ์ธ: ๋ ๊ฐ์ฒด์ ๊ด๊ณ ์ค ์ ์ด์ ๊ถํ(๋ฐ์ดํฐ ์กฐํ, ์ ์ฅ, ์์ , ์ญ์ )์ ๊ฐ์ง๋ ๊ฐ์ฒด
- FK๋ฅผ ๊ด๋ฆฌํ๋(FK๋ฅผ ํ๋๋ก ๊ฐ์ง๊ณ ์๋) ์ํฐํฐ๋ฅผ ์ฐ๊ด๊ด๊ณ์ ์ฃผ์ธ์ผ๋ก ๋ณธ๋ค.
๐ฏ 1:1 ๊ด๊ณ(One-to-One)
ํ ๊ฐ์ ์ํฐํฐ๊ฐ ๋ค๋ฅธ ํ๋์ ์ํฐํฐ์ ๋จ ํ๋์ ๊ด๊ฒ๋ฅผ ๊ฐ์ง๋ ๊ฒฝ์ฐ์ด๋ค.
์ฆ, ์ํฐํฐ A์ ์ธ์คํด์ค ํ๋๋ ์ํฐํฐ B์ ์ธ์คํด์ค ํ๋์ ๋์๋๋ค.
๋จ๋ฐฉํฅ์ธ ๊ฒฝ์ฐ์ ์๋ฐฉํฅ์ธ ๊ฒฝ์ฐ๋ฅผ ๋๋์ด ์๊ฐํด๋ณด๊ฒ ๋ค.
๋จ๋ฐฉํฅ
DB์์ ๋ชจ๋ ์ฌ์ฉ์๋ users ํ ์ด๋ธ์, ์๋น์ค์ ๋ฑ๋ก๋ ๋ชจ๋ ์ฌ์ง์ photos ํ ์ด๋ธ์ ์ ์ฅ๋์ด ์๋ค๊ณ ํ์. photos ํ ์ด๋ธ์๋ ์ฌ์ฉ์์ ํ๋กํ ์ด๋ฏธ์ง๋ ํฌํจ๋์ด ์๋ค.
์ฌ์ฉ์(User) 1๋ช
์ 1๊ฐ์ ํ๋กํ ์ด๋ฏธ์ง(Photo)์ ๊ฐ์ง ์ ์๋ค.
1๊ฐ์ ํ๋กํ ์ด๋ฏธ์ง๋ ์ฌ์ฉ์ 1๋ช
์๊ฒ ์ํ๋ค.
๋จ๋ฐฉํฅ์ธ ์ด์
์ผ๋ฐ์ ์ธ ์๋น์ค์์ ํ๋กํ ์ฌ์ง์ ์ฌ์ฉ์ ์ ๋ณด๋ฅผ ๋ถ๋ฌ์ฌ ๋๋ง ๊ฐ์ ธ์จ๋ค.
ํ๋กํ ์ฌ์ง์ด ๋ฐ๋ก ๋
๋ฆฝ์ ์ผ๋ก ํ์ํ ๊ฒฝ์ฐ, ํ๋กํ ์ฌ์ง์ด ์ฌ์ฉ์ ์ ๋ณด๊น์ง ๊ฐ์ ธ์์ผ ํ๋ ๊ฒฝ์ฐ๋ ์๋ค.
User๋ ์์ ์ด ๊ฐ์ง Photo๋ฅผ ์์์ผ ํ์ง๋ง
Photo๋ ์์ ์ ๊ฐ์ง User๋ฅผ ๋ชฐ๋ผ๋ ๋๋ค.
์ด๋ฌํ ์ด์ ๋ก User -> Photo ๋จ๋ฐฉํฅ์ผ๋ก ์ค์ ํ๋ค.
JPA์์ ๋จ๋ฐฉํฅ, ์๋ฐฉํฅ์ ์ ํ ๋๋ "๊ฐ์ฒด๊ฐ ์๋ก๋ฅผ ์์์ผ ํ๋๊ฐ?"๋ฅผ ์๊ฐํด๋ณด๋ฉด ๋๋ค.
์ด๋ ํ ์ด๋ธ์ด FK๋ฅผ ๊ฐ์ ธ์ผ ํ ๊น?
์ผ๋ฐ์ ์ผ๋ก FK์ ์ฃผ์ธ์ 1:N์ธ ๊ด๊ณ์์๋ N์ธ ์ชฝ์ ์ํ์ง๋ง,
1:1์ธ ๊ด๊ณ์์๋ ์ด๋ ์ชฝ์ด FK๋ฅผ ๊ด๋ฆฌํ ์ง,
์ฆ ์ด๋ ์ํฐํฐ๊ฐ ์ฐ๊ด ๊ด๊ณ์ ์ฃผ์ธ์ด ๋ ์ง ์ ํด์ผ ํ๋ค.
๋ค์ํ ์ด์ ๊ฐ ์๊ฒ ์ง๋ง
๋ค์๊ณผ ๊ฐ์ ์ด์ ๋ก ์ ํ๋ค.
1. ์๋ฏธ์ ๊ด๊ณ: ๋๊ฐ ์ด ๊ด๊ณ๋ฅผ ๊ด๋ฆฌํ ์ ์๋?
๊ฐ์ฅ ๋จผ์ ๋ ์ค๋ฅด๋ ์ด์ ๋ค.
User์ Photo์ ์๋ฏธ๋ ์ฌ์ฉ์์ ์ฌ์ฉ์์ ํ๋กํ ์ด๋ฏธ์ง์ด๋ค.
์ฌ์ฉ์๊ฐ ์ฌ์ฉ์์ ํ๋กํ ์ด๋ฏธ์ง์ ํฌํจ๋๊ธฐ ๋ณด๋ค๋, ํ๋กํ ์ด๋ฏธ์ง๊ฐ ์ฌ์ฉ์ ์ ๋ณด์ ํฌํจ๋๋ ์ชฝ์ด ์ณ๋ค.
์ฌ์ง์ด "์์๋ ์ฌ์ฉ์"๋ฅผ ๋ฑ๋กํ๊ณ ๊ด๋ฆฌํ๋ ๊ฒ๋ณด๋ค
์ฌ์ฉ์๊ฐ ํ๋กํ ์ฌ์ง์ ์ค์ ํ๊ฑฐ๋ ๋ณ๊ฒฝํ๋ ๊ฐ๋
์ด ์์ฐ์ค๋ฝ๋ค.
User๊ฐ Photo ๊ฐ์ฒด๋ฅผ ์์ ํ๊ณ , Photo ๊ฐ์ฒด๋ ํน์ User ๊ฐ์ฒด์ ์ข
์๋๋ค.
๐ก ์ฃผ์ฒด๊ฐ ๋๋ ์ํฐํฐ(์์ ์)๊ฐ ์ํฐํฐ๋ฅผ ๊ด๋ฆฌํ๋ ๊ฒ ์ผ๋ฐ์ -> ์์ ์๊ฐ FK๋ฅผ ๊ฐ์ง๋ค.
์ด ๊ฒฝ์ฐ์๋ User๊ฐ Photo์ id ์ปฌ๋ผ๊ณผ ๋งคํ๋๋ photo_id๋ฅผ ๊ฐ์ง๋ ๊ฒ ๋ง๋ค.
2. ์กฐํ ์ฑ๋ฅ ๊ณ ๋ ค
๋๋ถ๋ถ์ ๊ฒฝ์ฐ User ์ ๋ณด๋ฅผ ๊ฐ์ ธ์ฌ ๋ ํ๋กํ ์ฌ์ง์ ํจ๊ป ์กฐํํ ๊ฒ์ด๋ค.
์ด ์ํฉ์ด ํ๋กํ ์ฌ์ง์ ์กฐํํ ๋ ์ ์ ์ ๋ณด๋ฅผ ๊ฐ์ ธ์ค๋ ๊ฐ๋
๋ณด๋ค ์ต์ํ๋ค.
์ด๋ User์ FK๊ฐ ์๋ค๋ฉด ์ฆ์ Photo์ joinํด์ User ์ ๋ณด์ ํน์ Photo๋ฅผ ์กฐํํ๊ธฐ ํธํ๋ค.
๋ง์ฝ Photo์ FK๋ฅผ ๋๋ค๋ฉด, ๋จผ์ User ์ ๋ณด๋ฅผ ๊ฐ์ ธ์จ ํ user_id๋ฅผ ๊ฐ์ง Photo๋ฅผ ํ
์ด๋ธ ์ ์ฒด์์ ์กฐํํด์ผ ํ๋ค.
๐ ์ฃผ์ ํค์๋
- @OneToOne: 1:1 ๊ด๊ณ๋ฅผ ๋ช ์ํ๋ ์ด๋ ธํ ์ด์ ์ด๋ค.
- @JoinColumn: ์ฐ๊ด ๊ด๊ณ์ ์ฃผ์ธ์ด FK๋ฅผ ๋ช
์์ ์ผ๋ก ์ง์ ํ๋ ์ด๋
ธํ
์ด์
์ด๋ค.
- @JoinColumn(name = food_id) ์ด๋ฐ ์์ผ๋ก ์ปฌ๋ผ๋ช ์ ์ํ๋๋๋ก ์ง์ ํ๊ณ ์ถ์ ๋ ์ฌ์ฉํ๋ค.
- FK๋ฅผ ๊ฐ์ง๋ ๊ฐ์ฒด์์๋ง ์ฌ์ฉํ๋ค.
์ฝ๋
User Entity
@Entity
@Table(name="users")
@NoargsConstructor // Entity๋ฅผ ๋ง๋ค๊ธฐ ์ํด์๋ ๊ธฐ๋ณธ ์์ฑ์๊ฐ ํ์์ ์
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@OneToOne
@JoinColumn(name = "photo_id")
private Photo photo;
...
}
Photo Entity
@Entity
@Table(name="photos")
@NoargsConstructor
public class Photo {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String fileName;
private String contentType;
private Long size;
...
}
์๋ฐฉํฅ
๊ทธ๋ ๋ค๋ฉด ์ํฐํฐ๊ฐ ์๋ก 1:1๋ก ๋์ํ๊ณ , ์๋ก์ ์กด์ฌ๋ฅผ ์์์ผ ํ๋ ์์๋ ๋ฌด์์ด ์์๊น?
์๋น์์ 1๋ช ์ ๊ณ ๊ฐ์ 1๊ฐ์ ์์๋ง ์ฃผ๋ฌธํ ์ ์๋ค๊ณ ํด๋ณด์.
๊ณ ๊ฐ์ ๋์ค์ ๊ฒฐ์ ํ๋ ค๋ฉด ์์ ์ด ์ฃผ๋ฌธํ ์์์ ์์์ผ ํ๋ค.
์์๋ ์จ์ดํฐ๊ฐ ์๋นํ๋ ค๋ฉด ์์ ์ ์ฃผ๋ฌธํ ๊ณ ๊ฐ์ ์์์ผ ํ๋ค.
๋ฐ๋ผ์ ๊ณ ๊ฐ - ์์์ ์๋ก ๊ฐ์ฒด๋ฅผ ์๊ณ ์์ด์ผ ํ๋ ๊ด๊ณ์ด๋ฏ๋ก ์๋ฐฉํฅ์ด๋ค.
์ด๋๋ ์๋ก์ ์ํฐํฐ๋ฅผ ์ฐธ์กฐํ๊ณ ์์ด์ผ ํ๋ค.
๊ณ ๊ฐ์ Customer, ์์์ Food๋ผ๊ณ ํ์.
์ฐธ๊ณ ๋ก DB์์๋ ๋จ๋ฐฉํฅ ๊ด๊ณ๋ก ์ค๊ณ๊ฐ ๊ฐ๋ฅํ์ง๋ง
์กฐํ(์์ ์๋น) ๊ธฐ๋ฅ์ ํธํ๊ฒ ํ๊ธฐ ์ํด JPA์์ ์๋ฐฉํฅ ๊ด๊ณ๋ก ์ค์ ํ๋ ๊ฒ์ด๋ค.
์ด ๊ด๊ณ์ ์ฃผ์ธ์ ๋๊ตฌ์ผ๊น?
์๋ฏธ์ ์ผ๋ก ๋ดค์ ๋, ๊ณ ๊ฐ์ด ํน์ ์์์ ์ฃผ๋ฌธํ๊ฑฐ๋ ์ ํํ๋ "๊ด๋ฆฌ ์ฃผ์ฒด"์ด๋ฏ๋ก Customer๊ฐ ์ฃผ์ธ์ด๋ค. Customer ํด๋์ค๊ฐ FK๋ฅผ ๊ฐ์ ธ์ผ ํ๋ค.
๐ ์ฃผ์ ํค์๋
- mappedBy: ์๋ฐฉํฅ ๊ด๊ณ์์ ์ด ์ธ๋ ํค๋ฅผ ๊ด๋ฆฌํ๋ ์ํฐํฐ(์ฃผ์ธ)๊ฐ ๋๊ตฌ์ธ์ง ์ง์ ํ ๋ ์ฌ์ฉํ๋ ์ต์
์ด๋ค.
- ์ฃผ์ธ์ด ์๋ ์ชฝ์์ ์ค์ ํ๋ค.
- ์ฐ๊ด ๊ด๊ณ๋ฅผ ๊ด๋ฆฌํ๋ ํ๋ ์ด๋ฆ์ ์ง์ ํด์ผ ํ๋ค.
- DB ํ ์ด๋ธ ๋ด FK ์ปฌ๋ผ ์ด๋ฆ์ด ์๋๋ผ ์ฃผ์ธ ์ํฐํฐ ํด๋์ค์ ์ฐธ์กฐ ํ๋ ์ด๋ฆ์ด๋ค!
์ฝ๋
Customer Entity
@Entity
@Table(name="customers")
@NoargsConstructor
public class Customer {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private int seatIndex;
...
// ๊ณ ๊ฐ์ด ์ํค๋ 1๊ฐ์ ๋ฉ๋ด
@OneToOne
@JoinColumn(name="food_id")
private Food food;
}
Food Entity
์ฃผ์ธ์ธ Customer์์ Food๋ฅผ ์ฐธ์กฐํ๋ ํ๋๋ food์ด๋ค.
๋ฐ๋ผ์ Food ์ํฐํฐ์์ mappedBy ์ต์
์ผ๋ก Customer์์ food ํ๋๊ฐ ์ฐ๊ด๊ด๊ณ์ ์ฃผ์ธ์์ ๋ช
์ํ๋ค.
@Entity
@Table(name="food")
@NoargsConstructor
public class Food {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private int price;
...
// ๊ณ ๊ฐ์ด ์ํค๋ 1๊ฐ์ ๋ฉ๋ด
@OneToOne(mappedBy = "food")
private Customer customer;
}
๐ฏ 1:N/N:1 ๊ด๊ณ(One-to-Many/Many-to-One)
์ํฐํฐ A์ 1๊ฐ์ ์ธ์คํด์ค๊ฐ ์ํฐํฐ B์ N๊ฐ์ ์ธ์คํด์ค์ ๋์ํ ๋ A์ B์ ๊ด๊ณ๋ฅผ 1:N์ด๋ผ๊ณ ํ๋ค.
1๋ช
์ ์ฌ์ฉ์๊ฐ ์ฌ๋ฌ ๊ฐ์ ๊ฒ์๊ธ์ ์์ฑํ ์ ์๋ค.
์ฌ์ฉ์๋ฅผ User, ๊ฒ์๊ธ์ Post๋ผ๊ณ ํด๋ณด์.
DB ์์์์ ๊ตฌ์กฐ๋ ์์ ๊ฐ๋ค.
Post์์ FK๋ฅผ ๊ฐ์ง๋ฏ๋ก ์ฐ๊ด๊ด๊ณ์ ์ฃผ์ธ์ Post์ด๋ค.
๋จ๋ฐฉํฅ
Post๋ ์์ ์ ์์ฑํ User ์ ๋ณด๋ฅผ ์์์ผ ํ์ง๋ง
User๋ ์์ ์ด ์์ฑํ Post ์ ๋ณด๊ฐ ํ์์ ์ธ ๊ฑด ์๋ ๋๋ ๋จ๋ฐฉํฅ์ผ๋ก ๊ฐ๋ฅํ๋ค.
๐ ์ฃผ์ ํค์๋
- @ManyToOne: N:1 ๊ด๊ณ๋ฅผ ๋ํ๋ธ๋ค.
- ์ฌ๋ฌ ๊ฐ์ Post๊ฐ ํ๋์ User๋ฅผ ๊ฐ๋ฆฌํค๋ ์ํฉ์ด๋ค.
- FK๋ N์ชฝ์์ ๊ด๋ฆฌ, ์ฆ Post๊ฐ ์ฃผ์ธ์ด๋ค.
- Many์ ํด๋นํ๋ Post์์ ์ฌ์ฉํ๋ค.
์ฝ๋
User Entity
@Entity
@Table(name="users")
@NoargsConstructor
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String email;
...
}
Post Entity
@Entity
@Table(name="posts")
@NoargsConstructor
public class Post {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String title;
private String content;
...
@ManyToOne
@JoinColumn(name="author_id")
private User user;
}
์๋ฐฉํฅ
๋ง์ฝ Post๊ฐ ์์ฑ์ User๋ฅผ ์๊ณ ์์ด์ผ ํ๊ณ ,
User๋ ์์ ์ด ์ด Post๋ฅผ ์์์ผ ํ ๋๋ ์๋ฐฉํฅ ๊ด๊ณ๋ก ์ค๊ณํ๋ค.
์ผ๋ฐ์ ์ธ ์๋น์ค์์๋ ์ด ๊ฒฝ์ฐ๊ฐ ๋ง์ง ์์๊น?
๐ ์ฃผ์ ํค์๋
- @OneToMany: 1:N ๊ด๊ณ๋ฅผ ๋ํ๋ด๋ ์ด๋
ธํ
์ด์
์ด๋ค.
- 1๊ฐ์ ์ํฐํฐ๊ฐ ์ฌ๋ฌ ๊ฐ์ ์ํฐํฐ๋ฅผ ๊ฐ์ง๋ค๋ ์๋ฏธ์ด๋ค.
- ํ ๋ช ์ User๋ ์ฌ๋ฌ ๊ฐ์ Post๋ฅผ ๊ฐ์ง ์ ์๋ค.
- 1์ชฝ์ ์ํ๋ ์ํฐํฐ์์ ์ฌ์ฉํ๋ค.
- ๋ฐ๋์ mappedBy ์ต์ ์ผ๋ก ์ฃผ์ธ(@ManyToOne์ ๊ฐ์ง ์ํฐํฐ)์ ๋ช ์ํด์ผ ํ๋ค.
์ฝ๋
User Entity
1:N์ธ ๊ด๊ณ๋ N์ธ ๊ฐ์ฒด๋ฅผ List, ๋ฐฐ์ด ๊ฐ์ ๊ฐ์ผ๋ก ์ ์ฅํ๋ค.
@Entity
@Table(name="users")
@NoargsConstructor
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String email;
...
@OneToMany(mappedBy="author")
List<Post> posts;
}
Post Entity
@Entity
@Table(name="posts")
@NoargsConstructor
public class Post {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String title;
private String content;
...
@ManyToOne
@JoinColumn(name="author_id")
private User author;
}
๐ฏ N:M ๊ด๊ณ(Many-to-Many)
์ํฐํฐ A์ N๊ฐ์ ์ธ์คํด์ค๊ฐ ์ํฐํฐ B์ M๊ฐ์ ์ธ์คํด์ค์ ๋์ํ ๋ A์ B์ ๊ด๊ณ๋ฅผ N:M์ด๋ผ๊ณ ํ๋ค.
๊ฐ์ฅ ๋ง์ด ๋๋ ์์๋ ๋ํ๊ต์์ "ํ์๊ณผ ๊ฐ์"์ ๊ด๊ณ์ด๋ค.
ํ ๋ช
์ ํ์์ ์ฌ๋ฌ ๊ฐ์ ์์
์ ์๊ฐํ ์ ์๋ค. → N:1 ๊ด๊ณ (Student → Course)
ํ ๊ฐ์ ์์
์๋ ์ฌ๋ฌ ๋ช
์ ํ์์ด ๋ฑ๋ก๋ ์ ์๋ค. → 1:N ๊ด๊ณ (Course → Student)
๋ฐ๋ผ์, N:M ๊ด๊ณ๋ฅผ ํ์ฑํ๋ค.
์ด๋๋ ๋ ๊ฐ์ฒด ๊ฐ์ ์ฐ๊ฒฐ ํ
์ด๋ธ์ด ๋ฐ๋ก ํ์ํ๋ค.
N:M ๊ด๊ณ๋ ์ง์ ํํํ ์ ์๊ธฐ ๋๋ฌธ์ด๋ค.
์ด ํ
์ด๋ธ์ ์ค์ ๋ก ์ ์๋ฏธํ ๊ฐ์ฒด๋ฅผ ์ ์ฅํ๋ ํ
์ด๋ธ์ด ์๋๋ผ
ํ์๊ณผ ๊ฐ์์ ๊ด๊ณ๋ง์ ์ ์ฅํ๋ ์ญํ ์ ํ๋ค.
์ด๋ ์ฐ๊ด ๊ด๊ณ์ ์ฃผ์ธ์ ๋ช
ํํ ๋งํ๊ธฐ๋ ์กฐ๊ธ ์ด๋ ต๋ค.
students, courses ํ
์ด๋ธ ๋ชจ๋ ์๋ก๋ฅผ FK๋ก ๊ฐ๊ณ ์์ง ์๊ธฐ ๋๋ฌธ์ด๋ค.
๊ทธ๋ฅ ๋ ์ค ํธํ ๊ฒ์ ์ฃผ์ธ์ผ๋ก ํ๋ค.
ํ์ ๊ธฐ์ ํ @JoinTable์ ์ด ์ชฝ์ ์ฃผ์ธ์ด๋ผ๊ณ ๋ณธ๋ค.
์ค๋ฌด์์๋ ๋ค๋๋ค ๊ด๊ณ๋ฅผ ์ง์ํ๋ฏ๋ก ์ด ์ ๋๋ง ํด๋ ์ถฉ๋ถํ ๋ฏ ํ๋ค.
์ฐธ๊ณ : ์ธํ๋ฐ QnA
๐ ์ฃผ์ ํค์๋
- @ManyToMany: ์ด๋
ธํ
์ด์
์ ์ฌ์ฉํ๋ฉด JPA๊ฐ ์๋์ผ๋ก ์ฐ๊ฒฐ ํ
์ด๋ธ์ ์์ฑํด์ค๋ค.
- ์์ชฝ ์ํฐํฐ ๋ชจ๋์ ์ฌ์ฉํ๋ค.
- @JoinTable: ๋ช
์์ ์ผ๋ก ์ฐ๊ฒฐ ํ
์ด๋ธ์ ์ค์ ํ๊ณ ์ถ์ ๋ ์ฌ์ฉํ๋ค.
- ์ฃผ์ธ ์ํฐํฐ, ํ ์ํฐํฐ์์๋ง ๋ช ์ํ๋ฉด ๋๋ค.
- name: ์ฐ๊ฒฐ ํ ์ด๋ธ ์ด๋ฆ
- joinColumns: ํ์ฌ ์ํฐํฐ์์ ์๋ ๊ฐ ์ค ์ฐ๊ฒฐ ํ
์ด๋ธ์์ FK๋ก ์ธ ์ปฌ๋ผ๋ช
๋ค
- Student ์ํฐํฐ์์ ์ฐ๊ฒฐ ํ ์ด๋ธ์ ๋ง๋ ๋ค๋ฉด Student์ id ํ๋๋ฅผ ์ฐ๊ฒฐ ํ ์ด๋ธ์ FK๋ก ์ด๋ค.
- inverseJoinColumns: ๋ฐ๋ ์ํฐํฐ์์ ์๋ ๊ฐ ์ค ์ฐ๊ฒฐ ํ
์ด๋ธ์์ FK๋ก ์ธ ์ปฌ๋ผ๋ช
๋ค
- Student ์ํฐํฐ์์ ์ฐ๊ฒฐ ํ ์ด๋ธ์ ๋ง๋ ๋ค๋ฉด Course์ id ํ๋๋ฅผ ์ฐ๊ฒฐ ํ ์ด๋ธ์ FK๋ก ์ด๋ค.
- mappedBy: @JoinTable์ ์ฐ์ง ์์ ๋ค๋ฅธ ํ ์ชฝ์์๋ mappedBy ์ต์
์ ์ฌ์ฉํ์ฌ ์ฐ๊ด ๊ด๊ณ์ ์ฃผ์ธ/๋น์ฃผ์ธ์ ๊ตฌ๋ถํ๋ค.
- Student๊ฐ ์ฃผ์ธ, Course๊ฐ ๋น์ฃผ์ธ์ด๋ฏ๋ก Course์์ ์ฌ์ฉํ๋ค.
์ฝ๋
Student Entity
@Entity
@Table(name="students")
@NoargsConstructor
public class Student {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String department;
private String email;
...
@ManyToMany // N:M ๊ด๊ณ ๋ช
์
// ์ฐ๊ฒฐ ํ
์ด๋ธ ์ง์
@JoinTable(
name = "student_course",
joinColumns = @JoinColumn(name = "student_id"),
inverseJoinColumns = @JoinColumn(name = "course_id")
)
private List<Course> courses;
}
Course Entity
@Entity
@Table(name="courses")
@NoargsConstructor
public class Course {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private String department;
private String semester;
private String professor;
...
@ManyToMany(mappedBy="courses") // N:M ๊ด๊ณ ๋ช
์
private List<Student> students;
}
์ฐธ๊ณ ์๋ฃ
[JPA] ์ฐ๊ด๊ด๊ณ ๋งคํ ์ฃผ์ธ์ ๋ํด์ (mappedBy)
TIL-15 JPA Entity ์ฐ๊ด๊ด๊ณ 1๋1 ๊ด๊ณ
+๊ธฐํ ์์ ์๋ฃ