Post

[JPA] κ°’ νƒ€μž…

πŸ“Œ λ“€μ–΄κ°€λ©°

JPA의 λ°μ΄ν„°λŠ” 크게 μ—”ν‹°ν‹° νƒ€μž…κ³Ό κ°’ νƒ€μž…μœΌλ‘œ λ‚˜λ‰œλ‹€. 이번 κΈ€μ—μ„œλŠ” κ°’ νƒ€μž…(κΈ°λ³Έκ°’Β·μž„λ² λ””λ“œΒ·μ»¬λ ‰μ…˜)을 μ •λ¦¬ν•œλ‹€.

νƒ€μž…νŠΉμ§•
μ—”ν‹°ν‹° νƒ€μž…@Entity, μ‹λ³„μžλ‘œ 좔적 κ°€λŠ₯ (변해도 좔적)
κ°’ νƒ€μž…μ‹λ³„μž μ—†μŒ, λ³€κ²½ μ‹œ 좔적 λΆˆκ°€

κ°’ νƒ€μž… λΆ„λ₯˜:

1
2
3
4
κ°’ νƒ€μž…
β”œβ”€ κΈ°λ³Έκ°’ νƒ€μž…     int, Integer, String
β”œβ”€ μž„λ² λ””λ“œ νƒ€μž…   기본값을 λͺ¨μ€ 볡합 νƒ€μž… (@Embeddable)
└─ μ»¬λ ‰μ…˜ κ°’ νƒ€μž…  κ°’ νƒ€μž…μ„ μ—¬λŸ¬ 개 (@ElementCollection)

1. κΈ°λ³Έκ°’ νƒ€μž…

int, long, String처럼 λ‹¨μˆœνžˆ κ°’μœΌλ‘œ μ“°λŠ” νƒ€μž…. μ‹λ³„μžκ°€ μ—†μ–΄ λ³€κ²½ μ‹œ 좔적 λΆˆκ°€ν•˜κ³ , 생λͺ…μ£ΌκΈ°κ°€ 엔티티에 μ˜μ‘΄ν•œλ‹€.

⚠️ κ°’ νƒ€μž…μ€ κ³΅μœ ν•˜λ©΄ μ•ˆ λœλ‹€. κ°’ 볡사(call by value)둜 닀뀄야 μ‚¬μ΄λ“œ μ΄νŽ™νŠΈκ°€ μ—†λ‹€.


2. μž„λ² λ””λ“œ νƒ€μž… (@Embeddable)

κΈ°λ³Έκ°’ νƒ€μž…μ„ λͺ¨μ•„μ„œ λ§Œλ“  볡합 νƒ€μž…(예: μ£Όμ†Œ = λ„μ‹œ+거리+우편번호). μƒˆλ‘œμš΄ κ°’ νƒ€μž…μ„ μ‚¬μš©μž μ •μ˜λ‘œ λ§Œλ“ λ‹€.

1
2
3
4
5
@Embeddable          // κ°’ νƒ€μž… μ •μ˜ν•˜λŠ” κ³³
public class Address { ... }

@Embedded            // κ°’ νƒ€μž… μ‚¬μš©ν•˜λŠ” κ³³
private Address address;

⚠️ κΈ°λ³Έ μƒμ„±μž ν•„μˆ˜. 그리고 μ—¬λŸ¬ μ—”ν‹°ν‹°μ—μ„œ κ³΅μœ ν•˜λ©΄ μœ„ν—˜ν•˜λ‹€. μž„λ² λ””λ“œ 값이 λ°”λ€Œλ©΄ 그것을 μ°Έμ‘°ν•˜λŠ” λͺ¨λ“  μ—”ν‹°ν‹°μ˜ 값이 ν•¨κ»˜ λ°”λ€ŒκΈ° λ•Œλ¬Έ. 같은 값을 λ„£κ³  μ‹ΆμœΌλ©΄ μƒˆ μž„λ² λ””λ“œλ₯Ό λ§Œλ“€μ–΄ κ°’ λ³΅μ‚¬ν•˜μž.

μž₯점섀λͺ…
μž¬μ‚¬μš©μ—¬λŸ¬ μ—”ν‹°ν‹°μ—μ„œ μ‚¬μš©
높은 응집도관련 값을 ν•˜λ‚˜λ‘œ 묢음
의미 μžˆλŠ” λ©”μ†Œλ“œPeriod.isWork() 같은 λ©”μ†Œλ“œ

