Search
Duplicate

관계 λ§€ν•‘

관계 λ§€ν•‘

JPA 관계 λ§€ν•‘ κ°œλ…

JPAμ—μ„œ μ—”ν„°ν‹° κ°„μ˜ 관계λ₯Ό μ„€μ •ν•  λ•Œ μ—°κ΄€ 관계 맀핑을 μ‚¬μš©ν•©λ‹ˆλ‹€. κ΄€κ³„λŠ” λ‹€μŒκ³Ό 같이 λΆ„λ₯˜λ©λ‹ˆλ‹€.
β€’
1:1 (One-To-One) β†’ @OneToOne
β€’
1:N (One-To-Many) β†’ @OneToMany
β€’
N:1 (Many-To-One) β†’ @ManyToOne
β€’
N:M (Many-To-Many) β†’ @ManyToMany
이 쀑 1:N & N:1 κ΄€κ³„λŠ” κ°€μž₯ 많이 μ‚¬μš©λ˜λ©°, μ‹€λ¬΄μ—μ„œλŠ” 쀑간 ν…Œμ΄λΈ”μ„ μ΄μš©ν•œ Many-To-Many ν•΄κ²° 방법이 μΌλ°˜μ μž…λ‹ˆλ‹€.

관계 λ§€ν•‘ μ£Όμš” μ–΄λ…Έν…Œμ΄μ…˜

μ–΄λ…Έν…Œμ΄μ…˜
μ„€λͺ…
@OneToOne
1:1 관계 λ§€ν•‘
@OneToMany
1:N 관계 λ§€ν•‘ (ν•œ 개의 μ—”ν„°ν‹°κ°€ μ—¬λŸ¬ 개의 μ—”ν„°ν‹°λ₯Ό μ°Έμ‘°)
@ManyToOne
N:1 관계 λ§€ν•‘ (μ—¬λŸ¬ 개의 μ—”ν„°ν‹°κ°€ ν•œ 개의 μ—”ν„°ν‹°λ₯Ό μ°Έμ‘°)
@ManyToMany
N:M 관계 λ§€ν•‘ (쀑간 ν…Œμ΄λΈ”μ„ λ³„λ„λ‘œ λ§Œλ“€μ§€ μ•ŠλŠ” 경우 μ‚¬μš©)
@JoinColumn (name="foreign_key")
μ™Έλž˜ ν‚€(FK)λ₯Ό μ§€μ •
@MappedBy
μ–‘λ°©ν–₯ κ΄€κ³„μ—μ„œ λ°˜λŒ€μͺ½ λ§€ν•‘ μ„€μ •
@Cascade(CascadeType.ALL)
μ—°κ΄€λœ μ—”ν„°ν‹°μ˜ μƒνƒœ 변경을 μžλ™μœΌλ‘œ μ „νŒŒ
@Fetch (FetchType.LAZY / FetchType.EAGER)
μ—°κ΄€ 관계 데이터λ₯Ό κ°€μ Έμ˜€λŠ” 방식 μ§€μ • (μ§€μ—° λ‘œλ”©, μ¦‰μ‹œ λ‘œλ”©)

Boards & Files 관계 λ§€ν•‘ 예제 (1:N, N:1 관계 적용)

Boards(κ²Œμ‹œκΈ€)은 μ—¬λŸ¬ 개의 Files(파일)을 κ°€μ§ˆ 수 μžˆμœΌλ―€λ‘œ 1:N 관계가 λ©λ‹ˆλ‹€.

Boards μ—”ν„°ν‹° (κ²Œμ‹œκΈ€)

import jakarta.persistence.*; import lombok.*; import org.springframework.data.annotation.CreatedDate; import org.springframework.data.annotation.LastModifiedDate; import java.time.LocalDateTime; import java.util.List; @Entity @Table(name = "boards") @Getter @Setter @NoArgsConstructor @AllArgsConstructor @Builder public class Boards { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Column(nullable = false, length = 100) private String title; @Column(nullable = false, columnDefinition = "TEXT") private String content; @OneToMany(mappedBy = "board", cascade = CascadeType.ALL, orphanRemoval = true) private List<Files> files; @CreatedDate @Column(updatable = false) private LocalDateTime createdAt; @LastModifiedDate private LocalDateTime updatedAt; }
Java
볡사

Files μ—”ν„°ν‹° (파일)

import jakarta.persistence.*; import lombok.*; @Entity @Table(name = "files") @Getter @Setter @NoArgsConstructor @AllArgsConstructor @Builder public class Files { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long id; @Column(nullable = false) private String fileName; @Column(nullable = false) private String filePath; @ManyToOne @JoinColumn(name = "board_id", nullable = false) private Boards board; }
Java
볡사

