์๋ฒ ๋๋ ํ์ (๋ณตํฉ ๊ฐ ํ์ )
์ฐ๋ฆฌ๋ ์๋ก์ด ๊ฐ ํ์ ์ ์ง์ ์ ์ํด์ ์ฌ์ฉํ ์ ์์ต๋๋ค. ์๋ฅผ ๋ค๋ฉด ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
public Class Address {
private String city;
private String street;
private String zipcode;
}
city์ street, zipcode๋ฅผ ๊ฐ์ง๋ Address๋ ํด๋์ค๋ฅผ ๋ง๋ค์์ต๋๋ค.
๊ทธ๋ฌ๋ ์ด๋ ์ํฐํฐ๋ก ์ฌ์ฉํ ๋ชฉ์ ์ด ์๋ ๊ฐ ํ์ ์ผ๋ก ์ฌ์ฉํ๊ธฐ ์ํด ๋ง๋ ๊ฒ์ ๋๋ค.
์ด๋ฅผ JPA์์๋ ์๋ฒ ๋๋ ํ์ ์ด๋ผ๊ณ ๋ถ๋ฅด๋ฉฐ, ์๋ฒ ๋๋ ํ์ ๋ int, String๊ณผ ๊ฐ์ ๊ฐ ํ์ ์ ๋๋ค.
@Embedded & @Embeddable
์๋ฒ ๋๋ ํ์ ์ ํ๋๋ก ์ฌ์ฉํ๋ ค๋ฉด ํ๋ ์์ @Embedded๋ฅผ ๋ถ์ ๋๋ค.
๊ทธ๋ฆฌ๊ณ ๊ฐ ํ์ ์ผ๋ก ์ฌ์ฉ๋๋ ํด๋์ค์๋ @Embeddable์ ๋ถ์ ๋๋ค.
@Embeddable: ๊ฐ ํ์ ์ ์ ์ํ๋ ๊ณณ์ ํ์
@Embedded: ๊ฐ ํ์ ์ ์ฌ์ฉํ๋ ๊ณณ์ ํ์
์ด๋ ๊ฐ ํ์ ํด๋์ค์๋ ๊ธฐ๋ณธ ์์ฑ์๊ฐ ํ์๋ก ์กด์ฌํด์ผ ํฉ๋๋ค.
์์
@Entity
public class Member {
@Id @GeneratedValue
private Long id;
private String name;
@Embedded
private Address address;
}
@Embeddable
public class Address {
private String city;
private String street;
private String zipcode;
}
DB์ ๋งคํ๋๋ ๋ชจ์ต์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
์๋ฒ ๋๋ ํ์ ์ ๊ฐ ํ์ ์ ์ผ๋ถ์ผ ๋ฟ์ ๋๋ค.
๋ฐ๋ผ์ ์๋ฒ ๋๋ ํ์ ์ ์ํ ๊ฐ์ด ๊ทธ๋๋ก ๋งคํ๋ฉ๋๋ค.
์๋ฒ ๋๋ ํ์ ์ ์ฌ์ฉํ์ง ์๊ณ street, zipcode, city๋ฅผ Member์์ ๊ทธ๋ฅ ์ฌ์ฉํ ๋์ ํ ์ด๋ธ์ ๊ตฌ์กฐ๋ ๋๊ฐ์ ๊ฒ์ ๋๋ค.
์๋ฒ ๋๋ ํ์ ๊ณผ ์ฐ๊ด๊ด๊ณ
์๋ฒ ๋๋ ํ์ ์ ๋๋ค๋ฅธ ์๋ฒ ๋๋ ํ์ ์ ํฌํจํ๊ฑฐ๋ ์ํฐํฐ๋ฅผ ์ฐธ์กฐํ ์ ์์ต๋๋ค.
์ฆ ๋ค๋ฅธ ์ํฐํฐ, ํน์ ๊ฐ ํ์ ๊ณผ ์ฐ๊ด๊ด๊ณ๋ฅผ ๋งบ์ ์ ์๋ค๋ ๋ป์ ๋๋ค.
์์
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Entity
@Setter
@Getter
public class Member{
@Id @GeneratedValue
@Column(name = "MEMBER_ID")
private Long id;
private String name;
@Embedded
private Address address;
@Embedded
private Phone phone;
}
Member๋ Address์ Phone์ ๊ฐ ํ์ ์ผ๋ก ์ฌ์ฉํฉ๋๋ค.
@Embeddable
public class Address {
private String city;
private String street;
@Embedded
private Zipcode zipcode;
}
Address๋ ๋๋ค๋ฅธ ์๋ฒ ๋๋ ํ์ ์ Zipcode๋ฅผ ์ฐธ์กฐํฉ๋๋ค.
@Embeddable
public class Zipcode {
private String zip;
private String plusFour;
}
@Embeddable
public class Phone {
private String areaCode;
private String number;
@ManyToOne
@JoinColumn(name = "PHONE_PROVIDER")
private PhoneServiceProvider provider;
}
Phone์ PhoneServiceProvider์ @ManyToOne์ ์ฐ๊ด๊ด๊ณ๋ฅผ ๊ฐ์ง๊ณ ์์ต๋๋ค.
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Entity
public class PhoneServiceProvider {
@Id @GeneratedValue
private Long id;
private String name;
}
์์ฑ๋๋ ํ ์ด๋ธ์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
@AttributeOverride ๋ฅผ ์ฌ์ฉํ ์์ฑ ์ฌ์ ์
์ ์ ๋ค๋ฅธ ๊ธ(https://ttl-blog.tistory.com/141)์์ @AttributeOverrid๋ฅผ ํตํด ์ปฌ๋ผ ์์ฑ์ ์ฌ์ ์ ํ ์ ์๋ค๊ณ ํ์์ต๋๋ค.
์๋ฒ ๋๋ ํ์ ์์๋ ์ด๋ป๊ฒ ์ฌ์ฉํ๋์ง ์์๋ณด๋๋ก ํ๊ฒ ์ต๋๋ค.
์๋ฅผ ๋ค์ด ํ์์ด ์ง ์ฃผ์์ ํ์ฌ ์ฃผ์ 2๊ฐ์ ์ฃผ์๋ฅผ ํ์๋ก ํ๋ค๊ณ ํ๋ฉด ์ด๋ป๊ฒ ํด์ผํ ๊น์?
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Entity
@Setter
@Getter
public class Member{
@Id @GeneratedValue
@Column(name = "MEMBER_ID")
private Long id;
private String name;
@Embedded
private Address homeAddress;
@Embedded
private Address companyAddress;
@Embedded
private Phone phone;
}
์์ ๊ฐ์ ํด๋์ค๋ฅผ ๊ฐ์ง๊ณ ์คํํด๋ณด๋ฉด ๋ค์ ์ค๋ฅ๊ฐ ๋ฐ์ํฉ๋๋ค.
์์ธ ๋ฉ์ธ์ง๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
org.hibernate.MappingException:
Repeated column in mapping for entity:
jpa.jpa.Member column: city (should be mapped with insert="false" update="false")
์ํฐํฐ์ ๋ฐ๋ณต๋๋ ์ปฌ๋ผ์ด ์์ด์ ๋งคํ์ค๋ฅ๊ฐ ๋ฐ์ํ๋ค๊ณ ํฉ๋๋ค.
์ด๋ด ๋ ์ด ์ค๋ณต๋๋ ์ปฌ๋ผ์ ํด๊ฒฐํด์ฃผ๊ธฐ ์ํด @AttributeOverride๋ฅผ ์ฌ์ฉํ ์ ์์ต๋๋ค.
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Entity
@Setter
@Getter
public class Member{
@Id @GeneratedValue
@Column(name = "MEMBER_ID")
private Long id;
private String name;
@Embedded
@AttributeOverrides({
@AttributeOverride(name = "city", column = @Column(name = "HOME_CITY")),
@AttributeOverride(name = "street", column = @Column(name = "HOME_STREET")),
@AttributeOverride(name = "zipcode.zip", column = @Column(name = "HOME_ZIP")),
@AttributeOverride(name = "zipcode.plusFour", column = @Column(name = "HOME_PLUS_FOUR")),
})
private Address homeAddress;
@Embedded
@AttributeOverrides({
@AttributeOverride(name = "city", column = @Column(name = "COMPANY_CITY")),
@AttributeOverride(name = "street", column = @Column(name = "COMPANY_STREET")),
@AttributeOverride(name = "zipcode.zip", column = @Column(name = "COMPANY_ZIP")),
@AttributeOverride(name = "zipcode.plusFour", column = @Column(name = "COMPANY_PLUS_FOUR")),
})
private Address companyAddress;
@Embedded
private Phone phone;
}
๊ฐ ํ์ ์ฃผ์ - ์๋ฒ ๋๋ ํ์ ์ ๊ณต์ ์ฐธ์กฐ
์๋ฒ ๋๋ ํ์ ๊ฐ์ ๊ฐ ํ์ ์ ์ฌ๋ฌ ์ํฐํฐ์์ ๊ณต์ ํ๋ฉด ์ํํฉ๋๋ค.
์ด๋ค ๊ฐ์ฒด์ ๊ฐ์ ์์ ํ์๋๋ฐ, ๋ค๋ฅธ ๊ฐ์ฒด์ ๊ฐ๊น์ง ์์ ๋๋ ๊ฒฝ์ฐ๊ฐ ๋ฐ์ํ ์ ์๊ธฐ ๋๋ฌธ์ ๋๋ค.
์์๋ฅผ ํ๋ ๋ค์ด๋ณด๊ฒ ์ต๋๋ค.
Address address = new Address("์์ธ", "๊ธธ", new Zipcode("100","100"));
Member member1 = new Member();
member1.setAddress(address);
em.persist(member1);
Member member2 = new Member();
member2.setAddress(address);//address ๊ณต์
em.persist(member2);
member1.getAddress().setCity("๋์ ");
์ ์ฝ๋์ ๊ฒฐ๊ณผ๋ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
์์ ๊ฐ์ ๋ฌธ์ ์ ๋ฐ์์ ๋ง๊ธฐ ์ํด ๊ฐ ํ์ ์ ๊ณต์ ๋์ง ๋ชปํ๊ฒ ๋ง์์ผ ํฉ๋๋ค.
์ด๋ฅผ ์ํ ๋ฐฉ๋ฒ๋ค์ ์์๋ณด๋๋ก ํ๊ฒ ์ต๋๋ค.
๋ถ๋ณ ๊ฐ์ฒด๋ก ๋ง๋ค๊ธฐ
๊ฐ์ฒด๋ฅผ ๋ถ๋ณํ๊ฒ ๋ง๋ค๋ฉด ๊ฐ์ ์์ ํ ์ ์๊ธฐ ๋๋ฌธ์, ๊ณต์ ์ฐธ์กฐ๋ก ๋ฐ์ํ๋ ๋ถ์์ฉ์ ๋ฐฉ์งํ ์ ์์ต๋๋ค.
๋ฐ๋ผ์ ๊ฐ ํ์ ์ ๋๋๋ก ๋ถ๋ณ ๊ฐ์ฒด(์์ฑ ์์ ์ดํ ์ ๋ ๊ฐ์ ๋ณ๊ฒฝํ ์ ์๋ ๊ฐ์ฒด)๋ก ์ค๊ณํด์ผ ํฉ๋๋ค.
๋ถ๋ณ ๊ฐ์ฒด๋ก ๋ง๋๋ ๋ฐฉ๋ฒ์ ์ฌ๋ฌ ๋ฐฉ๋ฒ์ด ์์ผ๋, ๊ฐ์ฅ ๊ฐ๋จํ ๋ฐฉ๋ฒ์ ์์๋ก๋ง ๊ฐ์ ์ค์ ํ๊ณ , ์์ ์๋ ๋ง๋ค์ง ์์ผ๋ฉด ๋ฉ๋๋ค.
์์ Address๋ฅผ ๋ถ๋ณ ๊ฐ์ฒด๋ก ๋ง๋ค์ด๋ณด๊ฒ ์ต๋๋ค.
@Embeddable
public class Address {
private String city;
private String street;
@Embedded
private Zipcode zipcode;
protected Address(){}//JPA๋ ๊ธฐ๋ณธ ์์ฑ์๊ฐ ํ์์ด๋ค.
public Address(String city, String street, Zipcode zipcode) {
this.city = city;
this.street = street;
this.zipcode = zipcode;
}
//์์ ์๋ ๋ง๋ค์ง ์๋๋ค.
}
์ด์ Address๋ ๋ถ๋ณ ๊ฐ์ฒด์ ๋๋ค.
๊ฐ์ ์์ ํ ์ ์์ผ๋ฏ๋ก ๊ณต์ ํด๋ ๋ถ์์ฉ์ด ๋ฐ์ํ์ง ์์ต๋๋ค.
๋ง์ฝ ๊ฐ์ ์์ ํด์ผ ํ๋ฉด, ์์ฑ์๋ฅผ ์ด์ฉํด ์๋ก์ด ๊ฐ์ฒด๋ฅผ ๋ง๋ค์ด ์ฌ์ฉํด์ฃผ์ด์ผ ํฉ๋๋ค.
์ฐธ๊ณ ๋ก String, Integer๋ ์๋ฐ๊ฐ ์ ๊ณตํ๋ ๋ํ์ ์ธ ๋ถ๋ณ ๊ฐ์ฒด์ ๋๋ค.
๊ฐ ํ์ ์ ๋น๊ต - equals ์ฌ์ ์
equals๋ ๊ธฐ๋ณธ์ด == ๋น๊ต์ด๊ธฐ ๋๋ฌธ์, ๊ฐ ํ์ ์ ์๋ก ๋ง๋ค์ด ์ฃผ์๋ค๋ฉด equals, hashCode๋ฅผ ์ฌ์ ์ํด ์ฃผ์ด์ผ ํฉ๋๋ค.
(์ฌ๋งํ๋ฉด ์๋์ผ๋ก ์์ฑํด์ฃผ๋ ๊ธฐ๋ฅ์ ๊ทธ๋๋ก ์ฌ์ฉํ๋ ๊ฒ์ด ์ข์ต๋๋ค.)
์ฐธ๊ณ
@Inheritance๋ ๋คํ์ฑ์ ์ํ ์์์
@MappedSuperclass๋ ์ฝ๋ ์ฌ์ฌ์ฉ์ ์ํ ์์์
@Embedded, @Embeddable์ ํฉ์ฑ์ ๊ตฌํํ ๋ ์ฌ์ฉํฉ๋๋ค.
๐ Reference
[์๋ฐ ORM ํ์ค JPA ํ๋ก๊ทธ๋๋ฐ - ๊น์ํ]
'๐๏ธ Spring > JPA' ์นดํ ๊ณ ๋ฆฌ์ ๋ค๋ฅธ ๊ธ
[JPA] JPA์์์ ํ๋ก์ (0) | 2021.12.15 |
---|---|
[JPA] @AssocicationOverride - ์ฐ๊ด๊ด๊ณ(์ธ๋ ํค ์ปฌ๋ผ๋ช ) ์ฌ์ ์ (0) | 2021.12.15 |
[JPA] @MappedSuperclass (0) | 2021.12.15 |
[JPA] ์์๊ด๊ณ ๋งคํํ๋ ๋ฐฉ๋ฒ (0) | 2021.12.15 |
[JPA] ์ฐ๊ด๊ด๊ณ ๋งคํํ๋ ๋ฐฉ๋ฒ (2) | 2021.12.15 |