# [JPA] κ°’ νƒ€μž… - μž„λ² λ””λ“œ κ°’ νƒ€μž…, μ»¬λ ‰μ…˜ κ°’ νƒ€μž…
Study Repository

[JPA] κ°’ νƒ€μž… - μž„λ² λ””λ“œ κ°’ νƒ€μž…, μ»¬λ ‰μ…˜ κ°’ νƒ€μž…

by rlaehddnd0422

JPA의 데이터 νƒ€μž…μ—λŠ” 크게 μ—”ν‹°ν‹° νƒ€μž…, κ°’ νƒ€μž…μœΌλ‘œ λ‚˜λˆŒ 수 μžˆμŠ΅λ‹ˆλ‹€.

// μ—”ν‹°ν‹° νƒ€μž… 
@Entity
public class Member{

    @Id 
    private Long id; // κ°’ νƒ€μž…

    private String name; // κ°’ νƒ€μž…

    @Embedded
    private Address address; // μž„λ² λ””λ“œ κ°’ νƒ€μž…

    private List<Address> addressHistory; // μ»¬λ ‰μ…˜ κ°’ νƒ€μž… 

}
  • μ—”ν‹°ν‹° νƒ€μž… : λ‹¨μˆœνžˆ @Entity둜 μ •μ˜ν•˜λŠ” 객체
  • κ°’ νƒ€μž… : λ‹¨μˆœν•œ 수치 정보
    • λ‹¨μˆœ κ°’ νƒ€μž… : int, double, String, Integer 
    • μž„λ² λ””λ“œ κ°’ νƒ€μž… : μ‚¬μš©μž μ •μ˜ νƒ€μž… @Embedded
    • μ»¬λ ‰μ…˜ κ°’ νƒ€μž… : List, Set, Map κ³Ό 같은 μ»¬λ ‰μ…˜μ„ μ‚¬μš©ν•œ νƒ€μž… 

κ°’ νƒ€μž… νŠΉμ§•

  • μ—”ν‹°ν‹° νƒ€μž…μ€ μ‹λ³„μž 값을 톡해 좔적이 κ°€λŠ₯ν•˜λ‹€λŠ” 점에 λ°˜ν•΄, κ°’ νƒ€μž…μ€ λ‹¨μˆœν•œ μˆ˜μΉ˜μ •λ³΄μ΄κΈ° λ•Œλ¬Έμ— μ‹λ³„μžλ‘œ 좔적이 λΆˆκ°€λŠ₯ν•©λ‹ˆλ‹€.
  • 생λͺ…μ£ΌκΈ°λ₯Ό 엔티티에 μ˜μ‘΄ν•©λ‹ˆλ‹€. 즉, μ—”ν‹°ν‹°κ°€ μ‚­μ œλ˜λ©΄ κ°’νƒ€μž…μ€ μžλ™μœΌλ‘œ 같이 μ œκ±°λ©λ‹ˆλ‹€.
    • μ—”ν‹°ν‹°λŠ” 생성, μ˜μ†ν™”, μ†Œλ©Έν•˜λŠ” 생λͺ…μ£ΌκΈ°κ°€ μžˆμŠ΅λ‹ˆλ‹€.

μž„λ² λ””λ“œ κ°’ νƒ€μž… ( 볡합 κ°’ νƒ€μž…)

μƒˆλ‘œμš΄ κ°’ νƒ€μž…μ„ 직접 μ •μ˜ν•΄μ„œ μ‚¬μš©ν•˜λŠ” νƒ€μž…μž…λ‹ˆλ‹€. μž„λ² λ””λ“œ νƒ€μž…λ„ λ§ˆμ°¬κ°€μ§€λ‘œ κ°’ νƒ€μž…μ„ ν¬ν•¨ν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€.

@Embeddable
public class Address {

	private String city; // κ°’ νƒ€μž…
	private String street; // κ°’ νƒ€μž…
    ...
}

