πŸ“š [JPA] μ—°κ΄€ 관계 λ§€ν•‘

이가은·2024λ…„ 5μ›” 16일
0

Spring

λͺ©λ‘ 보기
10/13
post-thumbnail

πŸ“• μ—°κ΄€ 관계 λ§€ν•‘

객체의 참쑰와 ν…Œμ΄λΈ”μ˜ μ™Έλž˜ν‚€λ₯Ό λ§€ν•‘ν•˜λŠ” 것

βœ” JPAμ—μ„œλŠ” μ—°κ΄€ 관계에 μžˆλŠ” μƒλŒ€ ν…Œμ΄λΈ”μ˜ PKλ₯Ό 멀버 λ³€μˆ˜λ‘œ κ°–μ§€ μ•Šκ³ , μ—”ν‹°ν‹° 객체 자체λ₯Ό ν†΅μ§Έλ‘œ μ°Έμ‘°ν•œλ‹€.

πŸ“– μ—°κ΄€ 관계λ₯Ό μ‚¬μš©ν•˜λŠ” 이유

객체 간에 관계가 μžˆμ„ 경우, 객체λ₯Ό μ°Έμ‘°ν•˜μ—¬ μ—°κ΄€λœ λ‚΄μš©λ“€μ„ 확인할 수 μžˆλ‹€. ν…Œμ΄λΈ”μ˜ μž…μž₯μ—μ„œλŠ” μ—°κ΄€ 관계λ₯Ό 톡해 λΆˆν•„μš”ν•œ μΉΌλŸΌμ„ μƒμ„±ν•˜μ§€ μ•Šμ•„λ„ λœλ‹€.

예λ₯Ό λ“€μ–΄, Team Entity와 Member Entityκ°€ μ—°κ΄€ 관계에 μžˆλ‹€κ³  ν•œλ‹€λ©΄ Member 객체에 μ—°κ΄€λœ Team의 정보λ₯Ό 확인할 수 μžˆλ‹€.

πŸ“– μ—°κ΄€ 관계 λ§€ν•‘ μ‹œ 생각해야 ν•  것

β—½ λ°©ν–₯ : 단방ν–₯, μ–‘λ°©ν–₯ (객체 κ°„μ˜ μ°Έμ‘°)
β—½ μ—°κ΄€ κ΄€κ³„μ˜ 주인 : μ–‘λ°©ν–₯일 λ•Œ μ—°κ΄€ κ΄€κ³„μ—μ„œ κ΄€λ¦¬μ˜ 주체가 λ˜λŠ” κ³³
β—½ 닀쀑성 : μΌλŒ€μΌ, μΌλŒ€λ‹€, λ‹€λŒ€μΌ, λ‹€λŒ€λ‹€

πŸ“™ λ°©ν–₯

πŸ“– 단방ν–₯ μ—°κ΄€ 관계

두 Entityκ°€ 관계λ₯Ό 맺을 λ•Œ, ν•œ μͺ½μ˜ Entity만 μ°Έμ‘°ν•˜κ³  μžˆλŠ” 것을 의미

[객체 μ—°κ΄€ 관계]
β—½ νšŒμ› 객체(Member)λŠ” Member.team ν•„λ“œ(멀버 λ³€μˆ˜)둜 νŒ€ 객체와 μ—°κ΄€ 관계
β—½ νšŒμ› 객체와 νŒ€ κ°μ²΄λŠ” 단방ν–₯ 관계
β—½ νšŒμ›μ€ Member.team ν•„λ“œλ₯Ό 톡해 νŒ€μ„ μ•Œ 수 μžˆμ§€λ§Œ, νŒ€ 객체둜 μ†Œμ†λœ νšŒμ›λ“€μ„ μ•Œ 수 μ—†κΈ° λ•Œλ¬Έμ΄λ‹€
β—½ member ➑ team의 μ‘°νšŒλŠ” member.getTeam()으둜 κ°€λŠ₯ν•˜μ§€λ§Œ, team ➑ memberλ₯Ό μ ‘κ·Όν•˜λŠ” ν•„λ“œλŠ” μ—†λ‹€

[ν…Œμ΄λΈ” 연관관계]
β—½ νšŒμ› ν…Œμ΄λΈ”μ€ TEAM_ID μ™Έλž˜ν‚€(FK)둜 νŒ€ ν…Œμ΄λΈ”κ³Ό 연관관계
β—½ νšŒμ› ν…Œμ΄λΈ”κ³Ό νŒ€ ν…Œμ΄λΈ”μ€ μ–‘λ°©ν–₯ 관계
β—½ νšŒμ› ν…Œμ΄λΈ”μ˜ TEAM_ID μ™Έλž˜ν‚€λ₯Ό ν†΅ν•΄μ„œ νšŒμ›κ³Ό νŒ€μ„ 쑰인할 수 있고, λ°˜λŒ€λ‘œ νŒ€κ³Ό νšŒμ›λ„ 쑰인할 수 μžˆλ‹€
β—½ MEMBER ν…Œμ΄λΈ”μ˜ TEAM_ID μ™Έλž˜ν‚€ ν•˜λ‚˜λ‘œ MEMBER JOIN TEAMκ³Ό TEAM JOIN MEMBER λ‘˜ λ‹€ κ°€λŠ₯ν•˜λ‹€

