자바 ORM 표준 JPA 프로그래밍 - 기본편을 공부하며 정리한 내용입니다.
자바 ORM 표준 JPA 프로그래밍 - 기본편 - 인프런 | 강의
JPA를 처음 접하거나, 실무에서 JPA를 사용하지만 기본 이론이 부족하신 분들이 JPA의 기본 이론을 탄탄하게 학습해서 초보자도 실무에서 자신있게 JPA를 사용할 수 있습니다., - 강의 소개 | 인프런
www.inflearn.com
✅다대일 [N:1]
단방향
- 가장 많이 사용하는 연관관계
public class Member{
@Id @GeneratedValue
private Long id;
@Column(name = "USERNAME")
private String name;
@ManyToOne
@JoinColumn(name = "TEAM_ID") // 생략 가능 jpa가 자동으로 "클래스이름" + "_ID"로 매핑
private Team team;
}
------------------------------------
public class Team{
@Id @GeneratedValue
private Long id;
private String name;
}
@JoinColumn 어노테이션을 생략하면 아래와 같은 전략에 따라 외래 키를 매핑합니다.
필드명 + “_” + 참조하는 테이블의 기본 키(@Id) 컬럼명
외래키에 TEAM의 기본키를 매핑 시켜주면 된다.
양방향
- 다대일에서 다 가 연관관계의 주인이 된다. (외래키가 있는 쪽이 연관관계의 주인!)
Member
public class Member{
@Id @GeneratedValue
private Long id;
@Column(name = "USERNAME")
private String name;
@ManyToOne
@JoinColumn(name = "TEAM_ID")
private Team team;
// getter, setter ..
}
Team
public class Team{
@Id @GeneratedValue
private Long id;
private String name;
@OneToMany(mappedBy = "team")
private List<Member> members;
// getter, setter ..
}
단방향에서 Team에 컬렉션을 추가 시켜주기만 하면 된다.
양방향 매핑시 값 넣을 때 실수하지 말기!!
// team 생성
Team team = new Team();
team.setName("team 1");
// member 생성
Member member1 = new Member();
member1.setName("member1");
em.persist(member1);
// member -> Team에 넣어준다.
team.getMembers().add(member1);
실행을 하면?
당연하게도 member의 team_id가 안들어갔다. 왜 그런지 까먹었다면 다시 공부하자 .. 연관관계의 주인(Owner)
[5 - 3) 연관관계 매핑 기초 - 양방향 연관관계의 주인
자바 ORM 표준 JPA 프로그래밍 - 기본편을 공부하며 정리한 내용입니다. 자바 ORM 표준 JPA 프로그래밍 - 기본편 - 인프런 JPA를 처음 접하거나, 실무에서 JPA를 사용하지만 기본 이론이 부족하신 분들
iseunghan.tistory.com](https://iseunghan.tistory.com/173?category=934316)
이유는, team이 연관관계의 주인이 아니라서 이다. 그렇기 때문에 값이 제대로 안들어간 것이고,
..
team.getMembers().add(member);
member.setTeam(team); // * 중요 *
member에 team을 설정해주면 된다!
✅일대다 [1:N] (이 모델은 권장하지 않음)
일대다 단방향 매핑보다는 다대일 양방향 매핑을 사용하는게 좋다.
왜 그런지는 함께 살펴보도록 하겠습니다.
- 일대다 단방향
코드
Team
@Entity
public class Team {
@Id @GeneratedValue
private Long id;
private String name;
@OneToMany
@JoinColumn(name = "TEAM_ID") // 조금 이상한 부분(?), 외래키를 매핑해준다 (연관관계의 주인으로 설정)
private List<Member> members = new ArrayList<>();
// getter, setter..
}
@JoinColumn 을 꼭 해줘야 한다. 안그러면 join table로 되어 중간 테이블이 생성되게 된다.
Member
@Entity
public class Member {
@Id @GeneratedValue
private Long id;
private String name;
// getter, setter ..
}
Main
// team을 만들어 준다.
Team team = new Team();
team.setName("team 1");
// member 3명 생성
Member member1 = new Member();
member1.setName("member1");
em.persist(member1);
Member member2 = new Member();
member2.setName("member2");
em.persist(member2);
Member member3 = new Member();
member3.setName("member3");
em.persist(member3);
// member들을 Team에 넣어준다. (연관관계 주인만 수정,삭제 가능!!)
team.getMembers().add(member1);
team.getMembers().add(member2);
team.getMembers().add(member3);
em.persist(team);
tx.commit();
실행을 해주면,
insert 쿼리가 총 4개 (member 3개, team 1개) 가 잘 나간것을 확인할 수 있다.
그런데?
?!!
나는 분명 team에 있는 members (List)를 받아와서 add(member1,2,3)을 해줬는데, 왜 update M**ember 쿼리가 나가는 거지?** 라고 할 수 있다.
이유는 간단하다. 연관관계의 주인은 Team으로 설정 되었지만, 외래키의 위치는 (일대다의 다에 해당하는) member테이블에 있기 때문에, team에 add를 해도 쿼리는 Member에 대해서 나가게 된다.
- 엔티티가 관리하는 외래키가 다른 테이블에 있다.
- 외래키가 Team 테이블이 아닌, Member 테이블에 있기 때문에 연관관계 관리를 위해 추가로 UPDATE SQL 실행
- 일대다 양방향
Member
@Entity
public class Member {
@Id @GeneratedValue
private Long id;
private String name;
@ManyToOne
private Team team; // team만 넣어준다.
// getter, setter ..
}
✅일대일 [1:1]
🚀가장 선호하는 방법__ 주 테이블의 외래 키 단방향, 양방향
- 단방향
- 외래키의 위치를 선택 가능
- 외래키에 데이터베이스 유니크(UNI) 제약조건 추가
일대일 단방향 생각해보기
외래키를 어디에 넣을지 주테이블을 먼저 정해야한다. 객체지향적으로 봤을 때, Member가 Locker를 가지고 있지 않을 순 있어도 Locker가 Member가 없는데 할당된 것은 뭔가 이상하다. 회원이 생기면 그때 락커를 하나 배정해주는 것이다. 그렇기 때문에 객체지향관점으로 봤을 때 Member가 Locker를 소유하고 있는게 더 자연스럽다. 그래서 Member가 주테이블이 된다.
public class Member{
@Id @GeneratedValue
private Long id;
@Column(name = "USERNAME")
private String name;
@OneToOne
@JoinColumn(name = "LOCKER_ID")
private Locker locker;
}
--------------------------------
public class Locker{
@Id @GeneratedValue
private Long id;
private String name;
}
다대일(@ManyToOne) 단방향 매핑과 유사하다.
- 양방향
- 다대일 양방향 매핑 처럼 외래키가 있는 곳이 연관관계 주인
- 반대편은 mappedBy 적용
public class Member{
@Id @GeneratedValue
private Long id;
@Column(name = "USERNAME")
private String name;
@OneToOne
@JoinColumn(name = "LOCKER_ID")
private Locker locker;
}
--------------------------------
public class Locker{
@Id @GeneratedValue
private Long id;
private String name;
@OneToOne(mappedBy = "locker")
private Member member;
}
주인이 아닌쪽에 mappedBy를 사용해서 매핑시켜준다.
대상 테이블에 외래키 단방향, 양방향
- 대상 테이블에 외래키 단방향 정리
- 단방향 관계는 JPA가 지원 X
- 양방향 관계는 지원 O
- 대상 테이블에 외래키 양방향
- 일대일 주 테이블에 외래키 양방향 매핑방법과 같음