Member 엔티티에 city, street으둜 상세 데이터λ₯Ό κ°–λŠ” 것보닀 μž„λ² λ””λ“œ νƒ€μž…μ„ μ‚¬μš©ν•΄μ„œ μ •μ˜ν•˜λŠ” 것이 κ°€λ…μ„±μ΄λ‚˜, 객체지ν–₯ μΈ‘λ©΄μ—μ„œ μ’‹μŠ΅λ‹ˆλ‹€.

뿐만 μ•„λ‹ˆλΌ μƒˆλ‘œ μ •μ˜ν•œ κ°’ νƒ€μž…μΈ AddressλŠ” 클래슀이기 λ•Œλ¬Έμ— μž¬μ‚¬μš©λ„ κ°€λŠ₯ν•˜κ³ , 응집도도 μ•„μ£Ό λ†’μŠ΅λ‹ˆλ‹€.

μž„λ² λ””λ“œ κ°’ νƒ€μž…μ€ κΈ°λ³Έ μƒμ„±μžκ°€ ν•„μˆ˜μ μœΌλ‘œ μžˆμ–΄μ•Ό ν•©λ‹ˆλ‹€.

 μž„λ² λ””λ“œ κ°’ νƒ€μž…μ€ κ°’ νƒ€μž…μ„ 포함할 뿐만 μ•„λ‹ˆλΌ μ—”ν‹°ν‹°λ₯Ό μ°Έκ³ ν•˜λŠ” 것도 κ°€λŠ₯ν•©λ‹ˆλ‹€.

@Embeddable
public class Address {

    private String city; // κ°’ νƒ€μž…
    private String street; // κ°’ νƒ€μž…
    ...

    @Embedded
    private ZipCode zipcode; // μž„λ² λ””λ“œ νƒ€μž… 포함

    @ManyToOne
    private State state; // μ—”ν‹°ν‹° μ°Έμ‘° 
}

+ @AttributeOverrideλ₯Ό μ‚¬μš©ν•΄ 맀핑 정보λ₯Ό μž¬μ •μ˜ ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

@Entity
public class Member{

    @Id @GeneratedValue
    private Long id;

    private String name;

    @Embedded
    private Address address;

    @Embedded
    @AttributeOverrides({ 
    @AttributeOverride(name="city", column=@Column(name="COMPANY_CITY")),
    @AttributeOverride(name="street", column=@Column(name="COMPANY_STREET")),
    @AttributeOverride(name="zipcode", column=@Column(name="COMPANY_ZIPCODE"))})
    private Address companyAddress;

}
  • 맀핑정보λ₯Ό μž¬μ •μ˜ν•˜λŠ” κ²½μš°λŠ” λ“œλ¬ΌκΈ΄ ν•©λ‹ˆλ‹€λ§Œ, μž„λ² λ””λ“œ νƒ€μž…μ„ ν•œ μ—”ν‹°ν‹°μ—μ„œ μž¬μ‚¬μš©ν•˜λŠ” 경우 @AttributeOverride둜 맀핑정보(컬럼λͺ…)을 μž¬μ •μ˜ ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

+ μž„λ² λ””λ“œ νƒ€μž…μ„ null둜 μ„€μ •ν•˜λ©΄ νƒ€μž… λ‚΄λΆ€ λͺ¨λ“  κ°’ νƒ€μž…μ΄ null둜 μ„€μ •λ©λ‹ˆλ‹€.

member.setAddress(null);
em.persist(member);
// -> member.address.city = null
// -> member.address.street = null
// -> member.address.zipcode = null

μž„λ² λ””λ“œ κ°’ νƒ€μž… μ‚¬μš©μ‹œ μ£Όμ˜ν•  점

μž„λ² λ””λ“œ κ°’ νƒ€μž… μ‚¬μš© μ‹œ μ£Όμ˜ν•΄μ•Ό ν•  점이 μžˆμŠ΅λ‹ˆλ‹€.

