import javax.persistence.Embeddable;
import java.util.Objects;
@Embeddable
public class Address {
private String city;
private String street;
private String zipcode;
public Address() {
}
public Address(String city, String street, String zipcode) {
this.city = city;
this.street = street;
this.zipcode = zipcode;
}
public String getCity() {
return city;
}
public String getStreet() {
return street;
}
public String getZipcode() {
return zipcode;
}
@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);
}
}
import javax.persistence.*;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
@Entity
public class Member {
@Id @GeneratedValue
@Column(name = "MEMBER_ID")
private Long id;
@Column(name = "USERNAME")
private String username;
//주소
@Embedded
private Address homeAddress;
@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<>();
public Long getId() {
return id;
}
// ... 이하 생략
}
이런 값 타입 리스트 구조를 가진다고 했을 때 어떻게 동작할까?
Member member = new Member();
member.setUsername("member1");
member.setHomeAddress(new Address("HomeCity", "street", "10000"));
member.getFavoriteFoods().add("치킨");
member.getFavoriteFoods().add("족발");
member.getFavoriteFoods().add("피자");
member.getAddressHistory().add(new Address("old1", "street", "10000"));
member.getAddressHistory().add(new Address("old2", "street", "10000"));
em.persist(member);
em.flush();
em.clear();
System.out.println("============== START ==============");
Member findMember = em.find(Member.class, member.getId());
이렇게 만들어서 find해보면
FavoriteFoods와 addressHistory는 쿼리문을 날리지 않는다. 즉, 프록시로 가져오게 된다.
그리고 수정 시에 즉
homeCity에서 newCity로 바꾸려고 할 때,
findMember.getHomeAddress().setCity("newCity");
이렇게 진행해야할 것 같지만 이렇게 진행하면 사이드 이펙드가 생긴다.
그래서
Address a = findMember.getHomeAddress();
findMember.setHomeAddress(new Address("newCity", a.getStreet(), a.getZipcode()));
이렇게 진행하여야 한다.
치킨에서 한식으로 바꿀 때는
// 치킨 -> 한식
findMember.getFavoriteFoods().remove("치킨");
findMember.getFavoriteFoods().add("한식");
지웠다가 다시 add 한다.
old1을 newCity1으로 바꿀 때도 까다로운데, hashCode와 equals가 오버라이드 되어있다고 가정하에
findMember.getAddressHistory().remove(new Address("old1", "street", "10000"));
findMember.getAddressHistory().add(new Address("newCity1", "street", "10000"));
이렇게 진행하면 된다. 그러나 결과를 보면
멤버에 해당하는 address를 다 지우고 지운 만큼의 address를 다시 insert하는 것을 확인할 수 있다.
이 이유는
라는 값 타입의 특징 때문이다.
그래서 현업에서는 명확하지 않으면 이 값 타입을 사용하는 것을 추천하지 않는다고 한다.
[ JPA ] JPQL 경로 표현식 (0) | 2022.01.31 |
---|---|
[ JPA ] jpql 페이징 (0) | 2022.01.29 |
[ JPA ] 임베디드 타입 (0) | 2022.01.26 |
[ JPA ] CASCADE는 어디에 사용할까 (persist 한 번만 쓰고 싶을 때) (0) | 2022.01.22 |
[ JPA ] 지연로딩과 즉시로딩 (0) | 2022.01.20 |