//νšŒμ›κ³Ό νŒ€μ„ μ‘°μΈν•˜λŠ” SQL
SELECT * FROM MEMBER M
JOIN TEAM T ON M.TEAM_ID = T.TEAM_ID

//νŒ€κ³Ό νšŒμ›μ„ μ‘°μΈν•˜λŠ” SQL
SELECT * FROM TEAM T
JOIN MEMBER M ON T.TEAM_ID = M.TEAM_ID

🎈 객체 μ—°κ΄€ 관계와 ν…Œμ΄λΈ” μ—°κ΄€ κ΄€κ³„μ˜ 차이점
β—½ κ°μ²΄λŠ” 참쑰둜 μ—°κ΄€ 관계λ₯Ό λ§Ίκ³ , ν…Œμ΄λΈ”μ€ μ™Έλž˜ν‚€λ‘œ μ—°κ΄€ 관계λ₯Ό λ§ΊλŠ”λ‹€
β—½ μ°Έμ‘°λ₯Ό μ‚¬μš©ν•˜λŠ” 객체의 μ—°κ΄€ κ΄€κ³„λŠ” 단방ν–₯이닀
-> 객체간에 μ—°κ΄€ 관계λ₯Ό μ–‘λ°©ν–₯으둜 λ§Œλ“€κ³  μ‹ΆμœΌλ©΄ λ°˜λŒ€μͺ½μ—λ„ ν•„λ“œλ₯Ό μΆ”κ°€ν•΄μ„œ μ°Έμ‘°λ₯Ό 보관해야 ν•œλ‹€. μ΄λ ‡κ²Œ μ–‘μͺ½μ—μ„œ 단방ν–₯ μ—°κ΄€ 관계 맀핑을 톡해 μ–‘λ°©ν–₯ μ—°κ΄€ 관계λ₯Ό λ§ΊλŠ”λ‹€
β—½ μ™Έλž˜ν‚€λ₯Ό μ‚¬μš©ν•˜λŠ” ν…Œμ΄λΈ”μ˜ μ—°κ΄€ κ΄€κ³„λŠ” μ–‘λ°©ν–₯이닀
-> ν…Œμ΄λΈ”μ€ μ™Έλž˜ν‚€ ν•˜λ‚˜λ‘œ 쑰인을 μ‚¬μš©ν•΄μ„œ μ–‘λ°©ν–₯으둜 쿼리가 κ°€λŠ₯ν•˜λ―€λ‘œ 사싀상 λ°©ν–₯μ΄λΌλŠ” κ°œλ…μ΄ μ—†λ‹€. 두 객체가 단방ν–₯ μ°Έμ‘°λ₯Ό 각각 κ°€μ Έμ„œ μ–‘λ°©ν–₯ κ΄€κ³„μ²˜λŸΌ μ‚¬μš©ν•˜λŠ” 것이닀

πŸ“– μ–‘λ°©ν–₯ μ—°κ΄€ 관계

두 Entityκ°€ 관계λ₯Ό 맺을 λ•Œ, μ–‘ μͺ½μ΄ μ„œλ‘œ μ°Έμ‘°ν•˜κ³  μžˆλŠ” 것을 의미
-> μ„œλ‘œ 단방ν–₯ μ—°κ΄€ 관계 맀핑을 톡해 μ–‘λ°©ν–₯ μ—°κ΄€ 관계λ₯Ό λ§ΊλŠ”λ‹€