1. κ°’ νƒ€μž…μ€ κ³΅μœ λ˜μ–΄μ„œλŠ” μ•ˆλ©λ‹ˆλ‹€.

  • νšŒμ›1.address.city = "OldCity" 
  • add = νšŒμ›1.getAddress()
  • νšŒμ›2.setAddress(add) 
  • νšŒμ›2.address.city = "NewCity"
  • νšŒμ›1의 city도 NewCity둜 변경됨 ( 곡유 μ°Έμ‘° λΆ€μž‘μš© )

μž„λ² λ””λ“œ κ°’ νƒ€μž…λ„ 객체이기 λ•Œλ¬Έμ— 곡유되게 되면 μžλ°”μ—μ„œλŠ” μΈμŠ€ν„΄μŠ€ 값을 κ³΅μœ ν•˜λŠ” 것이 μ•„λ‹ˆλΌ μ°Έμ‘°λ₯Ό κ³΅μœ ν•˜κ²Œ λ©λ‹ˆλ‹€. 

 

μ°Έμ‘°λ₯Ό κ³΅μœ ν•˜κ²Œ 되면 μž„λ² λ””λ“œ νƒ€μž… λ‚΄λΆ€ 값이 λ³€κ²½λ˜λ©΄ ν•΄λ‹Ή μΈμŠ€ν„΄μŠ€λ₯Ό κ³΅μœ ν•΄μ„œ μ‚¬μš©ν•˜λŠ” μ—”ν‹°ν‹°λ“€μ˜ 값이 μ „λΆ€ Update λ˜λŠ” λΆ€μž‘μš©μ΄ λ°œμƒν•©λ‹ˆλ‹€.

 

곡유 참쑰둜 λ°œμƒν•˜λŠ” λ²„κ·ΈλŠ” 정말 μ°Ύμ•„λ‚΄κΈ° μ–΄λ ΅κΈ° λ•Œλ¬Έμ—, μž„λ² λ””λ“œ νƒ€μž…μ˜ μΈμŠ€ν„΄μŠ€λŠ” κ³΅μœ ν•΄μ„œ μ‚¬μš©ν•˜μ§€ μ•Šλ„λ‘ ν•©μ‹œλ‹€.

 

λ‹¨νŽΈμ μΈ 해결방법 : κ³΅μœ ν•˜λŠ” λŒ€μ‹  μΈμŠ€ν„΄μŠ€λ₯Ό λ³΅μ‚¬ν•΄μ„œ μ‚¬μš©ν•˜λŠ” 방법이 μžˆμŠ΅λ‹ˆλ‹€.

μžλ°”λŠ” κΈ°λ³Έ κ°’ νƒ€μž…μ€ 값을 λ³΅μ‚¬ν•΄μ„œ λ„˜κΈ°μ§€λ§Œ, 객체 νƒ€μž…μ€ 참쑰만 λ„˜κΉλ‹ˆλ‹€.

ν•˜μ§€λ§Œ λ³„λ„μ˜ λ©”μ†Œλ“œλ‘œ ν•΄λ‹Ή 객체 νƒ€μž…μ΄ μ°Έμ‘°κ°€ μ•„λ‹Œ μΈμŠ€ν„΄μŠ€μ˜ 값을 λ„˜κΈ°λ„λ‘ κ΅¬ν˜„ν•΄μ„œ 볡사할 수 μžˆμŠ΅λ‹ˆλ‹€.

