@Entity
로 정의하는 객체값 타입은 복잡한 객체 세상을 조금이라도 단순화하려고 만든 개념!
<Member> 회원은 이름, 시작일자, 종료일자, 도시명, 도로명, 우편번호를 가진다
Long id;
String name;
LocalDateTime startDtae;
LocalDateTime endDate;
String city;
String street;
String zipcode;
<Member> 회원은 이름, 근무 기간, 집 주소를 가진다
Long id;
String name;
Period workPeriod;
Address homeAddress;
jpa 에서는 @Embeddable (값 타입 정의하는 곳)
, @Embedded (값 타입 사용하는 곳)
에 표시를 한다.
( + 기본 생성자 필수 )
복합 값 타입(임베디드 타입)에 엔티티도 들어올 수 있다.
외래키로 불러오기만 하면 되는거임.
!! 같은 값 타입을 여러번 사용하고 싶을때
@AttributeOverride
라는 속성을 사용해 지정해줘야함 (Column 이름을)@AttributeOverrides({ @AttributeOverride(name="city", column=@Column(name = "xxx")), @AttributeOverride(name="street", column=@Column(name = "xxx")), @AttributeOverride(name="zipcode", column=@Column(name = "xxx")), })
조심해야 할 것!!
임베디드 값 타입을 하나의 인스턴스로 여러개를 동시에 공유하면 안됨!!
같은 값을 주고 싶을 때는, clone 을 만들어서 넣어주어야함!
-> 개발자가 신경을 쓰는 부분... human mistake가 충분히 있을 수 있음....
==> 객체 타입의 한계.. 다른 방법 없을까?
불변객체 (immutable object)
- 생성 시점 이후 절대 값을 변경할 수 없는 객체
- setter 를 만들지 않기!!
- Side Effect가 생길 가능성을 없애줌!
=> 가급적 임베디드 타입은 불변객체로 만들어 주는 것이 좋음!
Address.java
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Address address = (Address) o;
return Objects.equals(city, address.city) && Objects.equals(street, address.street) && Objects.equals(zipcode, address.zipcode);
}
@Override
public int hashCode() {
return Objects.hash(city, street, zipcode);
}
위 경우엔 city, street, zipcode 직접 접근 한다.
이렇게 체크를 해주어서, getter 로 접근 할 수 있도록 하는 것이 좋음
(프록시 객체의 경우 에러가 날 수 있음)
equals 함수를 override 할때는 기본적으로 제공해주는 것을 사용하는 것이 좋음!!
@ElementCollection, @CollectionTable
을 사용!Member.java -> @ElementCollection, @CollectionTable
@Entity
public class Member {
@Id @GeneratedValue
@Column(name = "MEMBER_ID")
private Long id;
private String name;
@ElementCollection
@CollectionTable(name = "FAVORITE_FOOD",
joinColumns = @JoinColumn(name = "MEMBER_ID"))
@Column(name = "FOOD_NAME") // 안해도 되지만, 해당 테이블에서의 Column 명이 애매
private Set<String> favoriteFoods = new HashSet<>();
@ElementCollection
@CollectionTable(name = "ADDRESS",
joinColumns = @JoinColumn(name = "MEMBER_ID"))
private List<Address> addressHistory = new ArrayList<>();
}
Address.java
@Embeddable
public class Address {
public Address() {
}
public Address(String city, String street, String zipcode) {
this.city = city;
this.street = street;
this.zipcode = zipcode;
}
private String city;
private String street;
private String zipcode;
}
Member member = new Member();
member.setName("changer");
member.getAddressHistory().add(new Address("city1", "street1", "1234"));
member.getAddressHistory().add(new Address("city2", "street2", "1234"));
member.getFavoriteFoods().add("치킨");
member.getFavoriteFoods().add("피자");
member.getFavoriteFoods().add("족발");
em.persist(member);
위와 같이 자동으로 Table 이 생성된다.
Member findMember = em.find(Member.class, member.getId());
findMember.getFavoriteFoods().remove("치킨");
findMember.getFavoriteFoods().add("삼계탕");
이렇게 하면 자동으로 table에 업데이트 된다.
addressHistory 의 경우에는
member.getAddressHistory().add(new Address("city1", "street1", "1234"));
...
...
Member findMember = em.find(Member.class, member.getId());
// findMember.getFavoriteFoods().remove("치킨");
// findMember.getFavoriteFoods().add("삼계탕");
findMember.getAddressHistory().remove(new Address("city1", "street1", "1234"));
findMember.getAddressHistory().add(new Address("city3", "street3", "1432"));
equals 함수가 구현이 되어있다면, remove 함수는 equals 가 true 인 항목을 없애준다.
add는 똑같이 하면 된다.
잘 돌아가는 것 같지만, 영속성 컨텍스트가 실제로는 우리 생각처럼 DB query 를 날리지 않음
(update 가 아닌, 통으로 delete 후 create 를 함!)
이거 너무 제약사항이 많은걸? 다른 대안 없어??!!
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
@JoinColumn(name = "MEMBER_ID")
private List<AddressEntity> addressEntityList = new ArrayList<>();
// @ElementCollection
// @CollectionTable(name = "ADDRESS",
// joinColumns = @JoinColumn(name = "MEMBER_ID"))
// private List<Address> addressHistory = new ArrayList<>();
member.getAddressEntityList().add(new AddressEntity("city1", "street1", "1234"));
member.getAddressEntityList().add(new AddressEntity("city2", "street2", "1234"));
...
...
findMember.getAddressEntityList().remove(new AddressEntity("city1", "street1", "1234"));
findMember.getAddressEntityList().add(new AddressEntity("city3", "street3", "1432"));
값 타입 컬렉션은 정말로 컬렉션 개수가 몇개 안될때! 막 쌓이는 것들이 아니고