🎈 무쑰건 μ–‘λ°©ν–₯ 관계λ₯Ό ν•˜λ©΄ 쉽지 μ•Šλ‚˜β“
❌ 객체 μž…μž₯μ—μ„œ μ–‘λ°©ν–₯ 맀핑을 ν–ˆμ„ λ•Œ 였히렀 λ³΅μž‘ν•΄μ§ˆ 수 μžˆλ‹€
예λ₯Ό λ“€μ–΄, 일반적인 λΉ„μ¦ˆλ‹ˆμŠ€ μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ—μ„œ μ‚¬μš©μž(User) μ—”ν‹°ν‹°λŠ” ꡉμž₯히 λ§Žμ€ 엔티티와 μ—°κ΄€ 관계λ₯Ό κ°–λŠ”λ‹€. 이런 κ²½μš°μ— λͺ¨λ“  μ—”ν‹°ν‹°λ₯Ό μ–‘λ°©ν–₯ κ΄€κ³„λ‘œ μ„€μ •ν•˜κ²Œ 되면 μ‚¬μš©μž(User) μ—”ν‹°ν‹°λŠ” μ—„μ²­λ‚˜κ²Œ λ§Žμ€ ν…Œμ΄λΈ”κ³Ό μ—°κ΄€ 관계λ₯Ό 맺게 되고 User ν΄λž˜μŠ€κ°€ λ³΅μž‘ν•΄μ§„λ‹€. 그리고 λ‹€λ₯Έ 엔티티듀도 λΆˆν•„μš”ν•œ μ—°κ΄€ 관계 λ§€ν•‘μœΌλ‘œ 인해 λ³΅μž‘μ„±μ΄ 증가할 수 μžˆλ‹€. κ·Έλž˜μ„œ μ–‘λ°©ν–₯으둜 ν• μ§€ 단방ν–₯으둜 ν• μ§€ κ΅¬λΆ„ν•΄μ€˜μ•Ό ν•œλ‹€. κ΅¬λΆ„ν•˜κΈ° 쒋은 기쀀은 기본적으둜 단방ν–₯ λ§€ν•‘μœΌλ‘œ ν•˜κ³  λ‚˜μ€‘μ— μ—­λ°©ν–₯으둜 객체 탐색이 κΌ­ ν•„μš”ν•˜λ‹€κ³  λŠλ‚„ λ•Œ μΆ”κ°€ν•˜λŠ” 것이 μ’‹λ‹€κ³  ν•œλ‹€.

πŸ“’ μ—°κ΄€ κ΄€κ³„μ˜ 주인

β—½ 두 객체(A, B)κ°€ μ–‘λ°©ν–₯ 관계, λ‹€μ‹œ 말해 단방ν–₯ 관계 2개(Aβ†’B, Bβ†’A)λ₯Ό 맺을 λ•Œ, μ—°κ΄€ κ΄€κ³„μ˜ 주인을 μ§€μ •ν•΄μ•Ό ν•œλ‹€
β—½ μ—°κ΄€ κ΄€κ³„μ˜ 주인을 μ§€μ •ν•˜λŠ” 것은 두 단방ν–₯ 관계(Aβ†’B, Bβ†’A)쀑, μ œμ–΄μ˜ κΆŒν•œ(μ™Έλž˜ ν‚€λ₯Ό λΉ„λ‘―ν•œ ν…Œμ΄λΈ” λ ˆμ½”λ“œλ₯Ό μ €μž₯, μˆ˜μ •, μ‚­μ œ 처리)을 κ°–λŠ” μ‹€μ§ˆμ μΈ 관계가 μ–΄λ–€ 것인지 JPAμ—κ²Œ μ•Œλ €μ£ΌλŠ” 것
β—½ μ—°κ΄€ κ΄€κ³„μ˜ 주인은 μ—°κ΄€ 관계λ₯Ό κ°–λŠ” 두 객체 μ‚¬μ΄μ—μ„œ 쑰회, μ €μž₯, μˆ˜μ •, μ‚­μ œλ₯Ό ν•  수 μžˆμ§€λ§Œ, μ—°κ΄€ κ΄€κ³„μ˜ 주인이 μ•„λ‹ˆλ©΄ 쑰회만 κ°€λŠ₯ν•˜λ‹€.
β—½ μ—°κ΄€ κ΄€κ³„μ˜ 주인이 μ•„λ‹Œ κ°μ²΄μ—μ„œ mappedBy 속성을 μ‚¬μš©ν•΄μ„œ 주인을 μ§€μ •ν•΄μ€˜μ•Ό ν•œλ‹€.
β—½ μ™Έλž˜ν‚€κ°€ μžˆλŠ” 곳을 μ—°κ΄€ κ΄€κ³„μ˜ 주인으둜 μ •ν•˜λ©΄ λœλ‹€κ³  ν•œλ‹€β—

πŸ“— 닀쀑성

λ°μ΄ν„°λ² μ΄μŠ€λ₯Ό κΈ°μ€€μœΌλ‘œ 닀쀑성을 κ²°μ •

μ—°κ΄€ κ΄€κ³„λŠ” λŒ€μΉ­μ„±μ„ κ°–λŠ”λ‹€
β—½ μΌλŒ€λ‹€ ↔ λ‹€λŒ€μΌ
β—½ μΌλŒ€μΌ ↔ μΌλŒ€μΌ
β—½ λ‹€λŒ€λ‹€ ↔ λ‹€λŒ€λ‹€

πŸ“– λ‹€λŒ€μΌ(N:1)

🎈 λ‹€λŒ€μΌ(N:1) 단방ν–₯