member.setAddress(new Address("μ „μ£Ό", "κΈˆμ•”λ™", "λͺ…λ₯œ1κΈΈ");
Address address = member.getAddress();

Address address2 = address.clone(); // clone() λ©”μ†Œλ“œμ— μ°Έμ‘°κ°€ μ•„λ‹Œ μΈμŠ€ν„΄μŠ€μ˜ 값을 λ³΅μ‚¬ν•˜λ„λ‘ κ΅¬ν˜„ 

address.setZipcode("λͺ…λ₯œ2κΈΈ");
member2.setAddress(address2);

 

ν•˜μ§€λ§Œ 이것이 곡유 μ°Έμ‘°λ₯Ό λ§‰λŠ” 근본적인 해결책은 μ•„λ‹ˆμ£ . 곡유 μ°Έμ‘°λ₯Ό λ§‰μœΌλ €λ©΄ 근본적으둜 객체λ₯Ό λΆˆλ³€ν•˜κ²Œ ν•΄μ•Όν•©λ‹ˆλ‹€.

 

근본적인 해결방법 : μˆ˜μ •μž λ©”μ†Œλ“œ 제거.

@Embedded
public class Address{

    private String city;
    private String street;
    private String zipcode;

    public Address(String city,String street,String zipcode)
    {
        this.city = city;
        this.street = street;
        this.zipcode = zipcode;
    }

	// setter X
}

객체λ₯Ό λΆˆλ³€ν•˜κ²Œ ν•œλ‹€.. 객체λ₯Ό λΆˆλ³€ν•˜κ²Œ ν•˜λ €λ©΄ ν•œ 번 μƒμ„±λœ 객체의 μˆ˜μ •μ„ λ§‰μœΌλ©΄ λ©λ‹ˆλ‹€.

μ‰½κ²Œ λ§ν•΄μ„œ, κΈ°λ³Έ μƒμ„±μžλ§Œ λ§Œλ“€κ³  setterλŠ” μ‚¬μš©ν•˜μ§€ μ•ŠλŠ” 것이죠.

 

객체λ₯Ό λΆˆλ³€ν•˜κ²Œ λ§Œλ“€λ©΄ 값을 μˆ˜μ •ν•  수 μ—†μœΌλ―€λ‘œ λΆ€μž‘μš©μ„ μ›μ²œμ— 차단할 수 μžˆμŠ΅λ‹ˆλ‹€. λ”°λΌμ„œ κ°’ νƒ€μž…μ€ κ°€λŠ₯ν•œ λΆˆλ³€κ°μ²΄λ‘œ μ„€κ³„ν•˜λ„λ‘ ν•©μ‹œλ‹€.

 

2. μž„λ² λ””λ“œ κ°’ νƒ€μž… 비ꡐ μ‹œ equals와 hashCode λ©”μ†Œλ“œλ₯Ό μž¬μ •μ˜ ν•΄μ£Όμ–΄μ•Ό ν•©λ‹ˆλ‹€.

μž„λ² λ””λ“œ κ°’ νƒ€μž…μ€ κ²°κ΅­ κ°μ²΄μž…λ‹ˆλ‹€.

μžλ°”μ—μ„œλŠ” κΈ°λ³Έ κ°’ νƒ€μž…μ— λŒ€ν•΄μ„œ 비ꡐ할 λ•Œ, 동등성을 λΉ„κ΅ν•˜κ³ , 객체 νƒ€μž…μ— λŒ€ν•΄ 비ꡐ할 λ•ŒλŠ” 동등성을 λΉ„κ΅ν•©λ‹ˆλ‹€.

 

μ—¬κΈ°μ„œ λ™μΌμ„±μ΄λž€ μΈμŠ€ν„΄μŠ€μ˜ 값을 λΉ„κ΅ν•œλ‹€λŠ” 것이고, 동등성은 μΈμŠ€ν„΄μŠ€μ˜ μ°Έμ‘° 값을 λΉ„κ΅ν•œλ‹€λŠ” λœ»μž…λ‹ˆλ‹€.

 

일반적으둜 μš°λ¦¬λŠ” 두 값을 비ꡐ할 λ•Œ 참쑰값을 λΉ„κ΅ν•˜λŠ” 것이 μ•„λ‹ˆλΌ, μΈμŠ€ν„΄μŠ€κ°€ λ‚΄ν¬ν•˜κ³  μžˆλŠ” κ°’ κ·Έ 자체λ₯Ό λΉ„κ΅ν•©λ‹ˆλ‹€. ν•˜μ§€λ§Œ μžλ°”λŠ” 객체에 λŒ€ν•΄μ„œλŠ” 기본적으둜 동등성을 λΉ„κ΅ν•œλ‹€κ³  ν–ˆμŠ΅λ‹ˆλ‹€.

 

λ”°λΌμ„œ μš°λ¦¬κ°€ 두 μž„λ² λ””λ“œ κ°’ νƒ€μž…μ„ 비ꡐ할 λ•Œ 동등성이 μ•„λ‹Œ 동일성을 κΈ°μ€€μœΌλ‘œ λΉ„κ΅ν•˜κ³  μ‹Άλ‹€κ³  ν•˜λ©΄ equals, hashCode λ©”μ†Œλ“œλ₯Ό μž¬μ •μ˜ν•΄ 쀌으둜써, λͺ¨λ“  ν•„λ“œμ˜ 값을 λΉ„κ΅ν•˜λ„λ‘ κ΅¬ν˜„ν•΄μ„œ 동일성을 λΉ„κ΅ν•˜λ„λ‘ μ„€μ •ν•΄μ£Όμ–΄μ•Ό ν•©λ‹ˆλ‹€. 

 

How to Override

 

동일성과 동등성 (feat. equals와 hashCode)

동일성과 동등성

velog.io

 


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

κ°’ νƒ€μž…μ„ ν•˜λ‚˜μ΄μƒ μ €μž₯ν•  λ•Œ μ»¬λ ‰μ…˜μ— λ³΄κ΄€ν•˜μ—¬ μ»¬λ ‰μ…˜μ„ κ°’ νƒ€μž…μ²˜λŸΌ μ‚¬μš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

이 λ•Œ @ElementCollection , @CollectionTable μ–΄λ…Έν…Œμ΄μ…˜μ΄ μ‚¬μš©λ©λ‹ˆλ‹€.

@Entity
public class Member {

    @Id
    private Long id;

    private String name;

    @Embedded // μž„λ² λ””λ“œ κ°’ νƒ€μž…
    private Address address;

    @ElementCollection
    @CollectionTable(name = "ADDRESS",
                    joinColumns = @JoinColumn(name = "MEMBER_ID"))
    @Column(name="HISTORY_HOME")
    private List<Address> addressHistory = new ArrayList<Address>();

    ...

}
  • @ElementCollection : μ»¬λ ‰μ…˜ κ°’ νƒ€μž… 맀핑을 μœ„ν•΄ μ‚¬μš©λ˜λŠ” μ–΄λ…Έν…Œμ΄μ…˜
  • μ»¬λ ‰μ…˜μ€ T을 μ»¬λ ‰μ…˜μœΌλ‘œ 가지기 λ•Œλ¬Έμ— λ³„λ„μ˜ ν…Œμ΄λΈ”μ„ μΆ”κ°€ν•˜κ³  ν…Œμ΄λΈ”μ„ 맀핑해야 ν•©λ‹ˆλ‹€.
    • @CollectionTable : μ»¬λ ‰μ…˜ κ°’ νƒ€μž…μ„ ν…Œμ΄λΈ”κ³Ό λ§€ν•‘ν•΄μ£ΌλŠ” μ–΄λ…Έν…Œμ΄μ…˜μœΌλ‘œ 이 μ–΄λ…Έν…Œμ΄μ…˜μ„ 톡해 μ»¬λ ‰μ…˜κ³Ό ν…Œμ΄λΈ”μ„ 맀핑할 수 μžˆμŠ΅λ‹ˆλ‹€. ( 이 μ–΄λ…Έν…Œμ΄μ…˜ μƒλž΅ μ‹œ κΈ°λ³Έκ°’(엔티티이름_μ»¬λ ‰μ…˜ 속성이름)으둜 μ„€μ •λœ ν…Œμ΄λΈ”κ³Ό μžλ™ λ§€ν•‘ν•©λ‹ˆλ‹€. )

κ°’ νƒ€μž… μ»¬λ ‰μ…˜ μ €μž₯ μ‹œ μ˜μ†μ„± 전이 + κ³ μ•„ 객체 제거 κΈ°λŠ₯은 μžλ™μœΌλ‘œ 가지고 μžˆμŠ΅λ‹ˆλ‹€.

μ—”ν‹°ν‹°λ₯Ό μ˜μ†ν™” ν•΄λ΄…μ‹œλ‹€.

@Entity
public class Member {

    @Id
    private Long id;

    private String name;

    @Embedded // μž„λ² λ””λ“œ κ°’ νƒ€μž…
    private Address address;

    @ElementCollection
    @CollectionTable(name = "ADDRESS",
                    joinColumns = @JoinColumn(name = "MEMBER_ID"))
    @Column(name="HISTORY_HOME")
    private List<Address> addressHistory = new ArrayList<Address>();

    ...

}
member.setName("kim");
member.setAddress(new Address("μ „μ£Ό","κΈˆμ•”","λͺ…λ₯œ1"));
member.getAddressHistory().add(new Address("μ „μ£Ό","객사","82")); 
em.persist(member);

persist 호좜 ν›„ commitν•˜μ—¬ flushν•˜κ²Œ 되면 2번의 SQL이 μ‹€ν–‰λ©λ‹ˆλ‹€.

insert into MEMBER (id, name, city, street, zipcode) values(1, 'kim', 'μ „μ£Ό', 'κΈˆμ•”', 'λͺ…λ₯œ1');
insert into ADDRESS (id, city, street, zipcode) values(1,'μ „μ£Ό', '객사', '82');

JPAλŠ” κ°’ νƒ€μž…λ„ ν•¨κ»˜ μ˜μ†ν™” ν•˜κΈ° λ•Œλ¬Έμ— κ°’ νƒ€μž… μ»¬λ ‰μ…˜κ³Ό λ§€ν•‘λœ ν…Œμ΄λΈ”μ—λ„ insert sql이 μ‹€ν–‰λ©λ‹ˆλ‹€.

 

+  κ°’ νƒ€μž… μ»¬λ ‰μ…˜μ„ μ‘°νšŒν•  λ•Œλ„ λ‹Ήμ—°νžˆ 패치 μ „λž΅μ„ μ‚¬μš©ν•  수 μžˆλŠ”λ° JPAλŠ” 기본적으둜 κ°’ νƒ€μž… μ»¬λ ‰μ…˜μ„ μ§€μ—°λ‘œλ”©(LAZY)둜 μ„€μ •ν•΄ λ‘μ—ˆμŠ΅λ‹ˆλ‹€.

Member member = em.find(Member.class, 1L);

List<Address> addressHistory = member.getAddressHistory();

addressHistory.get(0); // μ‹€μ œ μ‚¬μš© μ‹œ ν˜ΈμΆœν•˜λŠ” LAZY μ „λž΅μ΄ κΈ°λ³Έ 적용.

κ°’ νƒ€μž… μ»¬λ ‰μ…˜μ€ 기본적으둜 μ§€μ—°λ‘œλ”©μœΌλ‘œ μ„€μ •λ˜μ–΄ 있기 λ•Œλ¬Έμ—, μ‹€μ œ μ»¬λ ‰μ…˜μ„ μ‚¬μš©ν•  λ•Œ SELECT SQL을 1번 ν˜ΈμΆœν•©λ‹ˆλ‹€.

 

+ κ°’ νƒ€μž… μ»¬λ ‰μ…˜μ€ μ»¬λ ‰μ…˜μ— λ³€κ²½ 사항 λ°œμƒ μ‹œ μ—°κ΄€λœ λͺ¨λ“  데이터λ₯Ό μ‚­μ œν•˜κ³ , λ³€κ²½ μ‚¬ν•­μœΌλ‘œ λ‹€μ‹œ μ €μž₯ν•©λ‹ˆλ‹€.

κ°’ νƒ€μž… μ»¬λ ‰μ…˜μ— λ³΄κ΄€λœ κ°’ νƒ€μž…λ“€μ€ λ³„λ„μ˜ ν…Œμ΄λΈ”μ— λ³΄κ΄€λ©λ‹ˆλ‹€.

 

λ”°λΌμ„œ 여기에 λ³΄κ΄€λœ κ°’ νƒ€μž…μ˜ 값이 λ³€κ²½λ˜λ©΄ λ°μ΄ν„°λ² μ΄μŠ€μ— μžˆλŠ” 원본 데이터λ₯Ό μ°ΎκΈ° μ–΄λ ΅λ‹€λŠ” λ¬Έμ œκ°€ μžˆμŠ΅λ‹ˆλ‹€.

 

JPAλŠ” 이 문제λ₯Ό ν•΄κ²°ν•˜κΈ° μœ„ν•΄ κ°’ νƒ€μž… μ»¬λ ‰μ…˜μ˜ 변경사항이 생기면, κ°’ νƒ€μž… μ»¬λ ‰μ…˜κ³Ό λ§€ν•‘λœ ν…Œμ΄λΈ”μ˜ λͺ¨λ“  데이터λ₯Ό μ‚­μ œν•˜κ³ , ν˜„μž¬ κ°’ νƒ€μž… μ»¬λ ‰μ…˜ 객체에 μžˆλŠ” λͺ¨λ“  값을 λ°μ΄ν„°λ² μ΄μŠ€μ— μ €μž₯ν•©λ‹ˆλ‹€.

Memberm member = em.find(Member.class, 100L); 
List<Address> addressHistory = member.getAddressHistory(); 
addressHistory.add(new Address('μ „μ£Ό','집1','κΈΈ1'));
addressHistory.add(new Address('μ „μ£Ό','집2','κΈΈ2'));
em.persist(member);

// commit ν›„ μ‹€ν–‰λ˜λŠ” SQL
select from member where member_id = 100


// 기쑴의 λͺ¨λ“  데이터λ₯Ό μ‚­μ œ
delete from address where member_id = 100


// λ‹€μ‹œ μ €μž₯ 
insert into address (member_id, city, street, zipcode) values(100L, ...)
insert into address (member_id, city, street, zipcode) values(100L, ...)

 

λ”°λΌμ„œ μ‹€λ¬΄μ—μ„œλŠ” κ°’ νƒ€μž… μ»¬λ ‰μ…˜μ΄ λ§€ν•‘λœ ν…Œμ΄λΈ”μ— 데이터가 λ§Žλ‹€λ©΄ κ°’ νƒ€μž… μ»¬λ ‰μ…˜μ„ μ‚¬μš©ν•˜λŠ” 것보닀 μ—”ν‹°ν‹° νƒ€μž…μ„ μ‚¬μš©ν•˜μ—¬ μΌλŒ€λ‹€ κ΄€κ³„λ‘œ λ§€ν•‘ν•΄μ£ΌλŠ” 것이 μ’‹μŠ΅λ‹ˆλ‹€.

 

@Entity
public class Member {

    @Id
    private Long id;

    private String name;

    @Embedded // μž„λ² λ””λ“œ κ°’ νƒ€μž…
    private Address address;
	
    
    // μ˜μ†μ„± 전이, κ³ μ•„ 객체 제거 μ˜΅μ…˜ μΆ”κ°€ν•΄μ„œ κ°’ νƒ€μž… μ»¬λ ‰μ…˜μ²˜λŸΌ 맀핑
    @OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
    @JoinColumn(name = "MEMBER_ID")
    private List<AddressHistory> addressHistory = new ArrayList<AddressHistory>();

    ...

}

@Entity
public class AddressHistory{

    @Id
    @GeneratedValue
    private Long id;

    @Embedded Address address;

}

 

<정리>

  • μ—”ν‹°ν‹° νƒ€μž…μ€ μ‹λ³„μžκ°€ μžˆμ–΄ 좔적이 κ°€λŠ₯ν•˜μ§€λ§Œ κ°’ νƒ€μž…μ€ μ‹λ³„μžλ‘œ μΆ”적이 λΆˆκ°€λŠ₯ν•©λ‹ˆλ‹€.
  • μ—”ν‹°ν‹° νƒ€μž…μ€ μ°Έμ‘° 값을 κ³΅μœ ν•˜μ—¬ λ‹€λ₯Έ μ—”ν‹°ν‹°μ—μ„œ μ–Όλ§ˆλ“ μ§€ μ‘°νšŒν•  수 μžˆμ§€λ§Œ, κ°’ νƒ€μž…μ€ κ³΅μœ ν•˜κ²Œ 되면 μ°Έμ‘° λΆ€μž‘μš© λ¬Έμ œκ°€ λ°œμƒν•  수 있기 λ•Œλ¬Έμ— λΆˆλ³€ 객체둜 λ§Œλ“œλŠ” 것이 μ’‹μŠ΅λ‹ˆλ‹€.
  •  κ°’ νƒ€μž…μ€ 정말 κ°’ νƒ€μž…μ΄λΌ νŒλ‹¨λ  λ•Œλ§Œ μ‚¬μš©ν•©μ‹œλ‹€. μ‹λ³„μžκ°€ ν•„μš”ν•΄μ„œ μ§€μ†ν•΄μ„œ 값을 μΆ”μ ν•˜κ³  κ΅¬λΆ„ν•˜κ³  λ³€κ²½ν•΄μ•Ό ν•œλ‹€λ©΄ μ—”ν‹°ν‹° νƒ€μž…μ„ μ‚¬μš©ν•©μ‹œλ‹€.
  • κ°’ νƒ€μž… μ»¬λ ‰μ…˜μ€ @ElementCollection, @CollectionTable μ–΄λ…Έν…Œμ΄μ…˜μœΌλ‘œ μ‚¬μš©ν•˜κΈ°λ³΄λ‹€, κ°’ νƒ€μž… μ»¬λ ‰μ…˜μ„ μΌλŒ€λ‹€ 맀핑에 μ˜μ†μ„± 전이, 고아객체 μ‚­μ œ μ˜΅μ…˜μ„ κ³ λ €ν•˜λŠ” 것이 μ’‹μŠ΅λ‹ˆλ‹€.
    • why ? κ°’ νƒ€μž… μ»¬λ ‰μ…˜μ— 변경사항이 λ°œμƒν•˜κ²Œ 되면 κ°’ νƒ€μž… μ»¬λ ‰μ…˜μ— λ§€ν•‘λœ ν…Œμ΄λΈ”μ˜ μ—°κ΄€λœ λͺ¨λ“  데이터λ₯Ό μ‚­μ œν•˜κ³ , ν˜„μž¬ κ°’ νƒ€μž… μ»¬λ ‰μ…˜ 객체에 μžˆλŠ” λͺ¨λ“  값을 λ°μ΄ν„°λ² μ΄μŠ€μ— λ‹€μ‹œ μ €μž₯ν•˜κΈ° λ•Œλ¬Έμ— 맀우맀우 λΉ„νš¨μœ¨μ .

<참고 자료>

λΈ”λ‘œκ·Έμ˜ 정보

Study Repository

rlaehddnd0422

ν™œλ™ν•˜κΈ°