기본 값 타입
cf) 자바의 기본 타입은 절대 공유X
기본 타입은 값을 복사한다
Integer 같은 래퍼 클래스나 String 같은 특수한 클래스는 공유가능 객체이지만 변경 할 수 없다
-> 이게 무슨 소리냐?
Integer a = new Integer(10);
Integer b = a;
a.setValue(20); // 존재 가정
//출력 시 a == b == 20
//하지만 a 값을 바꿀 방법조차 없음
임베디드 타입
@Entity
public class Member{
@Embedded //상위 계층에 표기
private Address homeAddress;
...
}
@Embeddable //하위 계층에 표기
public class Address {
private String city;
private String street;
private String zipcode;
public Address() { //디폴트 생성자 필수
}
...
임베디드 타입은 엔티티의 값일 뿐이고, 사용 전 후에 매핑하는 테이블은 같다
그럼 왜 임베디드 타입을 사용할까?
-> 객체와 테이블을 아주 세밀하게 매핑하는 것이 가능하다
(ex) Address의 좌표값 등 재사용성을 높일 수 있다
위 그림처럼 임베디드 된 클래스에서 엔티티를 가질 수 있다.
(외래키만을 참조하면 되기 때문)
한 엔티티에서 같은 값을 사용하고 싶다..
@AttributeOverride(s) : 속성 재정의
public 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 = "EMP_END"))
})
private Address workAddress;
}
값 타입과 불변 객체
자바의 기본타입은 값을 복사하기 때문에 초기 설정값에는 지장이 없다
int a = 10;
int b = a; //값 복사
b = 4;
자바의 객체 타입은 하나의 인스턴스에 대해 참조를 복사하여 넘기기 때문에 값이 모두 변경된다
Address a = new Address("old");
Address b = a; //참조
b.setCity("new);
참조를 막을 방법이 없기 때문에 불변 객체로 만들어야 한다
그렇다면 Setter가 없는 상황에서 값을 수정하고 싶으면 어떻게 할까?
=> 객체를 새로 만들어서 수정하고 싶은 부분만 수정한 후 다시 통째로 넣어줘야한다.
Address newAddress = new Address("NewCity",
address.getStreet(), address.getZipcode());
member1.setHomeAddress(newAddress);
값 타입의 비교
값 타입들의 비교는 항상 equals를 사용하자
Address add2 = new Address("city", "street", "10000");
Address add1 = new Address("city", "street", "10000");
System.out.println("add1 == add2: " + (add1 == add2)); //false
System.out.println("add1 equals add2: " + (add1.equals(add2))); //false
//equals의 기본은 == 이기 때문에 false => equals 메서드 오버라이드 필요
(cf)
//String의 equals는 == 비교로 구현되어 있지 않음
//String.java
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
값 타입 컬렉션
(값타입)컬렉션 또한 값타입이기 때문에 em.persist(member) 만으로 모든 값타입 컬렉션에 대한 insert 쿼리가 발생한다
Member member = new Member();
member.setUsername("member1");
member.setHomeAddress(new Address("homeCity", "street", "1000"));
member.getFavoFoods().add("치킨");
member.getFavoFoods().add("족발");
member.getAddHistory().add(new Address("old1", "street","10000"));
member.getAddHistory().add(new Address("old2", "street","10000"));
em.persist(member);
값 타입 컬렉션은 영속성 전이(cascade) + 고아 객체 제거 기능을 필수로 가진다고 생각하자
--- 중간 과정 생략 (쿼리 이해가 잘 안됨 추후에 다시 확인) ---
결론: 값타입 컬렉션은 쿼리가 발생하면 이전에 저장되어 있는 값을 모두 날리므로 사용하지 말고, 일대다 관계를 고려하자
그렇다면 값타입 컬렉션은 언제 사용할까?
=> 정말 단순한 경우, 추적할 필요가 없고 업데이트를 하지 않을 경우
실전 예제 6 - 값 타입 매핑
Reference
김영한 님 - 자바 ORM 표준 JPA 프로그래밍 - 기본편
이렇게 유용한 정보를 공유해주셔서 감사합니다.