🎁 Member 클래슀 (λ‹€λŒ€μΌμ—μ„œ 닀에 ν•΄λ‹Ή)

@Entity
public class Member {
   @Id
   @Column(name = "MEMBER_ID")
   private Long id;
 
   @Column(name = "USERNAME")
   private String username;
 
   @ManyToOne
   @JoinColumn(name = "TEAM_ID")
   private Team team;
  
  //Getter, Setter, Constructor...
}

🎁 Team 클래슀 (λ‹€λŒ€μΌμ—μ„œ 일에 ν•΄λ‹Ή)

@Entity
public class Team {
	@Id
    @Column(name = "TEAM_ID")
    private Long id;
    
    @Column(name = "NAME")
    private String name;
    
    //Getter, Setter, Constructor
}

βœ” λ‹€λŒ€μΌ 단방ν–₯ λ§€ν•‘μ—μ„œλŠ” λ‹€(N)에 ν•΄λ‹Ήν•˜λŠ” ν΄λž˜μŠ€μ— 일(1)에 ν•΄λ‹Ήν•˜λŠ” 클래슀λ₯Ό μ°Έμ‘° ν•„λ“œλ‘œ μž‘μ„±ν•˜λ©΄ λœλ‹€
βœ” μ΄λ•Œ, ν•΄λ‹Ή μ°Έμ‘° ν•„λ“œ μœ„μ— @ManyToOneκ³Ό @JoinColumn(name = "μ™Έλž˜ν‚€ 이름")을 μΆ”κ°€ν•œλ‹€

@ManyToOne : λ‹€λŒ€μΌ(N:1) κ΄€κ³„λΌλŠ” λ§€ν•‘ 정보이닀. 연관관계λ₯Ό λ§€ν•‘ν•  λ•Œ 닀쀑성을 λ‚˜νƒ€λ‚΄λŠ” μ–΄λ…Έν…Œμ΄μ…˜μ„ ν•„μˆ˜λ‘œ μ‚¬μš©
@JoinColumn : μ™Έλž˜ν‚€λ₯Ό λ§€ν•‘ν•  λ•Œ μ‚¬μš©ν•˜κ³ , name μ†μ„±μ—λŠ” λ§€ν•‘ν•  μ™Έλž˜ν‚€ 이름을 μ§€μ •ν•œλ‹€. 이 μ–΄λ…Έν…Œμ΄μ…˜μ€ μƒλž΅μ΄ κ°€λŠ₯ν•˜κ³ , μƒλž΅ν•˜λ©΄ μ™Έλž˜ν‚€λ₯Ό 찾을 λ•Œ κΈ°λ³Έ μ „λž΅μ„ μ‚¬μš©ν•œλ‹€

🎈 λ‹€λŒ€μΌ(N:1) μ–‘λ°©ν–₯

🎁 Member 클래슀 (λ‹€λŒ€μΌμ—μ„œ 닀에 ν•΄λ‹Ή)

@Entity
public class Member {
   @Id
   @Column(name = "MEMBER_ID")
   private Long id;
 
   @Column(name = "USERNAME")
   private String username;
 
   @ManyToOne
   @JoinColumn(name = "TEAM_ID")
   private Team team;
  
  //Getter, Setter, Constructor...
}

🎁 Team 클래슀 (λ‹€λŒ€μΌμ—μ„œ 일에 ν•΄λ‹Ή)

@Entity
public class Team {
	@Id
    @Column(name = "TEAM_ID)
    private Long id;
    
    @Column(name = "NAME")
    private String name;
    
    @OneToMany(mappedBy = "team")
    private List<Member> members = new ArrayList<>(); 
    //NPE λ°©μ§€λ₯Ό μœ„ν•΄μ„œ, Collection 객체λ₯Ό μ΄ˆκΈ°ν™” ν•œλ‹€
    //NPE : Null Pointer Exception
    
    //Getter, Setter, Constructor
}

βœ” λ‹€λŒ€μΌ μ–‘λ°©ν–₯ λ§€ν•‘μ—μ„œ λ‹€(N)에 μ†ν•˜λŠ” Member ν΄λž˜μŠ€λŠ” λ‹€λŒ€μΌ 단방ν–₯ λ§€ν•‘μ˜ μ½”λ“œμ™€ λ™μΌν•˜λ‹€
βœ” λ‹€λŒ€μΌ μ–‘λ°©ν–₯으둜 λ§Œλ“œλ €λ©΄ 일(1) μͺ½μ— @OneToManyλ₯Ό μΆ”κ°€ν•˜κ³  μ–‘λ°©ν–₯ 맀핑을 μ‚¬μš©ν–ˆμœΌλ‹ˆ μ—°κ΄€κ΄€κ³„μ˜ 주인이 μ•„λ‹ˆκ³ , 어디에 λ§€ν•‘ λλŠ”μ§€μ— κ΄€ν•œ 정보 mappedByλ₯Ό λ„£μ–΄μ€˜μ•Ό ν•œλ‹€.
βœ” mappedBy둜 μ§€μ •ν•  λ•Œ 값은 λŒ€μƒμ΄ λ˜λŠ” λ³€μˆ˜λͺ…을 따라 μ§€μ •ν•˜λ©΄ λœλ‹€.

πŸ“– μΌλŒ€λ‹€(1:N)

🎈 μΌλŒ€λ‹€(1:N) 단방ν–₯

β—Ύ μΌλŒ€λ‹€(1:N) κ΄€κ³„λŠ” λ‹€λŒ€μΌ κ΄€κ³„μ˜ λ°˜λŒ€ λ°©ν–₯
β—Ύ 일(1)이 μ™Έλž˜ν‚€λ₯Ό κ΄€λ¦¬ν•˜λ©°, μ—°κ΄€ κ΄€κ³„μ˜ 주인

🎁 Team 클래슀 (μΌλŒ€λ‹€μ—μ„œ 일에 ν•΄λ‹Ή)

@Entity
public class Team {
	@Id
    @Column(name = "TEAM_ID")
    private Long id;
    
