TIL Spring #3-3
Entity μ°κ΄κ΄κ³
- 1:1
- N:1
- 1:N
- N:M
μ€μ λ‘ ν μ΄λΈμ λ± νκ°λ§ μ¬μ©νλ κ²½μ°λ κ±°μ μλ€.
DB tableμ μ°κ΄κ΄κ³ Entity κ°μ²΄μ μ°κ΄κ΄κ³ μ°¨μ΄κ° μμκΉ? μλ€λ©΄ μ΄λ»κ² λ€λ₯ΌκΉ?
μλ₯Ό λ€μ΄, κ³ κ°μ΄ μμμ μ£Όλ¬Ένλ νλ‘κ·Έλ¨μ μμ±νλ€κ³ κ°μ ν΄λ³΄μ.
κ·Έλ λ€λ©΄ λΉμ°ν μ£Όλ¬Ένλ κ³ κ° ν μ΄λΈ νλ, μμ ν μ΄λΈ νλ μ΄ λκ°λ κΈ°λ³Έμ μΌλ‘ νμν κ²μ΄λ€.
κ·Έλ°λ° κ³ κ°μ΄ μμμ μ£Όλ¬Ένμ λ ν΄λΉ 주문건μ λν건 μ μ ? μμ? μ΄λ ν μ΄λΈμ λͺ μν΄μ€μΌν κΉ?
μ΄λ₯Ό μ μ λ μμ ν μ΄λΈμ λ£κ² λλ©΄ λλ€ μ¬μ©μ, μμ λ΄μ©μ΄ μ€λ³΅λλ μ΄μκ° λ°μνλ€.
μ΄λ κ² user_id 컬λΌμ 1λ² 2λ² μ μ κ° μ£Όλ¬Ένλ€. λΌλ νν λ°©μλ μλ κΉ?
μΌλ¨ RDBMS μμμλ λΆκ°λ₯νλ€. λΌκ³ μ΄ν΄νμ.
- 2 row λ‘ ννμ΄ λκΈ΄ νλ€! κ·Έλ¬λ μμμ μ΄λ¦μ΄ λΆνμνκ² μ€λ³΅λλ€!
<ν΄κ²°λ°©μ>
μ£Όλ¬Έ μ 보λ₯Ό λ£μ μ€κ° ν μ΄λΈμ λ°λ‘ λ§λ€μ!
μ 리ν΄λ³΄λ©΄ κ³ κ°λ μμ μ¬λ¬κ°λ₯Ό μ£Όλ¬Έν μ μκ³ μμ λν μ¬λ¬ κ³ κ°μκ² μ£Όλ¬Έλ μ μλ€. -> N:M κ΄κ³!
N:M κ΄κ³μΈ ν μ΄λΈμ μ°κ΄κ΄κ³λ₯Ό ν΄κ²°νκΈ° μν΄ μ€κ°ν μ΄λΈμ μ¬μ©ν μ μλ€.
<ν μ΄λΈμ λ°©ν₯?>
- DB ν μ΄λΈ κ° λ°©ν₯μ΄ μμκΉ?
- ν μ΄λΈμμλ μνλ μ 보λ₯Ό κ³ κ°, μμ μ΄λ κΈ°μ€μΌλ‘ νλ JOINμ μ¬μ©ν΄ μ‘°νν μ μμΌλ©°
λμ κ²°κ³Όλ μ€μ°¨μμ΄ λκ°λ€. -> λ°©ν₯μ κ°λ μμ
κ·Έλ λ€λ©΄ JPA Entityμμλ?
κ²°λ‘ μ μΌλ‘ Entityμμλ κ°λ₯νλ€. μ΄κ²μ΄ DBμ μ μ©λλ κ²μ μλμ§λ§
κ°μ²΄ ννμμλ μ°Έμ‘°λ₯Ό λ¨λ°©ν₯ μλ°©ν₯ λκ°μ§ λͺ¨λ λ€ κ°λ₯νλ€.
μ°Έκ³ ) μΈλ ν€ μ£ΌμΈλ§μ΄ μΈλ ν€λ₯Ό λ±λ‘, μμ , μμ ν μ μμΌλ©° μ£ΌμΈμ΄ μλ μͺ½μ μ€μ§ μ½κΈ°λ§ κ°λ₯νλ€.
@JoinColumn μ λν μ΄μ μΌλ‘ μ£ΌμΈ μ§μ
μμ λ₯Ό ν΅ν΄ ν΄λΉ caseλ³λ‘ νμΈν΄λ³΄μ. (μΌκ΄μ±μ μν΄ μμ Entitydμλ§ μ£ΌμΈ κΆνμ λΆμ¬νλ€.)
<1:1>
# 1:1 κ΄κ³ - λ¨λ°©ν₯
@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;
}
- κ°μ₯ κ°λ¨νλ€ μ£ΌμΈμΈ μν°ν°μ 1:1 κ΄κ³λ₯Ό λνλ΄λ @OneToOne μ λν μ΄μ μμ±, μΈλν€μ μ£ΌμΈμμ μλ €μ£Όλ @JoinColumn μ λν μ΄μ μμ±ν΄μ£Όλ©΄ λλ€.
# 1:1 κ΄κ³ - μλ°©ν₯
-μΈλν€μ μ£ΌμΈ
@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 Food food;
}
- μλ°©ν₯ κ΄κ³μμλ μ£ΌμΈμ΄ μλ μν°ν°μ νλ μ€μ ν κ²μ΄ μλλ° λ°λ‘ mappedBy μ΅μ μ΄λ€.
μΈλν€μ μ£ΌμΈμ μ§μ ν΄μ€λ ν΄λΉ μ΅μ μ μ¬μ©νλ©° μ§κΈ 보μ΄λ "user"λΌλ μμ±κ°μ User ν΄λμ€λ₯Ό μλ―Ένλ κ²μ΄ μλ
μΈλν€μ μ£ΌμΈμΈ Food μν°ν°μ νλλͺ μ μλ―Ένλ€. (ν·κ°λ¦¬μ§ μκ² μ£Όμ)
- λν΄νΈ μ΅μ μ μ©λκΈ° λλ¬Έμ μλ΅μ΄ κ°λ₯νκΈ΄νλ λͺ¨νΈν κ²½μ° JPAμμ μ€κ°ν μ΄λΈμ μμ±ν μλ μκΈ° λλ¬Έμ λ°λμ λͺ μν΄μ£Όλ κ²μ΄ μ’λ€.
<N:1>
# N:1 κ΄κ³ - λ¨λ°©ν₯
- μ΄λ 1:1 λ¨λ°©ν₯ κ²½μ°μ λ§μ°¬κ°μ§λ‘ μ£ΌμΈ μΈλν€ μͺ½μ μ λν μ΄μ λ§ μ μμ±ν΄μ£Όλ©΄ λλ€.
λμ OneToOne λμ @ManyToOne μ λν μ΄μ μ μ¬μ©νλ€.
# N:1 κ΄κ³ - μλ°©ν₯
- μ΄ κ²½μ°λ 1:1 μλ°©ν₯ κ²½μ°μ λΉμ·νλ€!
- λ€λ§, μΈλν€μ μ£ΌμΈμ΄ μλ ν΄λμ€μ @OneToMany λΌλ μ λν μ΄μ μμ± νμ.
@Entity
@Table(name = "food")
public class Food {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private double price;
@ManyToOne //N:1 κ΄κ³λ₯Ό λνλ΄λ μ λν
μ΄μ
@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;
@OneToMany(mappedBy = "user") //μΈλν€μ μ£ΌμΈμ μλ €μ€.
//User ν΄λμ€ μλκ³
//μΈλν€μ μ£ΌμΈμΈ Food ν΄λμ€μ νλμΈ userμ!
private List<Food> foodList = new ArrayList<>();
}
- νλ μμ λ κ²μ μλ°©ν₯ μ°Έμ‘°λ₯Ό μν΄ κ³ κ° μν°ν°μμ μλ° μ»¬λ μ μ μ¬μ©νμ¬ μμ μν°ν°λ₯Ό μ°Έμ‘°νλ€! (μμμ νλλ§ μ£Όλ¬Έν κ²μ μλκΈ°μ μ¬λ¬κ°λ₯Ό λ΄μμΌνλ€.)
<1:N>
@OneToMany μ λν μ΄μ μ¬μ©
μμμ λ§μ°¬κ°μ§λ‘ μΈλν€ μ£ΌμΈμ μμμΌλ‘ λμ.
κ·Έλ°λ° 1:N κ΄κ³μμ Nμ ν μ΄λΈμ΄ μΈλν€λ₯Ό κ°μ§ μ μκΈ° λλ¬Έμ μ€μ μΈλν€λ κ³ κ°μ λλ€.
-λ¨λ°©ν₯
@Entity
@Table(name = "food")
public class Food {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private double price;
@OneToMany
@JoinColumn(name = "food_id") // users ν
μ΄λΈμ food_id 컬λΌ
private List<User> userList = new ArrayList<>();
}
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
}
N κ΄κ³μΈ Userμ μ μ μΈλν€λ₯Ό 보κ΄νκ³ μμμμ κ΄λ¦¬νλ€. μ°½κ³ κ°μ λλ..
- μλ°©ν₯
ν΄λΉ κ΄κ³μμλ μΌλ°μ μΌλ‘ μλ°©ν₯ κ΄κ³κ° μ‘΄μ¬νμ§ μλλ€.
mappedBy μμ± λν μ 곡νμ§ μλλ€.
@JoinColumnμ insert/updateμ false κ°μ μ£Όμ΄ μλ°©ν₯μ²λΌ μ€μ ν μλ μλ€.
<N:M>
@ManyToMany μ λν μ΄μ μ¬μ©
κΈ μ머리μμ λ΄€λ κ²μ²λΌ ν΄λΉ κ΄κ³μμλ μ€κ°ν μ΄λΈμ λ§λ€μ΄ μ¬μ©νλ€. (orders)
- λ¨λ°©ν₯
@Entity
@Table(name = "food")
public class Food {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
private double price;
@ManyToMany
@JoinTable(name = "orders")// μ€κ° ν
μ΄λΈ μμ±
joinColumns = @JoinColumn(name = "food_id"), // νμ¬ μμΉμΈ Food Entity μμ μ€κ° ν
μ΄λΈλ‘ μ‘°μΈν μ»¬λΌ μ€μ
inverseJoinColumns = @JoinColumn(name = "user_id")) // λ°λ μμΉμΈ User Entity μμ μ€κ° ν
μ΄λΈλ‘ μ‘°μΈν μ»¬λΌ μ€μ
private List<User> userList = new ArrayList<>();
}
- ν΄λΉ orders ν μ΄λΈμ JPAμ μν΄ μλμΌλ‘ λ§λ€μ΄μ§λ€. PK μ‘΄μ¬νμ§ μλλ€.
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
}
- μλ°©ν₯
- μΈλν€ μ£ΌμΈμ΄ μλ κ³ κ°μ μ½λλ§ λ³κ²½λλ€.
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
private String name;
@ManyToMany(mappedBy = "userList")
private List<Food> foodList = new ArrayList<>();
}
# N:M μλ°©ν₯ ν μ€νΈ μ½λ
@Test
@Rollback(value = false)
@DisplayName("NλM μλ°©ν₯ ν
μ€νΈ : κ°μ²΄μ μλ°©ν₯μ μ₯μ νμ©")
void test5() {
User user = new User();
user.setName("Robbie");
User user2 = new User();
user2.setName("Robbert");
// addUserList() λ©μλλ₯Ό μμ±ν΄ user μ 보λ₯Ό μΆκ°νκ³
// ν΄λΉ λ©μλμ κ°μ²΄ νμ©μ μν΄ user κ°μ²΄μ food μ 보λ₯Ό μΆκ°νλ μ½λλ₯Ό μΆκ°ν©λλ€. user.getFoodList().add(this);
Food food = new Food();
food.setName("μ보카λ νΌμ");
food.setPrice(50000);
food.addUserList(user);
food.addUserList(user2);
Food food2 = new Food();
food2.setName("κ³ κ΅¬λ§ νΌμ");
food2.setPrice(30000);
food2.addUserList(user);
userRepository.save(user);
userRepository.save(user2);
foodRepository.save(food);
foodRepository.save(food2);
// User λ₯Ό ν΅ν΄ food μ μ 보 μ‘°ν
System.out.println("user.getName() = " + user.getName());
List<Food> foodList = user.getFoodList();
for (Food f : foodList) {
System.out.println("f.getName() = " + f.getName());
System.out.println("f.getPrice() = " + f.getPrice());
}
}
- food.addUserList λ©μλλ₯Ό μ¬μ©ν΄ λ³΄λ€ κ°μ²΄μ§ν₯μ μΈ λ°©λ²μΌλ‘ μΈλν€λ₯Ό μ€μ ν΄μ€λ€.
<μ€κ°ν μ΄λΈμ μ§μ μμ±νμ¬ μμ±ν΄λ³΄κΈ°>
- order ν μ΄λΈμ μ§μ μμ±ν΄μ μ¬μ©νλ€. -> λ³κ²½λ°μμ 컨νΈλ‘€νκΈ° μ½κΈ° λλ¬Έμ νμ₯μ±μ μ©μ΄νλ€.
@Entity
@Table(name = "orders")
public class Order {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
@ManyToOne
@JoinColumn(name = "food_id")
private Food food;
@ManyToOne
@JoinColumn(name = "user_id")
private User user;
}
- μ΄μ μΈλν€μ μ£ΌμΈμ μμ, κ³ κ°μ΄ μλ μ£Όλ¬Έμ΄ λλ€.