참고한 레퍼런스는 JPA의 사실과 오해이다.
JPA강의를 듣고 정리한 글들 중 많은 글들이 양방향 연관관계보다는 단방향 연관관계를
권장하고 있다. 이는 반은 맞고 반은 틀린말인데 예시를 들어 설명하고자 한다.
[Member]
@Entity
public class Member {
@Id
@Column(name = "member_id")
private Long memberId;
private String name;
@Column(name = "create_dt")
private LocalDateTime createDate;
@OneToMany(cascade = CascadeType.ALL)
@JoinColumn(name = "member_id")
private List<MemberDtail> details;
}
[MemberDetail]
@Entity
public class MemberDetail {
@EmbeddedId
private Pk pk;
private String description;
@Embeddable
public static class Pk implements Serializable {
@Column(name = "member_id")
private Long memberId;
private String type;
}
}
[MemberService]
@Transactional
public void createMemberWithDetails() {
Member member = new Member("member1", LocalDateTime.now());
Member savedMember = memberRepository.save(member);
MemberDetail memberDtail1 = new MemberDetail();
memberDtail1.setPk(new MemberDetail.Pk(savedMember.getMemberId(), "type1"));
memberDetail1.setDescription("member1-type1");
MemberDetail memberDtail2 = new MemberDetail();
memberDtail1.setPk(new MemberDetail.Pk(savedMember.getMemberId(), "type2"));
memberDetail1.setDescription("member1-type2");
member.getDetails().add(memberDetail1);
member.getDetails().add(memberDetail2);
}
[실행시 나가는 쿼리]
insert into members values ('2019-11-27T15:20:00.123', 'member1', 1)
insert into member_details values ('member1-type1', 1, 'type1')
insert into member_details values ('member1-type2', 1, 'type2')
update member_details set member_id=1 where member_id=1 and type='type1'
update member_details set member_id=1 where member_id=1 and type='type2'
[Member]
@Entity
public class Member {
@Id
@Column(name = "member_id")
private Long memberId;
private String name;
@Column(name = "create_dt")
private LocalDateTime createDate;
@OneToMany(cascade = CascadeType.ALL, mappedBy = "member")
private List<MemberDtail> details;
}
[MemberDetail]
@Entity
public class MemberDetail {
@EmbeddedId
private Pk pk;
private String description;
@ManyToOne
@MapsId("memberId")
@JoinColumn(name = "member_id")
private Member member;
@Embeddable
public static class Pk implements Serializable {
@Column(name = "member_id")
private Long memberId;
private String type;
}
}
[MemberService]
@Transactional
public void createMemberWithDetails() {
Member member = new Member("member1", LocalDateTime.now());
Member savedMember = memberRepository.save(member);
MemberDetail memberDtail1 = new MemberDetail();
memberDtail1.setPk(new MemberDetail.Pk(savedMember.getMemberId(), "type1"));
memberDetail1.setDescription("member1-type1");
MemberDetail memberDtail2 = new MemberDetail();
memberDtail1.setPk(new MemberDetail.Pk(savedMember.getMemberId(), "type2"));
memberDetail1.setDescription("member1-type2");
member.getDetails().add(memberDetail1);
member.getDetails().add(memberDetail2);
}
[실행시 나가는 쿼리]
insert into members values ('2019-11-27T15:20:00.123', 'member1', 1)
insert into member_details values ('member1-type1', 1, 'type1')
insert into member_details values ('member1-type2', 1, 'type2')
일단 내가 맨위의 포스트의 유튜브 영상에서는 Case2를 일대다의 양방향 연관관계라고 설명한다. 그러나 나는 다대일의 양방향 연관관계라고 생각한다.
이유는 다음과 같다.
영한님 강의에서도 일대다 단방향 매핑보다는 다대일 양방향 매핑을 사용하자!!라고 나와있다.
내 관점에서는 Case1에서 Case2로 바꾼 것을 일대다 단방향 매핑에서 다대일 양방향 매핑으로 바꾼 것이므로 적절한 변환이라고 생각한다.
여기서 의문점이 하나 들 수 있다.
Member의 details는 연관관계의 주인이 아닌데 어째서 member.getDetails().add(memberDetail1);
를 했는데 INSERT쿼리가 나가는거지??
그것은 바로
@OneToMany(cascade = CascadeType.ALL, mappedBy = "member")
private List<MemberDtail> details;
에서 cascade = CascadeType.ALL
부분 때문이다.