    @Column(name = "NAME")
    private String name;
    
    @OneToMany
    @JoinColumn(name = "TEAM_ID") //MEMBER ν…Œμ΄λΈ”μ˜ TEAM_ID (FK)
    pricate List<Member> members = new ArrayList<>();
    
    //Getter, Setter, Constructor, ...
}

🎁 Member 클래슀 (μΌλŒ€λ‹€μ—μ„œ 닀에 ν•΄λ‹Ή)

@Entity
public class Member {
    @Id
    @Column(name = "MEMBER_ID")
    private Long id;
    
    @Column(name = "USERNAME")
    private String username;
    
    //Getter, Setter, Constructor
}

βœ” 일(1)에 @OneToMany와 @JoinColumn(name = "μ™Έλž˜ν‚€ 이름")을 μΆ”κ°€ν•œλ‹€
βœ” μΌλŒ€λ‹€ 단방ν–₯ 관계λ₯Ό λ§€ν•‘ν•  λ•ŒλŠ” @JoinColumn을 λͺ…μ‹œν•΄μ•Ό ν•œλ‹€. κ·Έλ ‡μ§€ μ•ŠμœΌλ©΄ JPAλŠ” μ—°κ²° ν…Œμ΄λΈ”μ„ 쀑간에 μƒμ„±ν•˜κ³ , μ—°κ΄€ 관계λ₯Ό κ΄€λ¦¬ν•˜λŠ” 쑰인 ν…Œμ΄λΈ” μ „λž΅μ„ 기본으둜 μ‚¬μš©ν•˜μ—¬ λ§€ν•‘ν•œλ‹€

μΌλŒ€λ‹€ 단방ν–₯ λ§€ν•‘μ˜ 단점 : λ§€ν•‘ν•œ 객체가 κ΄€λ¦¬ν•˜λŠ” μ™Έλž˜ ν‚€κ°€ λ‹€λ₯Έ ν…Œμ΄λΈ”μ— μžˆλ‹€. 본인 ν…Œμ΄λΈ”μ— μ™Έλž˜ν‚€κ°€ 있으면 μ—”ν‹°ν‹°μ˜ μ €μž₯κ³Ό μ—°κ΄€ 관계 처리λ₯Ό INSERT SQL ν•œ 번으둜 끝낼 수 μžˆμ§€λ§Œ, κ·Έλ ‡μ§€ μ•Šλ‹€λ©΄ μ—°κ΄€ 관계 처리λ₯Ό μœ„ν•œ UPDATE SQL을 μΆ”κ°€λ‘œ μ‹€ν–‰ν•΄μ•Ό ν•œλ‹€.
-> μΌλŒ€λ‹€ 단방ν–₯ μ—°κ΄€ 관계 맀핑이 ν•„μš”ν•œ κ²½μš°μ—λŠ” λ‹€λŒ€μΌ μ–‘λ°©ν–₯ μ—°κ΄€ 관계 맀핑을 ν•˜λŠ”κ²Œ μΆ”ν›„ μœ μ§€λ³΄μˆ˜ν•  λ•Œ 훨씬 μˆ˜μ›”ν•˜λ‹€

@OneToMany : μΌλŒ€λ‹€ κ΄€κ³„μ—μ„œ μ‚¬μš©

🎈 μΌλŒ€λ‹€(1:N) μ–‘λ°©ν–₯
κ³΅μ‹μ μœΌλ‘œ μ‘΄μž¬ν•˜μ§€ μ•Šκ³ , 싀무 μ‚¬μš© κΈˆμ§€ ❌

πŸ“– μΌλŒ€μΌ(1:1)

βœ” μΌλŒ€μΌ(1:1) κ΄€κ³„λŠ” μ£Ό ν…Œμ΄λΈ”μ΄λ‚˜ λŒ€μƒ ν…Œμ΄λΈ” λ‘˜ 쀑 μ–΄λŠ κ³³μ΄λ‚˜ μ™Έλž˜ν‚€λ₯Ό κ°€μ§ˆ 수 μžˆλ‹€

μ£Ό ν…Œμ΄λΈ”μ— μ™Έλž˜ν‚€ μ €μž₯ : 객체지ν–₯ κ°œλ°œμžλ“€μ΄ μ„ ν˜Έν•˜λŠ” λ°©μ‹μœΌλ‘œ, μ£Ό 객체가 λŒ€μƒ 객체λ₯Ό μ°Έμ‘°ν•˜λŠ” κ²ƒμ²˜λŸΌ μ£Ό ν…Œμ΄λΈ”μ— μ™Έλž˜ ν‚€λ₯Ό 두고 λŒ€μƒ ν…Œμ΄λΈ”μ„ μ°Έμ‘°ν•œλ‹€. μ£Ό ν…Œμ΄λΈ”μ΄ μ™Έλž˜ ν‚€λ₯Ό κ°€μ§€κ³  μžˆμœΌλ―€λ‘œ μ£Ό ν…Œμ΄λΈ”λ§Œ 확인해도 λŒ€μƒ ν…Œμ΄λΈ”κ³Ό 연관관계가 μžˆλŠ”μ§€ μ•Œ 수 μžˆλ‹€.

λŒ€μƒ ν…Œμ΄λΈ”μ— μ™Έλž˜ν‚€ μ €μž₯ : λ°μ΄ν„°λ² μ΄μŠ€ κ°œλ°œμžλ“€μ΄ μ„ ν˜Έν•˜λŠ” λ°©μ‹μœΌλ‘œ, ν…Œμ΄λΈ” 관계λ₯Ό μΌλŒ€μΌ(1:1)μ—μ„œ μΌλŒ€λ‹€(1:N)으둜 λ³€κ²½ν•  λ•Œ, ν…Œμ΄λΈ” ꡬ쑰λ₯Ό κ·ΈλŒ€λ‘œ μœ μ§€ν•  수 μžˆλ‹€.

🎈 μ£Ό ν…Œμ΄λΈ”μ— μ™Έλž˜ν‚€, μΌλŒ€μΌ(1:1) 단방ν–₯

🎁 Member 클래슀 (μΌλŒ€μΌμ—μ„œ μ£Ό ν…Œμ΄λΈ”μ— ν•΄λ‹Ή)

public class Member {
    @Id
    @Column(name = "MEMBER_ID")
    private Long id;

