연관관계 매핑을 정리해두고, JPA에서는 어떻게 사용하는지 정리해 두려고 한다.
- 방향 : 회원/팀 기준
- 단방향 : 회원 → 팀 or 팀 → 회원 둘 중 한 쪽만 다른쪽을 참조하는 관계
- 양방향 : 회원 → 팀, 팀 → 회원 둘이 서로를 참조하는 관계
- 다중성
- 1:1 (일대일)
- 1:N (일대다 혹은 다대일)
- N:M (다대다)
- 연관관계의 주인 : 양방향 연관관계를 만들 때 연관 관계의 주인을 정해야 한다. => 누가 주인인지 꼭 필요.
단방향 :
회원은 하나의 팀에만 소속될수 있다. => 회원과 팀은 다대일 관계
쿼리를 한번 확인해보자.
- 회원 중심 조회
SELECT *
FROM MEMBER M
INNER JOIN TEAM T ON M.TEAM_ID = T.TEAM_ID
- 팀 중심 조회
SELECT *
FROM TEAM T
INNER JOIN MEMBER M ON M.TEAM_ID = T.TEAM_ID
이걸 자바객체로 만들어보자.
- 회원중심
class Team {
Long id;
String teamName;
..getter ..setter
}
class Member {
Long id;
String memberName;
Team team;
..getter ..setter
}
// 참조
Member a = new Member();
a.getTeam.getId();
- 팀중심
class Team {
Long id;
String teamName;
Member id;
...getter setter
}
class Member {
Long id;
String memberName;
...getter setter
}
// 참조
Team a = new Team();
a.getMember.getId();
객체는 양방향 참조를위해 두 객채에 각각 참조할 대상을 필수로 가지고있어야한다.. 당연..!
쿼리와 객체에서의 차이점만 살짝보고~
객체 관계 매핑을 JPA활용하여 만들어보면서 이해하도록 하자.
1). Team Class
@Entity
@Getter
@Setter
public class Team {
@Id
@Column (name = "TEAM_ID")
private Long id;
private String teamName;
}
2). Member Class
@Entity
@Getter
@Setter
public class Member {
@Id
@Column (name = "MEMBER_ID")
private Long id;
private String memberName;
@ManyToOne
@JoinColumn (name = "TEAM_ID")
private Team team;
}
@ManyToOne 과 @JoinColumn을 통해 다대일 관계를 나타냈다.
하나씩 이해해보자.
@ManyToOne
- 속성
- optional (default true) : false로 설정하면 연관된 엔티티가 반드시 존재해야한다.
- fetch : 글로벌 패치 전략 설정 (Lazy or Eager)
- cascade : 영속성 전이 기능 사용
- targetEntity : 연관된 엔티티의 타입 정보 설정 (targetEntity = Member.class 식으로 사용)
@JoinColumn(name="TEAM_ID")
- 외래 키 매핑
- name 속성은 매핑할 외래키의 이름
- 어노테이션을 생략해도 외래 키 생성
- 생략 시 외래키의 이름이 기본 전략을 활용하여 생성
- 속성
- name : 매핑할 외래 키의 이름
- referencedColumnName : 외래 키가 참조하는 대상 테이블의 컬럼명
- foreignKey : 외래 키 제약조건 지정 (테이블 생성 시에만 적용됨)
- unique/nullable/insertable/updateable/columnDefinition/table : @Column의 속성과 같음
사용할때는 member에 team을 넣어주는 방식으로 사용하는데, 내부적으로 entityManager가 persist(); 할때 team객체에 id가 부여된다 => 중요
양방향 :
양방향 관계는 양쪽에서 서로를 참조하고 있는 상태이다.
양방향 관계를 가지는 엔티티를 만들어보자.
1). Team Class
@Entity
@Getter
@Setter
public class Team {
@Id
@Column (name = "TEAM_ID")
private Long id;
private String teamName;
@OneToMany (mappedBy = "team")
private List<Member> members = new ArrayList<>();
}
2). Member Class
@Entity
@Getter
@Setter
public class Member {
@Id
@Column (name = "MEMBER_ID")
private Long id;
private String memberName;
@ManyToOne
@JoinColumn (name = "TEAM_ID")
private Team team;
}
Team에 @OneToMany 어노테이션을 추가해줬다.
Team1개에 여러명의 회원이 있을수 있으니, List<Member> List로 필드를 추가한다.
mappedBy 속성은 반대 클래스의 매핑 값(MemberClass에 Team team) 을 부여하면 된다. => 양방향이기 때문에 고유키를 서로 외래키로 하지 않아도 되지만 외래키의 위치를 잡기 위해 사용한다.
연관관계의 주인이란?
연관관계의 주인은 외래키를 가지고있는 엔티티가 주인이다 !!!!
즉 mappedBy는 주인을 지칭하는거로 생각하면 된다.
==> Team.members은 mappedBy = "team" => Member.team을 사용한다고 보면된다.
양방향 연관관계 저장시 주의사항
주인이 아닌 필드는 변경해도 변경저장이 되지않는다.
코드를 한번보자.
private void updateEntity(EntityManager em) {
Team team = em.find(Team.class, team_id);
// Member 내용은 저장되지 않음
team.getMembers.add(
Member.builder()
.name("member3")
.build();
);
// 저장됨
Member member = em.find(Member.class, member1_id);
member1.setTeam(team2);
}
왜 이런지 확인해보자.
물리적인 DB Team 에는 Member관련 컬럼이 없다!! 그래서, member에 Team을 등록할때는 Team정보가 저장되지만 Member관련 정보는 저장되지 않는다.
천천히 한걸음씩~
'JPA' 카테고리의 다른 글
[JPA] @Embedded @Embeddable 이란? 예제 (0) | 2021.08.17 |
---|---|
[JPA] No serializer found for class org.hibernate.proxy.pojo.bytebuddy.ByteBuddyInterceptor and no properties discovered to create BeanSerializer 오류 (0) | 2021.08.11 |
[JPA] SpringBoot + JPA @EnableJpaAuditing 이란? (0) | 2021.07.23 |
[JPA] SpringBoot Jpa 에서 Querydsl 세팅시 Qclass 못찾는 경우 (0) | 2021.07.22 |
[JPA] JPA Repository 메서드 명명규칙 (0) | 2021.04.14 |