int a = 10;
int b = a;
b = 20;
public class Member extends BaseEntity {
@Embedded
private Period workPeriod;
@Embedded
private Address homeAddress;
}
@Embeddable
public class Period {
private LocalDateTime startDate;
private LocalDateTime endDate;
// getter, setter, 기본 생성자
}
@Embeddable
public class Address {
private String city;
private String street;
private String zipcode;
// getter, setter, 기본 생성자
}
@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
값 타입은 복잡한 객체 세상을 조금이라도 단순화하려고
만든 개념이다. 따라서 값 타입은 단순하고 안전하게 다
룰 수 있어야 한다.
member와 member2가 같은 Address를 사용하므로 member.getHomeAddress().setCity("newCity");
실행시 member와 member2의 Address가 둘 다 바뀜.
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.getHomeAddress().setCity("newCity");
Address newAddres = new Address("newCity", address.getStreet(), address.getZipcode());
=> 불변이라는 작은 제약으로 부작용이라는 큰 재앙을 막을 수 있다 ❗
값 타입은 인스턴스가 달라도 그 안에 값이 같으면 같은 것으로 봐야 함
int a = 10;
int b = 10;
// a == b -> true
Address a = new Address("서울시");
Address b = new Address("서울시");
// a == b -> false
@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<>();
Member member = new Member();
member.setName("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();
Member findMember = em.find(Member.class, member.getId());
List<Address> addressHistory = findMember.getAddressHistory(); // 이 때 컬렉션 가져옴
Set<String> favoriteFoods = findMember.getFavoriteFoods();
//findMember.getHomeAddress().setCity("newCity"); // X
// 통으로 변경
Address a = findMember.getHomeAddress();
findMember.setHomeAddress(new Address("newCity", a.getStreet(), a.getZipcode()));
// 치킨 -> 한식
findMember.getFavoriteFoods().remove("치킨");
findMember.getFavoriteFoods().add("한식");
findMember.getAddressHistory().remove(new Address("old1", "street", "10000")); // 이렇게 remove 해주려면 equals, hashcode 구현 필수!
findMember.getAddressHistory().add(new Address("newCity1", "street", "10000"));
AddressEntity
@Entity
@Table(name = "ADDRESS")
public class AddressEntity {
@Id
@GeneratedValue
private Long id;
private Address address;
public AddressEntity(String city, String street, String zipcode) {
this.address = new Address(city, street, zipcode);
}
public AddressEntity(Address address) {
this.address = address;
}
}
Member
값 타입 컬렉션 방식이 아닌 일대다 방식 활용
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
@JoinColumn(name = "MEMBER_ID")
private List<AddressEntity> addressHistory = new ArrayList<>();
main
findMember.getAddressHistory().add(new AddressEntity("old1", "street", "10000"));
findMember.getAddressHistory().add(new AddressEntity("old2", "street", "10000"));