    @OneToOne
    @JoinColumn(name = "LOCKER_ID")
    private Locker locker;
    
    @Column(name = "USERNAME")
    private String username;

	//Getter, Setter, Constructor
}

🎁 Locker 클래슀 (μΌλŒ€μΌμ—μ„œ λŒ€μƒ ν…Œμ΄λΈ”μ— ν•΄λ‹Ή)

public class Locker {
    @Id
    @Column(name = "LOCKER_ID")
    private Long id;

    @Column(name = "NAME")
    private String name;
    
    //Getter, Setter, Constructor
}

βœ” μ£Ό ν…Œμ΄λΈ”μ— μ™Έλž˜ν‚€λ₯Ό μ €μž₯ν•˜λŠ” 단방ν–₯ 관계일 경우, μ£Ό ν…Œμ΄λΈ”μ— ν•΄λ‹Ήν•˜λŠ” ν΄λž˜μŠ€μ— λŒ€μƒ ν…Œμ΄λΈ”μ— ν•΄λ‹Ήν•˜λŠ” 클래슀λ₯Ό μ°Έμ‘° ν•„λ“œλ‘œ μž‘μ„±ν•œλ‹€
βœ” μ΄λ•Œ, ν•΄λ‹Ή μ°Έμ‘° ν•„λ“œ μœ„μ— @OneToOneκ³Ό @JoinColumn(name = "μ™Έλž˜ν‚€ 이름")을 μΆ”κ°€ν•œλ‹€

@OneToOne : μΌλŒ€μΌ κ΄€κ³„λŠ” μ–‘μͺ½μ΄ μ„œλ‘œ ν•˜λ‚˜μ˜ κ΄€κ³„λ§Œ κ°€μ§„λ‹€

🎈 μ£Ό ν…Œμ΄λΈ”μ— μ™Έλž˜ν‚€, μΌλŒ€μΌ(1:1) μ–‘λ°©ν–₯

🎁 Member 클래슀 (μΌλŒ€μΌμ—μ„œ μ£Ό ν…Œμ΄λΈ”μ— ν•΄λ‹Ή)

public class Member {
    @Id
    @Column(name = "MEMBER_ID")
    private Long id;