πŸ’‘ μž„λ² λ””λ“œ νƒ€μž…μ„ 써도 λ§€ν•‘ ν…Œμ΄λΈ”μ€ κ·ΈλŒ€λ‘œλ‹€. 클래슀만 μ„Έλ°€ν•˜κ²Œ λ‚˜λ‰  뿐이닀. (잘 μ„€κ³„ν•œ ORM은 ν…Œμ΄λΈ”λ³΄λ‹€ 클래슀 μˆ˜κ°€ λ§Žλ‹€) 같은 κ°’ νƒ€μž…μ„ ν•œ μ—”ν‹°ν‹°μ—μ„œ μ—¬λŸ¬ 번 μ“°λ©΄ 컬럼λͺ…이 μ€‘λ³΅λ˜λ―€λ‘œ @AttributeOverride둜 μž¬μ •μ˜ν•œλ‹€.


3. λΆˆλ³€ 객체둜 λ§Œλ“€κΈ°

⚠️ κ°’ νƒ€μž…μ˜ 곡유 사고λ₯Ό μ›μ²œ μ°¨λ‹¨ν•˜λ €λ©΄ λΆˆλ³€ 객체둜 λ§Œλ“ λ‹€. μƒμ„±μžλ‘œλ§Œ 값을 μ„€μ •ν•˜κ³  Setterλ₯Ό λ§Œλ“€μ§€ μ•ŠμœΌλ©΄ λœλ‹€.


4. κ°’ νƒ€μž… 비ꡐ

λΉ„κ΅λ°©λ²•λŒ€μƒ
동일성==μ°Έμ‘°κ°’ 비ꡐ
동등성equals()μΈμŠ€ν„΄μŠ€ κ°’ 비ꡐ

πŸ’‘ κ°’ νƒ€μž…μ€ equals()λ₯Ό μž¬μ •μ˜ν•΄ 동등성 λΉ„κ΅ν•˜λŠ” 게 μ’‹λ‹€. μž¬μ •μ˜ μ‹œ ν•„λ“œ 직접 접근보닀 getterλ₯Ό μ“°μž(ν”„λ‘μ‹œ 객체일 λ•Œ ν•„λ“œ 직접 접근이 μ•ˆ 되기 λ•Œλ¬Έ).

1
2
3
4
5
6
7
8
9
10
11
@Override
public boolean equals(Object o) {
    if (this == o) return true;
    if (o == null || getClass() != o.getClass()) return false;
    Address a = (Address) o;
    return Objects.equals(getCity(), a.getCity())
        && Objects.equals(getStreet(), a.getStreet())
        && Objects.equals(getZipcode(), a.getZipcode());
}
@Override
public int hashCode() { return Objects.hash(getCity(), getStreet(), getZipcode()); }

5. κ°’ νƒ€μž… μ»¬λ ‰μ…˜

κ°’ νƒ€μž…μ„ ν•˜λ‚˜ 이상 μ €μž₯ν•  λ•Œ @ElementCollection, @CollectionTable을 μ“΄λ‹€. DBλŠ” μ»¬λ ‰μ…˜μ„ ν•œ ν…Œμ΄λΈ”μ— λͺ» λ„£μœΌλ―€λ‘œ 별도 ν…Œμ΄λΈ”μ΄ ν•„μš”ν•˜λ‹€.

πŸ’‘ μ»¬λ ‰μ…˜μ€ μ†Œμœ  μ—”ν‹°ν‹°κ°€ 생λͺ…μ£ΌκΈ°λ₯Ό μ •ν•˜λ―€λ‘œ, Cascade + κ³ μ•„ 객체 μ œκ±°κ°€ ν•¨κ»˜ μžˆλŠ” 것과 κ°™λ‹€. μ§€μ—° λ‘œλ”©μ΄λ©°, μˆ˜μ •ν•  λ•ŒλŠ” μƒˆ 객체둜 ν†΅μ§Έλ‘œ κ°ˆμ•„ λΌμ›Œμ•Ό ν•œλ‹€.

1
2
3
4
// βœ… μƒˆ 객체둜 ꡐ체
findMember.setAddress(new Address("newCity", addr.getStreet(), addr.getZipcode()));
// ❌ μ ˆλŒ€ μ΄λ ‡κ²Œ ν•˜λ©΄ μ•ˆ 됨
findMember.getAddress().setCity("newCity");

