엔티티 타입
@Entity
로 정의하는 객체값 타입
int, Integer, String
처럼 단순히 값으로 사용하는 자바 기본 타입니다 객체String
JPA에서 정의
하여 사용해야 한다. JPA에서 정의
하여 사용해야 한다.값 타입
은 공유하면 안된다.
Side Effect
가 발생할 수 있기 때문이다int, double 같은 기본 타입(primitive type)은 절대 공유가 안된다.
자바의 기본 타입
은 공유되지 않는다. int a = 20;
int b = a; // 20이라는 값을 복사
b = 10;
Integer
같은 래퍼 클래스나 String
과 같은 특수한 클래스는 공유 가능한 객체이지만 변경은 불가능하다. Integer a = new Integer(10);
Integer b = a; // a의 참조를 복사
// side Effect 발생으로 아래 코드는 실행되지 않는다.(변경 불가)
a.setValue(20);
* Java에서는 변경 자체를 불가능(Immutable)하게 만들어서 Side Effect를 막는다.
Period.isWork()
처럼 해당 값 타입만 사용하는 의미 있는 메소드를 만들 수 있다.@Embeddable
@Embedded
@Embeddable
, @Embedded
중 하나만 명시하면 되지만, 둘 다 적는 것을 권장한다.값 타입
/ 임베디드 타입
에 상관없이 DB 회원 테이블의 형태는 동일하다.
@Entity
public class Member {
...
@Embedded
private Address homeAddress;
@Embedded
private Address workAddress;
...
}
@Embeddable
@NoArgsConstructor
public class Address {
private String city;
private String street;
private String zipcode;
...
}
@Embeddable
@NoArgsConstructor
public class Period {
private LocalDateTime startDate;
private LocalDateTime endDate;
...
}
ORM 어블리케이션
은 매핑한 테이블의 수보다 클래스의 수가 더 많다. @Entity
public class Member {
...
@Embedded
private Address homeAddress; // 주소
@Embedded
private Address workAddress; // 주소
---> 에러발생 : 컬럼명 중복(MappingException: Repeatedcolumn Error)
}
@AttributeOverride
: 속성 재정의@AttributeOverride
, @AttributeOverrides
를 사용해서 컬럼 명 속성을 재정의하여 중복을 피할 수 있다.@Entity
public class Member {
...
@Embedded
private Address homeAddress;
@Embedded
@AttributeOverrides({ // 새로운 컬럼에 저장 (컬럼명 속성 재정의)
@AttributeOverride(name="city", column=@Column(name = "WORK_CITY"),
@AttributeOverride(name="street", column=@Column(name = "WORK_STREET"),
@AttributeOverride(name="zipcode", column=@Column(name = "WORK_ZIPCODE")})
private Address workAddress;
...
}
임베디드 타입의 값이 NULL이면 매핑한 컬럼 값은 모두 NULL이다.
값 타입은 복잡한 객체 세상을 조금이라도 단순화하려고 만든 개념이다. 따라서 값 타입은 단순하고 안전하게 다룰 수 있어야 한다.
side effect
) 발생 Address address = new Address("city", "street", "10000");
//
Member member = new Member();
member.setUsername("member1");
member.setHomeAddress(address);
em.persist(member);
//
Member member2 = new Member();
member2.setUsername("member2");
member2.setHomeAddress(address);
em.persist(member2);
// 첫 번째 member의 Address(city) 속성만 변경하고 싶다.
member.getHomeAddress().setCity("new city");
---> member, member2 모두가 [UPDATE Query] 된다.
tx.commit(); // UPDATE Query 2번
대신 값(인스턴스)
를 복사해서 사용한다.Address address = new Address("city", "street", "10000");
//
Member member = new Member();
member.setUsername("member1");
member.setHomeAddress(address);
em.persist(member);
// Address 객체 복사
Address copyAddress = new Address(address.getCity(), address.getStreet(), address.getZipcode());
//
Member member2 = new Member();
member2.setUsername("member2");
member2.setHomeAddress(copyAddress); // 복사한 것을 넣는다.
em.persist(member2);
// 첫 번째 member의 Address(city) 속성만 변경된다.!
member.getHomeAddress().setCity("new city");
member2.setHomeAddress(address)
불변이라는 작은 제약으로 부작용이라는 큰 재앙을 막을 수 있다.
불변 객체
란Address address = new Address("city", "street", "10000");
Member member = new Member();
member.setUsername("member1");
member.setHomeAddress(address);
em.persist(member);
Address newAddress = new Address("NewCity", address.getStreet(), address.getZipcode());
member.setHomeAddress(newAddress); // 통으로 변경해 주어야 한다.
tx.commit();
int a = 10;
int b = 10;
System.out.println("a == b: " + (a == b)); // true
==
비교 시 false를 반환한다. Address address1 = new Address("서울시");
Address address2 = new Address("서울시");
System.out.println("address1 == address2: " + (address1 == address2)); // false
동일성(identity) 비교
==
사용동등성(equivalence) 비교
인스턴스의 값
을 비교한다.equals() 사용
equals()
를 재정의 해주어야한다.equals()
에 맞게 hashCode()
도 재정의 해줘야 한다.값 타입을 컬렉션에 담아서 쓰는 것
을 말한다.값 타입 컬렉션
은 값 타입을 하나 이상 저장할 때 사용한다.@ElementCollection
, @CollectionTable
사용@Entity
public class Member {
...
@ElementCollection
@CollectionTable(
name = "FAVORITE_FOOD",
joinColumns = @JoinColumn(name = "MEMBER_ID"))
@Column(name = "FOOD_NAME") // 컬럼명 지정 (예외)
private Set<String> favoriteFoods = new HashSet<>();
@ElementCollection
@CollectionTable(
name = "ADDRESS",
joinColumns = @JoinColumn(name = "MEMBER_ID"))
private List<Address> addressHistory = new ArrayList<>();
...
}
@ElementCollection
, @CollectionTable
어노테이션을 사용한다.