Notice
Recent Posts
Recent Comments
Link
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
Tags
- chapter02
- 이것이 MySQL이다
- bisection
- chapter01
- 알고리즘대회
- Fisher discriminant analysis
- CH01
- 스터디
- 알고리즘
- 개발순서
- Numerical optimization
- 자바ORM표준JPA프로그래밍
- secant
- MySQL
- Perceptron Convergence theorem
- 델타 rule
- 근구하기
- 5397번
- 로지스틱 회귀
- SCPC
- 선형판별분석
- falsePosition
- vector미분
- 선형분류
- 인공지능
- 2018
- 1차예선
- undirected graphical model
- directed graphical model
- graphical models
Archives
- Today
- Total
computer_study
[JPA] 06. 다양한 연관관계 매핑 본문
엔티티의 연관관계를 매핑할 때 고려해야 할 3가지
- 다중성(다대일, 일대다, 일대일, 다대다) - 실무에선 보통 다대일과 일대다 관계를 많이 사용한다.
- 단방향, 양방향 - 객체에서 한 쪽만 참조하는 것이 단방향, 양쪽 서로 참조는 양방향
- 연관관계의 주인 - 연관관계의 주인만이 외래 키를 변경할 수 있다. 주인이 아닌 곳에 mappedBy([주인 이름]) 을 사용한다.
1. 다대일
- 다대일 관계의 반대 방향은 항상 일대다 관계
- 데이터베이스 테이블의 '일', '다' 관계에서 외래 키는 항상 '다' 쪽에
- 객체 양방향 관계에서 연관관계의 주인은 항상 다쪽 (회원(N)과 팀(1)이 있으면 회원 쪽이 연관관계의 주인)
- 5장에서 살펴본 내용들이 다대일의 단방향, 양방향
- 양방향 연관관계는 항상 서로 참조해야 한다.
- 서로 참조를 위해 편의 메소드를 작성해주는데, 양 쪽에 메소드를 작성한다면 무한루프에 빠지지 않도록 주의해야한다.
2. 일대다
- 다대일 관계의 반대방향
- 엔티티를 하나 이상 참조할 수 있으므로 Collection, List, Set, Map중에 하나를 사용해야 한다.
단방향
- 하나의 팀이 여러 회원을 참조할 수 있으면 일대다 관계
- 팀이 회원들을 참조하지만, 회원이 팀을 참조하지 않는다면 단방향 관계
- 일대 다 관계에서 외래키는 항상 '다'쪽에
- Member가 다 쪽이지만, Member에 외래키를 매핑할 수 있는 필드가 없기에 참조 필드(members)가 있는 Team에서 MEMBER의 FK를 관리하게 된다.
- 일대다 단방향 관계를 매핑할 때 @JoinColumn을 명시해야 한다.(아니면 JPA는 joinTable전략을 기본으로 하여 매핑. 7.4)
- 일대 다 매핑의 단점
- 매핑한 객체가 관리하는 외래키가 다른 테이블에 있다는 점
- 엔티티 저장과 연관관계 처리 시, INSERT 뿐만 아니라 UPDATE 까지 추가로 실행해야 한다.
- 일대 다 보단 다대일 양방향 매핑 사용이 좋다.
- 성능과 관리의 편함을 위하여.
양방향
- 따로 존재하지 않고, 다대일 양방향 매핑을 사용해야 한다.(일대다 양방향이나 다대일 양방향은 사실 같은 말)
- '다'쪽이 항상 주인이 되기에 일대다에서 @OneToMany쪽에 주인이 될 수 없다.
- 하지만 일대다 단방향 매핑 반대편에 같은 외래 키를 사용하는 다대일 단방향 매핑을 읽기전용으로 추가하여 양방향 매핑을 사용할 수는 있다.
- 단방향과 마찬가지의 단점을 그대로 가지기에, 될 수 있으면 다대일 양방향을 사용하도록 한다.
Member
@Entity
public class Member{
// 다대일 단방향, 양방향 / 일대다 단방향
@Id @GeneratedValue
@Column(name = "MEMBER_ID")
private String id;
private String username;
// 다대일 단방향, 양방향//
@ManyToOne
@JoinColumn(name="TEAM_ID")
private Team team;
// 일대다 양방향
// 읽기만 가능하게 해서 문제 발생을 막는다
// 일대다 단방향 반대편에 다대일 단방향 매핑을 읽기 전용으로 두어 일대다 양방향처럼 보이도록
@ManyToOne
@JoinColumn(name= "TEAM_ID", insertable = false, updatable=false)
private Team team;
}
Team
@Entity
public class Team{
@Id @GeneratedValue
@Column(name="TEAM_ID")
private String id;
private String name;
// 다대일 양방향
@OneToMany(mappedBy="team")
private List<Member> members = new ArrayList<Member>();
// 일대다 단뱡향, 양방향
@OneToMany
@JoinColumn(name = "TEAM_ID") // MEMBER테이블의 TEAM_ID(FK)
private List<Member> members = new ArrayList<Member>();
...
}
3. 일대일
- 양쪽이 서로 하나의 관계만 가진다. (ex. 회원은 하나의 사물함만 사용)
- 일대일 관계는 그 반대도 일대일
- 일대일 관계는 주 테이블이나 대상 테이블 중 어느 곳이나 외래키를 가질 수 있다.(둘 중 선택해야 한다.)
- 주 테이블에 외래 키
- 주 테이블에 외래 키를 두고 대상 테이블을 참조
- 주 테이블만 확인해도 대상 테이블과 연관관계가 있는지 알 수 있다.
- 객체 지향적임
- 대상 테이블에 외래 키
- 테이블 관계를 일대일에서 일대다로 변경할 때, 테이블 구조를 그대로 유지할 수 있다.
3.1 주 테이블에 외래 키
단방향
- LOCKER_ID 외래키에 유니크 제약조건 추가 (UNI)
양방향
3.2 대상 테이블에 외래 키
단방향
- 대상 테이블에 외래 키가 있는 단방향 관계는 JPA에서 지원하지 않는다.
- 단방향 관계를 Locker에서 Member방향으로 수정하여 대상 테이블을 바꾸거나, 양방향 관계로 만든 후 Locker를 주인으로 설정해야 한다.
양방향
코드 예시
@Entity
public class Member{
// 단방향, 양방향
@Id @GeneratedValue
@Column(name = "MEMBER_ID")
private Long id;
private String username;
@OneToOne // 일대일 관계
@JoinColumn(name = "LOCKER_ID")
private Locker locker;
// 대상 테이블 외래키 양방향
@OneToOne(mappedBy = "member")
private Locker locker;
}
@Entity
public class Locker{
// 단방향
@Id @GeneratedValue
@Column(name = "LOCKER_ID")
private Long id;
private String name;
// 양방향
// MEMBER테이블이 외래 키를 가지고있으므로 Member.lock이 주인
// Locker.member는 주인이 아니라고 설정해야 하기에 mappedBy
@OneToOne(mappedBy = "locker")
private Member member;
// 대상 테이블 외래키 양방향
// 대상 엔티티인 Locker를 연관관계의 주인으로 만들어서 LOCKER테이브르이 외래 키를 관리하도록 함
@OneToOne
@JoinColumn(name = "MEMBER_ID")
private Member member;
}
4. 다대다
- 관계형 DB는 정규화된 테이블 2개로 다대다 관계를 표현할 수 없다.
- 중간에 연결 테이블을 추가해서 다대다 관계를 일대다/다대일 관계로 풀어낼 수 있다.
- (회원들이 상품을 주문하는 경우가 다대다 관계)
- 객체는 테이블과 다르게 2개로 다대다 관계를 만들 수 있다.
4.1 단방향
@Entity
public class Member{
@Id @Column(name = "MEMBER_ID")
private String id;
private String username;
// ManyToMany로 매핑하면서 JoinTable을 사용해 연결 테이블을 바로 매핑
@ManyToMany
@JoinTable(name="MEMBER_PRODUCT", // 다대다를 일대다/다대일 로 풀어내기 위한 연결 테이블 지정
joinColumns = @JoinColumn(name = "MEMBER_ID"), // 현재 방향인 회원과 매핑할 조인 컬럼 정보를 지정
inverseJoinColumns = @JoinColumn(name = "PRODUCT_ID")) // 반대 방향인 상품과 매핑할 조인 컬럼 정보
private List<Product> products = new ArrayList<Product>();
...
}
@Entity
public class Product{
@Id @Column(name="PRODUCT_ID")
private String id;
private String name;
}
4.2 양방향
단뱡향 product에 역방향만 추가하면 된다.
@Entity
public class Product{
@Id @Column(name="PRODUCT_ID")
private String id;
private String name; // 책 예시에는 없음
@ManyToMany(mappedBy = "products") // 역방향 추가
private List<Member> members;
}
4.3 매핑의 한계와 극복, 연결 엔티티 사용(식별관계)
- 다대다 매핑을 실무에서 하기엔 한계가 있다.
- MemberProduct에 주문 수량, 주문 날짜와 같은 컬럼이 추가된다면, 이들을 매핑 할 방법이 없다.
- 떄문에 연결 테이블을 매핑하는 연결 엔티티를 만들고 이곳에 추가한 컬럼을 매핑한다.
@Entity
public class Member{
@Id @Column(name = "MEMBER_ID")
private String id;
private String username;
@OneToMany(mappedBy = "member")
private List<MemberProduct> memberProducts;
...
}
@Entity
public class Product{
@Id @Column(name="PRODUCT_ID")
private String id;
private String name;
}
@Entity
@IdClass(MemberProductId.class) // 복합 기본 키를 매핑, 아래 식별자 클래스를 지정하면 된다
public class MemberProduct{
@Id // 기본키
@ManyToOne
@JoinColumn(name = "MEMBEWR_ID") // 외래키 한번에 매핑
private Member member;
@Id
@ManyToOne
@JoinColumn(name = "PRODUCT_ID")
private Product product;
// 기본 키가 MEMBER_ID, PRODUCT_ID인 복합 기본 키
private int orderAmount;
}
// 복합키를 사용하기 위한 별도의 식별자 클래스
public class MemberProductId implements Serializable{
private String member;
private String product;
@Override // equals, hashCode 메소드를 구현해야 한다.
public boolean equals(Object o){...}
@Override
public int hashCode(){...}
...
}
4.4 새로운 기본 키 사용(비식별관계)
- 간단하고 추천하는 기본 키 생성 전략은 데이터베이스에서 자동으로 생성해주는 대리 키를 Long값으로 사용하는 것
- 복합 키를 사용하는 것 보다 매핑이 단순하고 이해하기 쉬워진다. (편리하게 ORM 매핑을 할 수 있어 비식별 관계를 추천)
- ORDER_ID라는 새로운 기본 키 하나를 만들고, MEMBER_ID, PRODUCT_ID 컬럼을 외래키로만 사용할 수 있다.
@Entity
public class Member{
@Id @Column(name = "MEMBER_ID")
private String id;
private String username;
@OneToMany(mappedBy = "member")
private List<Order> orders = new ArrayList<Order>();
...
}
@Entity
public class Product{
@Id @Column(name="PRODUCT_ID")
private String id;
private String name;
}
@Entity
public class Order{
@Id @GeneratedValue
@Column(name = "ORDER_ID")
private Long id;
@ManyToOne
@JoinColumn(name = "MEMBER_ID")
private Member member;
@ManyToOne
@JoinColumn(name = "PRODUCT_ID")
private Product product;
private int orderAmount;
...
}
'스터디 > 자바 ORM표준 JPA 프로그래밍' 카테고리의 다른 글
[JPA] 08. 프록시와 연관관계 관리 (0) | 2022.08.22 |
---|---|
[JPA] 07. 고급 매핑 (0) | 2022.08.08 |
[JPA] 05. 연관관계 매핑 기초 (0) | 2022.07.25 |
[JPA] 04. 엔티티 매핑 (0) | 2022.07.11 |
[JPA] 03. 영속성 관리 (0) | 2022.06.29 |
Comments