⚠️ κ°’ νƒ€μž… μ»¬λ ‰μ…˜μ˜ μ œμ•½: μ‹λ³„μžκ°€ μ—†μ–΄ λ³€κ²½ 좔적이 μ–΄λ ΅λ‹€. 변경이 λ°œμƒν•˜λ©΄ μ—°κ΄€λœ 데이터λ₯Ό μ „λΆ€ μ‚­μ œν•˜κ³  ν˜„μž¬ 값을 λͺ¨λ‘ λ‹€μ‹œ μ €μž₯ν•œλ‹€(λΉ„νš¨μœ¨). κΈ°λ³Έν‚€λŠ” λͺ¨λ“  μ»¬λŸΌμ„ λ¬Άμ–΄ ꡬ성(null·쀑볡 λΆˆκ°€).

1
2
3
4
-- ν•˜λ‚˜ λ°”κΏ¨λŠ”λ° μ „λΆ€ μ‚­μ œ ν›„ μž¬μ‚½μž…!
delete from ADDRESS where MEMBER_ID=?
insert into ADDRESS (...) values (...)
insert into ADDRESS (...) values (...)

λŒ€μ•ˆ β€” μΌλŒ€λ‹€ 관계

πŸ’‘ μ‹€λ¬΄μ—μ„œλŠ” κ°’ νƒ€μž… μ»¬λ ‰μ…˜ λŒ€μ‹  μΌλŒ€λ‹€(μ—”ν‹°ν‹°) 관계λ₯Ό κ³ λ €ν•œλ‹€. κ°’ νƒ€μž…μ„ μ—”ν‹°ν‹°λ‘œ μŠΉκ²©μ‹œμΌœ @OneToMany + Cascade + orphanRemoval둜 κ΄€λ¦¬ν•œλ‹€.

1
2
3
// Member
@OneToMany(mappedBy = "member", cascade = CascadeType.ALL, orphanRemoval = true)
private List<AddressEntity> addressEntityList = new ArrayList<>();

πŸ“ 정리

1
2
3
4
5
6
JPA κ°’ νƒ€μž…
β”œβ”€ κΈ°λ³Έκ°’    int/String, 좔적 λΆˆκ°€, 곡유 κΈˆμ§€
β”œβ”€ μž„λ² λ””λ“œ  @Embeddable/@Embedded, λΆˆλ³€μœΌλ‘œ (Setter X)
β”œβ”€ 비ꡐ      equals() μž¬μ •μ˜ (getter μ‚¬μš©)
β”œβ”€ μ»¬λ ‰μ…˜    @ElementCollection, λ³€κ²½ μ‹œ 전체 μ‚­μ œΒ·μž¬μ‚½μž…
└─ λŒ€μ•ˆ      μ‹€λ¬΄λŠ” μΌλŒ€λ‹€ μ—”ν‹°ν‹° 관계
κ°œλ…ν•œ 쀄 μ •μ˜
μž„λ² λ””λ“œ νƒ€μž…κ°’μ„ λͺ¨μ€ 볡합 κ°’ νƒ€μž…
λΆˆλ³€ 객체Setter 없이 μƒμ„±μžλ‘œλ§Œ
κ°’ νƒ€μž… μ»¬λ ‰μ…˜λΉ„νš¨μœ¨μ (전체 μž¬μ‚½μž…) β†’ μΌλŒ€λ‹€ ꢌμž₯

κ°’ νƒ€μž…μ˜ 핡심은 β€œκ³΅μœ ν•˜μ§€ 말고, λΆˆλ³€μœΌλ‘œ λ§Œλ“€λΌβ€λ‹€. 특히 κ°’ νƒ€μž… μ»¬λ ‰μ…˜μ€ λ³€κ²½ μ‹œ 전체λ₯Ό μ‚­μ œΒ·μž¬μ‚½μž…ν•˜λŠ” λΉ„νš¨μœ¨μ΄ μžˆμ–΄, μ‹€λ¬΄μ—μ„œλŠ” μΌλŒ€λ‹€ μ—”ν‹°ν‹° κ΄€κ³„λ‘œ ν’€μ–΄λ‚΄λŠ” 것이 정석이닀.

This post is licensed under CC BY 4.0 by the author.

Comments powered by Disqus.