κ΄κ³ λ§€ν
JPA κ΄κ³ λ§€ν κ°λ
JPAμμ μν°ν° κ°μ κ΄κ³λ₯Ό μ€μ ν λ μ°κ΄ κ΄κ³ λ§€νμ μ¬μ©ν©λλ€. κ΄κ³λ λ€μκ³Ό κ°μ΄ λΆλ₯λ©λλ€.
β’
β’
β’
β’
μ΄ μ€ 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
@ManyToOne(fetch = FetchType.LAZY)
@JoinColumn(name = "board_id", nullable = false)
private Boards board;
Java
볡μ¬
β’
κΈ°λ³Έμ μΌλ‘ @ManyToOneμ FetchType.EAGER(μ¦μ λ‘λ©)λ‘ λμνλλ°, μ΄λ μ±λ₯ μ νλ₯Ό μΌμΌν¬ μ μμ.
β’
FetchType.LAZYλ₯Ό μ¬μ©νμ¬ μ€μ λ°μ΄ν°λ₯Ό μ¬μ©ν λλ§ μ‘°ννλλ‘ μ€μ .
@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 κ°μ κ΄κ³ λ§€νμ΄ μλ£λμμ΅λλ€! 