[AddressEntity]
@Entity
@Table(name = "ADDRESS")
public class AddressEntity {
@Id @GeneratedValue
private Long id;
@Embedded
private Address address; // 값 타입 사용
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
AddressEntity that = (AddressEntity) o;
return Objects.equals(address, that.address);
}
@Override
public int hashCode() {
return Objects.hash(address);
}
}
[Member]
@Entity
public class Member {
@Id @GeneratedValue
@Column(name = "MEMBER_ID")
private Long id;
@Column(name="USERNAME")
private String username;
@Embedded
private Address homeAddress;
// 컬렉션 값 타입 대신에 일대다 매핑
@OneToMany(cascade = CascadeType.ALL, orpahnRemoval = true)
@JoinColumn(name = "MEMBER_ID")
private List<AddressEntity> addressHistory = new ArrayList<>();
}
[JpaMain]
Member member = new Member();
member.setUsername("member");
member.setHomeAddress(new Address("homeCity", "street", "10000"));
member.getAddressHistory().add(new AddressEntity("old1", "street", "10000"));
member.getAddressHistory().add(new AddressEntity("old2", "street", "10000"));
em.persist(member);
em.flush();
em.clear();
Member findMember = em.find(Member.class, member.getId());
// 히스토리 바꾸기
findMember.getAddressHistory().remove(new AddressEntity("old1", "street", "10000"));
findMember.getAddressHistory().add(new AddressEntity("newCity1", "street", "10000"));
위의 예시는 일대다 단방향 매핑이다.
따라서 JpaMain
의 코드를 실행시키면 다음과 같이 쿼리가 호출된다.
insert
into
member
(city, street, zipcode, username, member_id)
values
(?, ?, ?, ?, ?)
// insert 쿼리 2번 -> address가 2개 있으므로
insert
into
address
(city, street, zipcode, id)
values
(?, ?, ?, ?)
// update 쿼리 2번 -> address가 2개 있으므로
update
address
set
member_id=?
where
id=?
양방향보다 단방향이 좋다? 에서 일대다 단방향 매핑의 경우 update 쿼리가 나갈 수 있으므로, 다대일 양방향 매핑을 추천한다는 글을 쓴 적이 있다.
따라서 위의 예시를 다대일 양방향 매핑으로 바꾼 후 진행해 봤다.
[Member]
@Getter @Setter
@Entity
public class Member {
@Id @GeneratedValue
@Column(name = "MEMBER_ID")
private Long id;
@Column(name = "USERNAME")
private String username;
@Embedded
private Address homeAddress;
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true, mappedBy = "member")
private List<AddressEntity> addressHistory = new ArrayList<>();
}
[AddressEntity]
@Getter
@NoArgsConstructor(access = AccessLevel.PROTECTED)
@Table(name = "ADDRESS")
@Entity
public class AddressEntity {
@Id @GeneratedValue
private Long id;
@Embedded
private Address address;
@ManyToOne
@JoinColumn(name = "MEMBER_ID")
private Member member;
public AddressEntity(String city, String street, String zipcode, Member member) {
this.address = new Address(city, street, zipcode);
this.member = member;
}
}
[TestCode]
Member member = new Member();
member.setUsername("member1");
member.setHomeAddress(new Address("homeCity", "street", "10000"));
member.getAddressHistory().add(new AddressEntity("old1", "street", "10000", member));
member.getAddressHistory().add(new AddressEntity("old1", "street", "10000", member));
memberRepository.save(member);
insert
into
member
(city, street, zipcode, username, member_id)
values
(?, ?, ?, ?, ?)
// insert 쿼리 2번
insert
into
address
(city, street, zipcode, member_id, id)
values
(?, ?, ?, ?, ?)
이렇게 다대일 양방향 매핑으로 변환 후 실행하면 update 쿼리가 나가지 않음을 알 수 있다.