    @OneToOne
    @JoinColumn(name = "LOCKER_ID")
    private Locker locker;
    
    @Column(name = "USERNAME")
    private String username;
	
    //μˆœμˆ˜ν•œ 객체λ₯Ό κ³ λ €ν•œ 연관관계 편의 λ©”μ„œλ“œ
    public void setLocker(Locker locker) {
        if (this.locker != null) {
            this.locker.setMember(null);
        }

        this.locker = locker;
        if (locker != null) {
            locker.setMember(this);
        }
    }
    
	//Getter, Setter, Constructor
}

🎁 Locker 클래슀 (μΌλŒ€μΌμ—μ„œ λŒ€μƒ ν…Œμ΄λΈ”μ— ν•΄λ‹Ή)

public class Locker {
    @Id
    @Column(name = "LOCKER_ID")
    private Long id;

    @Column(name = "NAME")
    private String name;
    
    @OneToOne(mappedBy = "locker")
    private Member member;
    
    //Getter, Setter, Constructor
}

βœ” μ£Ό ν…Œμ΄λΈ”μ— μ™Έλž˜ν‚€λ₯Ό μ €μž₯ν•˜λŠ” μ–‘λ°©ν–₯ 관계일 경우, μ£Ό ν…Œμ΄λΈ”μ— ν•΄λ‹Ήν•˜λŠ” ν΄λž˜μŠ€λŠ” μ£Ό ν…Œμ΄λΈ”μ— μ™Έλž˜ν‚€λ₯Ό μ €μž₯ν•˜λŠ” 단방ν–₯ 관계와 λ™μΌν•˜λ‹€
βœ” λŒ€μƒ ν…Œμ΄λΈ”μ— ν•΄λ‹Ήν•˜λŠ” ν΄λž˜μŠ€μ— μ£Ό ν…Œμ΄λΈ”μ— ν•΄λ‹Ήν•˜λŠ” 클래슀λ₯Ό μ°Έμ‘° ν•„λ“œλ‘œ μž‘μ„±ν•œλ‹€
βœ” μ΄λ•Œ, ν•΄λ‹Ή ν•„λ“œμœ„μ— @OneToOne(mappedBy = "λ°˜λŒ€μͺ½ λ§€ν•‘μ˜ ν•„λ“œ 이름값")을 μΆ”κ°€ν•œλ‹€

mappedBy : μ–‘λ°©ν–₯ 맀핑일 λ•Œ μ‚¬μš©ν•˜λ©°, λ°˜λŒ€μͺ½ λ§€ν•‘μ˜ ν•„λ“œ μ΄λ¦„κ°’μœΌλ‘œ μ„€μ •ν•œλ‹€. μ΄λŠ” μ—°κ΄€κ΄€κ³„μ˜ 주인을 μ„€μ •ν•˜κΈ° μœ„ν•œ 것이닀

🎈 λŒ€μƒ ν…Œμ΄λΈ”μ— μ™Έλž˜ν‚€, μΌλŒ€μΌ(1:1) 단방ν–₯
이런 μ—°κ΄€κ΄€κ³„λŠ” JPAμ—μ„œ μ§€μ›ν•˜μ§€ μ•ŠλŠ”λ‹€ ❌

🎈 λŒ€μƒ ν…Œμ΄λΈ”μ— μ™Έλž˜ν‚€, μΌλŒ€μΌ(1:1) μ–‘λ°©ν–₯

βœ” ν…Œμ΄λΈ” μ—°κ΄€κ΄€κ³„μ—μ„œ λŒ€μƒ ν…Œμ΄λΈ”μ— μ €μž₯된 μ™Έλž˜ν‚€μ— UNIQUE μ œμ•½μ‘°κ±΄μ΄ μΆ”κ°€λœ 것을 확인할 수 μžˆλ‹€

🎁 Member 클래슀 (μΌλŒ€μΌμ—μ„œ μ£Ό ν…Œμ΄λΈ”μ— ν•΄λ‹Ή)

public class Member {
    @Id
    @Column(name = "MEMBER_ID")
    private Long id;

    @OneToOne
    @JoinColumn(name = "LOCKER_ID")
    private Locker locker;
    
    @Column(name = "USERNAME")
    private String username;
    
	//Getter, Setter, Constructor
}

🎁 Locker 클래슀 (μΌλŒ€μΌμ—μ„œ λŒ€μƒ ν…Œμ΄λΈ”μ— ν•΄λ‹Ή)

public class Locker {
    @Id
    @Column(name = "LOCKER_ID")
    private Long id;

    @Column(name = "NAME")
    private String name;
    
