[JPA] ์ฐ๊ด๊ด๊ณ ๋งคํ - ๋จ๋ฐฉํฅ ์ฐ๊ด๊ด๊ณ
by rlaehddnd0422์ํฐํฐ๋ค์ ๋๋ถ๋ถ ๋ค๋ฅธ ์ํฐํฐ์ ์ฐ๊ด๊ด๊ณ๊ฐ ์์ต๋๋ค.
์๋ฅผ๋ค๋ฉด, Order(์ฃผ๋ฌธ) ์ํฐํฐ๋ ์ด๋ค ์ํ์ ์ฃผ๋ฌธํ๋์ง ์๊ธฐ ์ํด Item(์ํ) ์ํฐํฐ์ ์ฐ๊ด์ด ์๊ณ , ํ์(Member)์ด ์ํ(Item)์ ์ฃผ๋ฌธ(Order)ํ ๋, Member ์ํฐํฐ๋ Item(์ํ) ์ํฐํฐ์ Order(์ฃผ๋ฌธ) ์ํฐํฐ์ ์ฐ๊ด์ ๋งบ๊ณ ์์ต๋๋ค.
๊ทธ๋ ๋ค๋ฉด ๊ฐ์ฒด์ ํ ์ด๋ธ์์๋ ์ด๋ป๊ฒ ์ํฐํฐ ๊ฐ ์ฐ๊ด์ ๋งบ์๊น์?
"๊ฐ์ฒด"์์๋ ์ฐ๊ด๊ด๊ณ๋ฅผ ์ด๋ป๊ฒ ๋งบ์๊น์? ๋ฐ๋ก ์ฐธ์กฐ๋ฅผ ์ฌ์ฉํด์ ์ฐ๊ด๊ด๊ณ๋ฅผ ๋งบ์ต๋๋ค.
"ํ ์ด๋ธ"์์๋ ์ฐ๊ด๊ด๊ณ๋ฅผ ์ด๋ป๊ฒ ๋งบ์๊น์? ๋ฐ๋ก ์ธ๋ํค๋ฅผ ์ฌ์ฉํด์ ์ฐ๊ด๊ด๊ณ๋ฅผ ๋งบ์ต๋๋ค.
๊ฐ์ฒด์ ํ ์ด๋ธ์์๋ ์ํฐํฐ ๊ฐ์ ์ฐ๊ด๊ด๊ณ๋ฅผ ๋งบ๋ ๋ฐฉ์์ด ๋ค๋ฅธ๋ฐ์, ์ด๋ฒ ํฌ์คํ ์์๋ ๊ฐ์ฒด์ ์ฐธ์กฐ-ํ ์ด๋ธ์ ์ธ๋ํค๋ฅผ ๋งคํํ๋ ๋ฐฉ๋ฒ์ ๋ํด์ ์์๋ณด๊ฒ ์ต๋๋ค.
๋งคํํ๋ ๋ฐฉ๋ฒ์ ์์๋ณด๊ธฐ์ ์์, ๊ด๊ณํ ๋ฐ์ดํฐ๋ฒ ์ด์ค์์์ ์ํฐํฐ๊ฐ ๊ด๊ณ์ ๋ํ ํค์๋๋ฅผ ์์๋๋ ๊ฒ์ด ์ค์ํฉ๋๋ค.
์ํฐํฐ ์ฐ๊ด๊ด๊ณ ํค์๋ ์์๋ณด๊ธฐ
๋ฐฉํฅ[direction]
์ํฐํฐ ๊ฐ ์ฐ๊ด๊ด๊ณ์ ๋ฐฉํฅ์ ๋จ๋ฐฉํฅ๊ณผ ์๋ฐฉํฅ์ด ์์ต๋๋ค.
๋จ๋ฐฉํฅ์ ์๋ฅผ๋ค์ด, Member๋ผ๋ ์ํฐํฐ์ Team์ด๋ผ๋ ์ํฐํฐ๊ฐ ์กด์ฌํ๊ณ ๋ ์ํฐํฐ๊ฐ ์ฐ๊ด๊ด๊ณ๋ฅผ ๊ฐ์ง๊ณ ์์ ๋,
Member โก๏ธ Team ์ ์ฐ๊ด๊ด๊ณ๋ฅผ ๊ฐ์ง๋ค๊ณ ํด๋ด ์๋ค. ๊ทธ๋ผ ์ด ๋ Member๋ฅผ ํตํด Team์ ์ฐธ์กฐํ ์ ์์ง๋ง, Team์ ํตํด Member๋ฅผ ์ฐธ์กฐํ ์ ์์ต๋๋ค. ์ฆ, ๋ ์ค ํ ์ชฝ๋ง ์ฐธ์กฐํ ์ ์๋ ๊ด๊ณ๋ฅผ "๋จ๋ฐฉํฅ" ๊ด๊ณ๋ผ๊ณ ํฉ๋๋ค.
์๋ฐฉํฅ์ Member ↔๏ธ Team ์ ์ฐ๊ด๊ด๊ณ๋ฅผ ๊ฐ์ง ๋, Member๋ฅผ ํตํด Team์ ์ฐธ์กฐํ ์ ์์๊ณผ ๋์์ Team์ ํตํด Member๋ฅผ ์ฐธ์กฐํ ์ ์์ต๋๋ค. ์ฆ, ์์ชฝ ๋ชจ๋ ์๋ก๋ฅผ ์ฐธ์กฐํ ์ ์๋ ๊ด๊ณ๋ฅผ "์๋ฐฉํฅ" ๊ด๊ณ๋ผ๊ณ ํฉ๋๋ค.
๋ค์ค์ฑ[Mutiplicity]
๋ค์ค์ฑ์๋ 1:N, N:1, 1:1, N:M ๊ด๊ณ๊ฐ ์์ต๋๋ค.
- 1:N, N:1 ๊ด๊ณ : ์๋ฅผ๋ค์ด Member์ Team์ด ์ฐ๊ด๊ด๊ณ๋ฅผ ๊ฐ์ง ๋, ์ฌ๋ฌ ํ์์ ํ ํ์ ๋ค์ด๊ฐ ์ ์๊ณ , ๋ฐ๋๋ก ํ ํ์๋ ์ฌ๋ฌ ํ์์ด ๋ค์ด์ฌ ์ ์์ต๋๋ค. ์ด๋ฐ ๊ด๊ณ๋ฅผ ์ผ๋๋ค, ๋ค๋์ผ๊ด๊ณ๋ผ๊ณ ๋งํฉ๋๋ค.
- 1:1 ๊ด๊ณ : ์๋ฅผ๋ค์ด, Member์ PhoneNumber๋ผ๋ ์ํฐํฐ๊ฐ ์กด์ฌํ ๋, ๊ฐ๊ฐ์ Member๋ ๊ฐ๊ฐ์ PhoneNumber๋ฅผ ๊ฐ์ง๊ธฐ ๋๋ฌธ์ ์ด๋ฐ ๊ด๊ณ๋ฅผ ์ผ๋์ผ ๊ด๊ณ๋ผ๊ณ ๋งํฉ๋๋ค.
- N:M (๋ค๋๋ค ๊ด๊ณ) : ๋ค๋๋ค ๊ด๊ณ์ ์์ ์ค ํ๋๋ "ํ์-๊ณผ๋ชฉ" ๊ด๊ณ์
๋๋ค. ์ฌ๋ฌ ํ์๋ค์ด ์ฌ๋ฌ ๊ณผ๋ชฉ์ ์๊ฐํ ์ ์์ผ๋ฉฐ, ํ ํ์์ด ์ฌ๋ฌ ๊ณผ๋ชฉ์ ์๊ฐํ ์ ์๊ณ , ํ ๊ณผ๋ชฉ์ ์ฌ๋ฌ ํ์๋ค์ด ์๊ฐํ ์ ์์ต๋๋ค.
- ์ด๋ฌํ ๊ด๊ณ๋ ์ผ๋๋ค๋ ๋ค๋์ผ ๊ด๊ณ๋ก ํํํ๊ธฐ์ ์ ํฉํ์ง ์์ต๋๋ค.
- ๋ฐ๋ผ์ ์ด๋ฌํ ๊ฒฝ์ฐ์๋ ๋ค๋๋ค ๊ด๊ณ๋ฅผ ๋ํ๋ด๊ธฐ ์ํด ์ค๊ฐ์ "์๊ฐ" ๊ฐ์ ์ฐ๊ฒฐ ํ ์ด๋ธ์ ๋ง๋ค์ด์ ๊ฐ๊ฐ์ ํ์๊ณผ ๊ณผ๋ชฉ์ ์ฐ๊ฒฐํด์ค๋๋ค. ์ด๋ ๊ฒ ํ๋ฉด ํ ํ์์ด ์ฌ๋ฌ ๊ณผ๋ชฉ์ ์๊ฐํ ์ ์๊ณ , ํ ๊ณผ๋ชฉ์ ์ฌ๋ฌ ํ์๋ค์ด ์๊ฐํ ์ ์๋ ๋ค๋๋ค ๊ด๊ณ๋ฅผ ํํํ ์ ์์ต๋๋ค.
- ์ด๋ฌํ ๊ด๊ณ๋ ์ผ๋๋ค๋ ๋ค๋์ผ ๊ด๊ณ๋ก ํํํ๊ธฐ์ ์ ํฉํ์ง ์์ต๋๋ค.
์ฐ๊ด๊ด๊ณ์ ์ฃผ์ธ
๊ฐ์ฒด๋ฅผ ์๋ฐฉํฅ ์ฐ๊ด๊ด๊ณ๋ก ๋ง๋ค๋ฉด ์ฐ๊ด๊ด๊ณ์ ์ฃผ์ธ์ ์ ํด์ฃผ์ด์ผํฉ๋๋ค.
์ฃผ์ธ์ ์ด๋ค ๊ธฐ์ค์ผ๋ก ์ ํ๋ ์ง๋ ๋ค์ ํฌ์คํ ์๋ฐฉํฅ ์ฐ๊ด๊ด๊ณ ๋งคํ์์ ์์ธํ ์ค๋ช ํ๋๋ก ํ๊ฒ ์ต๋๋ค.
๋จ๋ฐฉํฅ ์ฐ๊ด๊ด๊ณ
๋จ๋ฐฉํฅ, ๋ค๋์ผ ๊ด๊ณ Member(N) โก๏ธ Team(1)์ ์ฐ๊ด๊ด๊ณ๊ฐ ์์ ๋,
๊ฐ์ฒด์ ํ ์ด๋ธ์์ ์ด๋ป๊ฒ ์ฐ๊ด๊ด๊ณ๋ฅผ ๋งบ๋์ง ๋ด ์๋ค.
1. ์์ํ ๊ฐ์ฒด์์ ์ฐ๊ด๊ด๊ณ
๊ฐ์ฒด์์๋ ์ฐ๊ด๊ด๊ณ๋ฅผ ์ฐธ์กฐ๋ฅผ ํตํด ๋งบ์ต๋๋ค.
public class Member{
private Long id;
private String username;
private Team team; // ํ์ ์ฐธ์กฐ ๋ณด๊ด
}
public class Team{
private Long id;
private String name;
...
}
์ด ๋ Member์์๋ Team์ ์กฐํํ ์ ์์ง๋ง(member.getTeam()), Team์์๋ Member๋ฅผ ์กฐํํ ์ ์์ต๋๋ค.(team.getMembers() X)
ํ์ง๋ง ์๋ฐฉํฅ ์ฐ๊ด๊ด๊ณ์ผ ๋๋ Team์์๋ Member๋ฅผ ์กฐํํ ์ ์์ต๋๋ค.
2. ํ ์ด๋ธ์์์ ์ฐ๊ด๊ด๊ณ
ํ ์ด๋ธ์์๋ ์ธ๋ํค๋ฅผ ํตํด ์ฐ๊ด๊ด๊ณ๋ฅผ ๋งบ์ต๋๋ค.
create table Member (
MEMBER_ID varchar(255) not null,
username varchar(255),
TEAM_ID varchar(255),
primary key (MEMBER_ID)
)
create table Team (
TEAM_ID varchar(255) not null,
name varchar(255),
primary key (TEAM_ID)
)
alter table Member
add constraint FKl7wsny760hjy6x19kqnduasbm
foreign key (TEAM_ID)
references Team
๋ฐ์ดํฐ๋ฒ ์ด์ค์ ํ ์ด๋ธ์ ์ธ๋ ํค ํ๋๋ก ๋จ๋ฐฉํฅ ์ฐ๊ด๊ด๊ณ๋ผ๊ณ ํด๋, ์๋ฐฉํฅ์ผ๋ก ์กฐํํ ์ ์์ต๋๋ค.
Member Join Team์ด ๊ฐ๋ฅํ๋ฏ์ด, Team Join Member๋ ๊ฐ๋ฅํฉ๋๋ค.
ํ ์ด๋ธ์์๋ ๋ ํ ์ด๋ธ์ด ์ธ๋ํค๋ก ์ฐ๊ด์ ๋งบ๊ณ ์์ผ๋ฉด ์ฒ์๋ถํฐ ์๋ฐฉํฅ ๊ด๊ณ์ ๋๋ค.
๋ฐ๋ผ์ ๊ฐ์ฒด์ ๋ฌ๋ฆฌ ํ ์ด๋ธ์๋ ๋ณ๋๋ก ์ถ๊ฐํ ๋ด์ฉ์ด ์ธ๋ํค๋ฅผ ์ ์ธํ๊ณ ๋ ์์ต๋๋ค.!
JPA๋ฅผ ์ฌ์ฉํ ๊ฐ์ฒด์ ์ฐธ์กฐ-ํ ์ด๋ธ์ ์ธ๋ํค๋ฅผ ๋งคํ
Member(N) โก๏ธ Team(1)
- ๊ฐ์ฒด ์ฐ๊ด๊ด๊ณ : Member ๊ฐ์ฒด์ Member.team ํ๋ ์ฌ์ฉ
- ํ ์ด๋ธ ์ฐ๊ด๊ด๊ณ : MEMBER.TEAM_ID ์ธ๋ํค ์ปฌ๋ผ ์ฌ์ฉ
JPA๋ฅผ ์ฌ์ฉํด Member.team ๊ณผ MEMBER.TEAM_ID์ ์ฐ๊ด๊ด๊ณ๋ฅผ ๋งคํํด๋ด ์๋ค.
Member
@Entity
public class Member{
@Id
@Column(name = "MEMBER_ID")
private String id;
private String username;
// ์ฐ๊ด๊ด๊ณ ๋งคํ
@ManyToOne
@JoinColumn(name="TEAM_ID")
private Team team;
...
}
- @ManyToOne : ์ด๋ฆ ๊ทธ๋๋ก ๋ค๋์ผ ๊ด๊ฒ๋ผ๋ ๋งคํ์ ๋ณด. ์ฐ๊ด๊ด๊ณ๋ฅผ ๋งคํํ ๋๋ ์ด๋ ๊ฒ ๋ค์ค์ฑ์ ๋ํ๋ด๋ ์ด๋ ธํ ์ด์ ์ ํ์์ ์ผ๋ก ์ฌ์ฉํด์ผ ํฉ๋๋ค.
- @JoinColumn(name="TEAM_ID") : ์ธ๋ ํค๋ฅผ ๋งคํํ ๋ ์ฌ์ฉํ๋ ์ด๋ ธํ ์ด์ ์ ๋๋ค.
@JoinColumn์ ์๋ตํ๋ฉด ๊ท์น์ ๋ฐ๋ผ ์๋์ผ๋ก ์ธ๋ ํค๋ฅผ ๋งคํํฉ๋๋ค.
ํ๋๋ช + _ + ์ฐธ์กฐํ๋ ํ ์ด๋ธ ์ปฌ๋ผ๋ช
ex) ์์ ๊ฒฝ์ฐ์๋ ์๋ตํ๋ฉด team_TEAM_ID ์ธ๋ํค๋ฅผ ์ฌ์ฉ
Team
@Entity
public class Team{
@Id
@Column(name = "TEAM_ID")
private String id;
private String name;
...
}
๋ง์ง๋ง์ผ๋ก ๋จ๋ฐฉํฅ ์ฐ๊ด๊ด๊ณ์์ ์ ์ฅ,์์ ,์ญ์ ,์กฐํํ๋ ๋ฐฉ๋ฒ์ ๋ํด์ ๊ฐ๋จํ๊ฒ ์์๋ด ์๋ค.
1. ์ ์ฅ
// ํ1 ์ ์ฅ
Team team1 = new Team("team1","ํ1");
em.persist(team1);
// ๋ฉค๋ฒ1 ์ ์ฅ
Member member1 = new Member("member1","๋ฉค๋ฒ์ด๋ฆ1");
member1.setTeam(team1); // ์ฐ๊ด๊ด๊ณ ์ค์
em.persist(member1);
Member ์ํฐํฐ๋ Team ์ํฐํฐ๋ฅผ ์ฐธ์กฐํ๊ณ ์ ์ฅํ์ต๋๋ค. (member1.setTeam(team1);
์์๋ฅผ ์ค์ด๊ธฐ ์ํด ์ฐ๊ด๊ด๊ณ๋ฅผ setter๋ฅผ ํตํด ์ค์ ํด์ฃผ์์ง๋ง, domain์ getter, setter๋ฅผ ์ฌ์ฉํ๋ ๊ฒ์ ์ง์ํฉ์๋ค. ์ค์ ์์๋ DTO(Data Transfer Object)๋ฅผ ์ฌ์ฉํฉ์๋ค.
JPA๋ ์ฐธ์กฐํ ํ์ ์๋ณ์(Team.id)๋ฅผ ์ธ๋ ํค๋ก ์ฌ์ฉํด์ ์ ์ ํ ๋ฑ๋ก ์ฟผ๋ฆฌ๋ฅผ ์์ฑํด์ค๋๋ค!
insert into team (team_id, name) values('team1','ํ1')
insert into member (member_id, name, team_id) values('member1','ํ์1','team1')
1. ์ ์์์์๋ ํธ๋์ญ์ ์ ํตํด ์งํํ์ง ์์๊ธฐ ๋๋ฌธ์ ๋ง์ง๋ง ์ค ์ฝ๋ em.persist(member1) ๊ฐ ๋๋๋ฉด ์์ธ๊ฐ ๋ฐ์ํ์ง ์์ผ๋ฉด ์๋์ผ๋ก commitํฉ๋๋ค.
2. ๋น์ฐํ ์๊ธฐ์ง๋ง ์ํฐํฐ๋ฅผ DB์ ์ ์ฅํ๊ธฐ ์ํด์๋ ์ํฐํฐ๊ฐ ์์ ์ํ์ฌ์ผ ํฉ๋๋ค. - persist ํ์ผ๋ฏ๋ก ์์์ํ.
2. ์กฐํ
์ฐ๊ด๊ด๊ณ๊ฐ ์๋ ์ํฐํฐ๋ฅผ ์กฐํํ๋ ๋ฐฉ๋ฒ์ ๋ ๊ฐ์ง์ ๋๋ค.
1. ๊ฐ์ฒด ๊ทธ๋ํ ํ์ ( ๊ฐ์ฒด ์ฐ๊ด๊ด๊ณ๋ฅผ ์ฌ์ฉํ ์กฐํ by getter )
Member member = em.find(Member.class,"member1");
Team team = member.getTeam();
๊ฐ์ฒด๋ฅผ ํตํด ์ฐ๊ด๋ ์ํฐํฐ ์กฐํํ๋ ๋ฐฉ๋ฒ์ ๊ฐ์ฒด ๊ทธ๋ํ ํ์ ์ด๋ผ๊ณ ํฉ๋๋ค.
2. JPQL ์ฌ์ฉ
public static void main(String[] args) {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
EntityManager em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin();
try {
String jpql = "select m from Member m join m.team t where t.name =: teamName";
List<Member> resultList = em.createQuery(jpql, Member.class)
.setParameter("teamName", "ํ1")
.getResultList();
for (Member member : resultList) {
System.out.println("member.getUsername() = " + member.getUsername());
}
tx.commit();
} catch (Exception e) {
e.printStackTrace();
tx.rollback();
} finally {
em.close();
}
emf.close();
}
์กฐํ๋ ํธ๋์ญ์ ์ ํตํด ์งํํด๋ณด์์ต๋๋ค.
3. ์์
์์ ๋ฐฐ์ด ์์์ฑ ์ปจํ ์คํธ์ ๋ณ๊ฒฝ ๊ฐ์ง ๊ธฐ๋ฅ์ ๋๊ฐ์ด ์ ์ฉํ๋ฉด ๋ฉ๋๋ค. ๋ฑํ ์ฐ๊ด๊ด๊ณ๊ฐ ์ถ๊ฐ๋์๋ค๊ณ ํด์ ์ฐจ์ด์ ์ ์์ต๋๋ค.
public static void main(String[] args) {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("hello");
EntityManager em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction();
tx.begin();
try {
Team team2 = new Team("team2", "ํ2");
em.persist(team2);
Member member1 = em.find(Member.class, "member1");
member1.setTeam(team2);
em.persist(member1);
tx.commit();
} catch (Exception e) {
e.printStackTrace();
tx.rollback();
} finally {
em.close();
}
}
4. ์ญ์
์ฐ๊ด๋ ์ํฐํฐ๋ฅผ ์ญ์ ํ ๋์๋ ์ฃผ์ํ ์ ์ด ์์ต๋๋ค. ๋ฐ๋์ ๊ธฐ์กด์ ์๋ ์ฐ๊ด๊ด๊ณ๋ฅผ ๋จผ์ ์ ๊ฑฐํ๊ณ ์ญ์ ํด์ผ ํฉ๋๋ค.
๊ทธ๋ ์ง ์์ผ๋ฉด ์ธ๋ ํค ์ ์ฝ์กฐ๊ฑด์ ์ํด ๋ฐ์ดํฐ๋ฒ ์ด์ค์์ ์ค๋ฅ๊ฐ ๋ฐ์ํฉ๋๋ค.
member1.setTeam(null);
em.remove(member1);
<์ ๋ฆฌ>
- ๋จ๋ฐฉํฅ ์ฐ๊ด๊ด๊ณ๋ฅผ ๋งคํํด๋ณด์์ต๋๋ค.
- ๋จ๋ฐฉํฅ์์ ์ธ๋ํค๋ฅผ ๊ฐ์ง๊ณ ์๋ ์ํฐํฐ์๋ ์ฐธ์กฐ ํ๋์ ๋ฐ๋์ ๋ค์ค์ฑ์ ๋ํ๋ด๋ ์ด๋
ธํ
์ด์
(ex) @ManyToOne)์ ๋ถ์ฌ์ฃผ์ด์ผ ํฉ๋๋ค.
- + ์ฐธ์กฐ ํ๋์ @JoinColumn์ name์์ฑ์๋ ์ธ๋ํค๋ก ์ฌ์ฉํ ์ปฌ๋ผ๋ช ์ ๋ถ์ฌ์ฃผ์ด์ผ ํฉ๋๋ค. ๋ถํ์ฃผ์ง ์์ผ๋ฉด ๊ท์น์ ๋ฐ๋ผ ์๋์ผ๋ก ์์ฑ๋ ์ธ๋ํค ์ปฌ๋ผ๋ช ๊ณผ ๋งคํ๋ฉ๋๋ค.
- ๋ค์ ํฌ์คํ ์์๋ ์๋ฐฉํฅ ์ฐ๊ด๊ด๊ณ๋ฅผ ์์๋ณด๊ณ ๋งคํํด๋ณด๋๋ก ํ๊ฒ ์ต๋๋ค! ๊ฐ์ฌํฉ๋๋ค.
<์ฐธ๊ณ ์๋ฃ>
'๐ Backend > Spring Data JPA' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[JPA] ๋ค๋์ผ, ์ผ๋๋ค, ์ผ๋์ผ (๋จ๋ฐฉํฅ, ์๋ฐฉํฅ) ์ฐ๊ด๊ด๊ณ ๋งคํ (0) | 2023.05.01 |
---|---|
[JPA] ์ฐ๊ด๊ด๊ณ ๋งคํ - ์๋ฐฉํฅ ์ฐ๊ด๊ด๊ณ (1) | 2023.04.30 |
[JPA] Entity Mapping : ํ๋ โก๏ธ ์ปฌ๋ผ ๋งคํ (0) | 2023.04.28 |
[JPA] Entity Mapping : ๊ธฐ๋ณธ ํค(PK) ๋งคํ (0) | 2023.04.27 |
[JPA] Entity Mapping : ๊ฐ์ฒด โก๏ธ ํ ์ด๋ธ ๋งคํ (0) | 2023.04.27 |
๋ธ๋ก๊ทธ์ ์ ๋ณด
Study Repository
rlaehddnd0422