관계 λ§€ν•‘ μ„€λͺ…

Boards β†’ Files (1:N 관계)

β€’
BoardsλŠ” μ—¬λŸ¬ 개의 Filesλ₯Ό ν¬ν•¨ν•©λ‹ˆλ‹€.
β€’
@OneToMany(mappedBy = "board")λ₯Ό 톡해 μ–‘λ°©ν–₯ 맀핑을 μ„€μ •ν•©λ‹ˆλ‹€.
β€’
cascade = CascadeType.ALL을 μ‚¬μš©ν•˜λ©΄ Boardsκ°€ μ‚­μ œλ  λ•Œ, μ—°κ΄€λœ Files도 ν•¨κ»˜ μ‚­μ œλ©λ‹ˆλ‹€.
β€’
orphanRemoval = trueλ₯Ό μ„€μ •ν•˜λ©΄ Files μ—”ν„°ν‹°κ°€ Boardsμ—μ„œ 제거될 경우, μžλ™μœΌλ‘œ μ‚­μ œλ©λ‹ˆλ‹€.

Files β†’ Boards (N:1 관계)

β€’
FilesλŠ” ν•˜λ‚˜μ˜ Boards에 μ†ν•©λ‹ˆλ‹€.
β€’
@ManyToOne을 톡해 board_idλΌλŠ” μ™Έλž˜ ν‚€(FK) μ»¬λŸΌμ„ μƒμ„±ν•˜κ³  Boards와 μ—°κ²°ν•©λ‹ˆλ‹€.
β€’
@JoinColumn(name = "board_id")λ₯Ό μ‚¬μš©ν•˜μ—¬ Boards ν…Œμ΄λΈ”μ˜ κΈ°λ³Έ ν‚€(id)와 μ—°κ²°λ©λ‹ˆλ‹€.

JPA 관계 λ§€ν•‘ Best Practice

μ§€μ—° λ‘œλ”© (FetchType.LAZY) μΆ”μ²œ
@ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "board_id", nullable = false) private Boards board;
Java
볡사
β€’
기본적으둜 @ManyToOne은 FetchType.EAGER(μ¦‰μ‹œ λ‘œλ”©)둜 λ™μž‘ν•˜λŠ”λ°, μ΄λŠ” μ„±λŠ₯ μ €ν•˜λ₯Ό μΌμœΌν‚¬ 수 있음.
β€’
FetchType.LAZYλ₯Ό μ‚¬μš©ν•˜μ—¬ μ‹€μ œ 데이터λ₯Ό μ‚¬μš©ν•  λ•Œλ§Œ μ‘°νšŒν•˜λ„λ‘ μ„€μ •.
CascadeType μ„€μ •
@OneToMany(mappedBy = "board", cascade = CascadeType.ALL, orphanRemoval = true) private List<Files> files;
Java
볡사
β€’
CascadeType.ALL을 μ‚¬μš©ν•˜λ©΄ λΆ€λͺ¨ μ—”ν„°ν‹° μ‚­μ œ μ‹œ μžμ‹ 엔터티도 ν•¨κ»˜ μ‚­μ œλ¨.
β€’
orphanRemoval = trueλ₯Ό μ„€μ •ν•˜λ©΄ 관계가 λŠμ–΄μ§„ μžμ‹ μ—”ν„°ν‹°λŠ” μžλ™ μ‚­μ œλ¨.

정리

1.
1:N κ΄€κ³„μ—μ„œ @OneToMany(mappedBy = "board")λ₯Ό μ‚¬μš©ν•˜μ—¬ λΆ€λͺ¨(Boards)κ°€ μžμ‹(Files)을 κ΄€λ¦¬ν•©λ‹ˆλ‹€.
2.
N:1 κ΄€κ³„μ—μ„œ @ManyToOne을 μ‚¬μš©ν•˜μ—¬ μ™Έλž˜ ν‚€(FK) 섀정을 ν•©λ‹ˆλ‹€.
3.
μ§€μ—° λ‘œλ”© (FetchType.LAZY)을 κΈ°λ³Έ μ„€μ •μœΌλ‘œ μ‚¬μš©ν•˜μ—¬ μ„±λŠ₯을 μ΅œμ ν™”ν•©λ‹ˆλ‹€.
4.
CascadeType 및 orphanRemoval μ˜΅μ…˜μ„ ν™œμš©ν•˜μ—¬ μ—”ν„°ν‹° 수λͺ… μ£ΌκΈ°λ₯Ό 효과적으둜 κ΄€λ¦¬ν•©λ‹ˆλ‹€.
이제 Boards 와 Files κ°„μ˜ 관계 맀핑이 μ™„λ£Œλ˜μ—ˆμŠ΅λ‹ˆλ‹€!