@Entity
로 정의하는 객체int
, Integer
, String
처럼 단순히 값으로 사용하는 자바 기본 타입이나 객체int
, double
)Integer
, Long
)String
: String name
, ing age
...
생명주기를 엔티티에 의존한다는 중요한 특징이 있다.
(예를 들어 회원을 삭제하면 이름, 나이 필드도 함께 삭제된다.)
값 타입은 공유하면 안된다.
(예를 들어 회원 이름 변경시 다른 회원의 이름도 변경 되어버리면 안되기 때문이다.)
int
, double
같이 기본 타입(primitive type)은 절대 공유하면 안된다.
기본 타입은 항상 값을 복사한다.
Integer
와 같이 래퍼 클래스나 String
같은 특수한 클래스는 공유가 가능한 객체이지만 변경 불가능
: 복합 값 타입, 내장 타입이라고도 함
int
, String
과 같은 값 타입(추적도 변경도 안됨)요구사항
- 회원 엔티티는 이름, 근무 시작일, 근무 종료일, 주소 도시, 주소 번지, 주소 우편번호를 가짐
- 회원 엔티티는 이름, 근무 기간, 집 주소를 가짐
@Embeddable
: 값 타입을 정의하는 곳에 표시@Embedded
: 값 타입을 사용하는 곳에 표시@AttributeOverride
: 속성 재정의
한 엔티티에서 같은 값 타입을 사용하면 컬럼명이 중복 되어버린다.
그럴 때 @AttributeOverrides
와 @AttributeOverride
를 사용해 컬러 명 속성을 재정의 한다.
📌 임베디드 타입의 값이 null이면 매핑한 컬럼 값은 모두 null이다.
값 타입은 복잡한 객체 세상을 조금이라도 단순화하기 위해 만든 개념. 따라서 값 타입은 단순하고 안전하게 다룰 수 있어야 함
int a = 10;
int b = a; // 기본 타입은 값을 복사하기 때문에 b = 10인 상태
b = 4;
// b만 4로 변경
Address a = new Address("old");
Address b = a; // 객체 타입은 참조를 전달
b.setCity("new");
// a와 b 가 같은 인스턴스를 가지고 있으므로 둘 다 "new"로 바뀜
📌
Integer
,String
은 자바가 제공하는 대표적인 불변 객체
값 타입은 인스턴스가 달라도 그 안의 값이 같으면 같은 것으로 봐야한다.
int a = 10; int b = 10;
이라면 a==b 는 true
이다.
Address a = new Address("ㅇㅇ시");
Address b = new Address("ㅇㅇ시");
라면 a==b 는 false
이다.
==
사용equals()
사용: 값 타입을 컬렉션에 담아 쓰는 것
@ElementCollection
, CollectionTable
사용해 매핑📌 값 타입 컬렉션은 영속성 전이(Cascade) + 고아 객체 제거 기능을 필수로 가진다고 볼 수 있다.
// JpaMain.java
try {
Member member = new Member();
member.setUsername("member1");
member.setHomeAddress(new Address("homeCity", "street", "100"));
member.getFavoriteFoods().add("물회");
member.getFavoriteFoods().add("미역국");
member.getFavoriteFoods().add("계란");
member.getAddressHistory().add(new Address("old1", "street", "100"));
member.getAddressHistory().add(new Address("old2", "street", "100"));
em.persist(member);
em.flush();
em.clear();
System.out.println("====== START ======");
Member findMember = em.find(Member.class, member.getId());
// homeCity -> newCity
Address a = findMember.getHomeAddress();
findMember.setHomeAddress(new Address("newCity", a.getStreet(), a.getZipcode()));
// 물회 -> 매운탕
findMember.getFavoriteFoods().remove("물회");
findMember.getFavoriteFoods().add("매운탕");
findMember.getAddressHistory().remove(new Address("old1", "street", "100"));
findMember.getAddressHistory().add(new Address("newCity1", "street", "100"));
tx.commit();
값 타입은 정말 값 타입이라고 판단될 때만 사용해야 한다.
엔티티와 값 타입을 혼동해 엔티티를 값 타입으로 만들면 안된다.
식별자가 필요하고, 지속해서 값을 추적, 변경해야 한다면 그것은 값 타입이 아닌 엔티티이다.
✔️ 실전 예제는 jpashop 프로젝트, jpashop DB를 사용합니다.
📌 참고
Address.java를 생성해 객체지향적으로 만들었다.
자세한 코드는 깃허브를 참고