엔티티 타입
@Entity로 정의하는 객체값 타입
int, Integer, String처럼 단순히 값으로 사용하는 자바 기본 타입니다 객체StringJPA에서 정의하여 사용해야 한다. 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 어노테이션을 사용한다.