    @OneToOne(mappedBy = "locker")
    private Member member;
    
    //μˆœμˆ˜ν•œ 객체λ₯Ό κ³ λ €ν•œ 연관관계 편의 λ©”μ„œλ“œ
    public void setMember(Member member) {
        if (this.member != null) {
            this.member.setLocker(null);
        }

        this.member = member;
        if (member != null) {
            member.setLocker(this);
        }
    }
    
    //Getter, Setter, Constructor
}

βœ” λŒ€μƒ ν…Œμ΄λΈ”μ— μ™Έλž˜ν‚€λ₯Ό μ €μž₯ν•˜λŠ” μ–‘λ°©ν–₯ 관계일 경우, μ£Ό ν…Œμ΄λΈ”μ— μ™Έλž˜ν‚€λ₯Ό μ €μž₯ν•˜λŠ” μ–‘λ°©ν–₯ 관계일 κ²½μš°μ™€ λ°˜λŒ€λ‘œ μ½”λ“œλ₯Ό μž‘μ„±ν•˜λ©΄ λœλ‹€

πŸ“– λ‹€λŒ€λ‹€(N:N)

JPAμ—μ„œ @ManyToManyλ₯Ό 톡해 λ‹€λŒ€λ‹€ 연관관계λ₯Ό μ œκ³΅ν•˜μ§€λ§Œ, μ‚¬μš©ν•˜μ§€ μ•ŠλŠ” 것을 μΆ”μ²œ ❌

β—½ 쀑간 ν…Œμ΄λΈ”μ΄ 숨겨져 있기 λ•Œλ¬Έμ— μžκΈ°λ„ λͺ¨λ₯΄λŠ” λ³΅μž‘ν•œ 쑰인의 쿼리(Query)κ°€ λ°œμƒν•˜λŠ” κ²½μš°κ°€ 생길 수 있기 λ•Œλ¬Έμ΄λ‹€.
β—½ λ‹€λŒ€λ‹€λ‘œ μžλ™μƒμ„±λœ μ€‘κ°„ν…Œμ΄λΈ”μ€ 두 객체의 ν…Œμ΄λΈ”μ˜ μ™Έλž˜ν‚€λ§Œ μ €μž₯되기 λ•Œλ¬Έμ— λ¬Έμ œκ°€ 될 ν™•λ₯ μ΄ λ†’λ‹€. JPAλ₯Ό 해보면 쀑간 ν…Œμ΄λΈ”μ— μ™Έλž˜ν‚€ 외에 λ‹€λ₯Έ 정보가 λ“€μ–΄κ°€λŠ” κ²½μš°κ°€ 많기 λ•Œλ¬Έμ— λ‹€λŒ€λ‹€λ₯Ό μΌλŒ€λ‹€, λ‹€λŒ€μΌλ‘œ ν’€μ–΄μ„œ λ§Œλ“œλŠ” 것(쀑간 ν…Œμ΄λΈ”μ„ Entity둜 λ§Œλ“œλŠ” 것)이 μΆ”ν›„ 변경에도 μœ μ—°ν•˜κ²Œ λŒ€μ²˜ν•  수 μžˆλ‹€.

βœ” λ‹€λŒ€λ‹€ μ—°κ΄€ 관계λ₯Ό 객체둜 ν‘œν˜„ν•˜κΈ° μœ„ν•΄μ„œλŠ” μ—°κ²° ν…Œμ΄λΈ”μš© μ—”ν‹°ν‹°λ₯Ό μΆ”κ°€ν•˜μ—¬ μΌλŒ€λ‹€, λ‹€λŒ€μΌ κ΄€κ³„λ‘œ ν’€μ–΄λ‚΄μ•Ό ν•œλ‹€.

🎁 @ManyToMany β†’ @OneToMany, @ManyToOne

@Entity
public class Member {
  @Id @Column(name = "MEMBER_ID")
  private String id;

  @OneToMany(mappedBy = "product")
  private List<Order> orders;
}

@Entity //μ—°κ²° ν…Œμ΄λΈ”μš© μ—”ν‹°ν‹°(Order)
public class Order {
  @Id
  @ManyToOne
  @JoinColumn(name = "MEMBER_ID")
  private Member member;

  @Id
  @ManyToOne
  @JoinColumn(name = "PRODUCT_ID")
  private Product product;
}

@Entity
public class Product {
  @Id @Column(name = "PRODUCT_ID")
  private String id;

  @OneToMany(mappedBy = "product")
	private List<Member> members;
}

πŸ“š 참고자료

πŸ“– JPA - Entity
πŸ“– JPA μ—°κ΄€ 관계 ν•œλ°©μ— 정리

profile
κ°€λΏ‘μ΄μ˜ 곡뢀 μƒμžπŸ“¦

0개의 λŒ“κΈ€