티스토리 뷰
| 다양한 연관관계 매핑
|| 다대일
데이터베이트 테이블의 일(1), 다(N) 관계에서 외래 키는 항상 다(N) 쪽에 존재
||| 다대일 단방향 [N:1]
> 회원 엔티티
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | @Entity public class Member { @Id @GeneratedValue @colum(name = "MEMBER_ID") private Long id; private String username; @ManyToOne @JoinColumn(name = "TEAM_ID") private Team team; // Getter, Setter .. } | cs |
> 팀 엔티티
1 2 3 4 5 6 7 8 9 10 11 12 13 | @Entity public class Team { @Id @GeneratedValue @Column(name = "TEAM_ID") private Long id; private String name; // Getter, Setter ... } | cs |
회원은 Member.team으로 팀 엔티티를 참조할 수 있지만,
팀에서는 회원을 참조하는 필드가 없음.
=> 회원과 팀은 단방향 연결관계
||| 다대일 양방향 [N:1, 1:N]
> 회원 엔티티
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 | @Entity public class Member { @Id @GeneratedValue @colum(name = "MEMBER_ID") private Long id; private String username; @ManyToOne @JoinColumn(name = "TEAM_ID") private Team team; public void setTeam(Team team) { this.team = team; // 무한루프 방지 if (!team.getMembers().contatins(this)) { team.getMembers().add(this); } } // Getter, Setter .. } | cs |
> 팀 엔티티
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | @Entity public class Team { @Id @GeneratedValue @Column(name = "TEAM_ID") private Long id; private String name; @OneToMany(mappedBy ="team") private List<Member> members = new ArrayList<Member>(); public void addMember(Member member) { this.members.add(member); // 무한루프 방지 if (member.getTeam() != this) { member.setTeam(this); } } // Getter, Setter ... } | cs |
* 양방향은 외래 키가 있는 쪽이 연관 관계의 주인
- Member.team이 연관관계의 주인
- JPA는 외래 키를 관리할 때 연관관계의 주인만 사용
- 주인이 아닌 Team.members는 조회를 위한 JPQL이나 객체 그래프 탐색 시 사용
* 양방향 연관관계는 항상 서로를 참조해야 함
- getTeam(), getMember()
|| 일대다
일대다 관계는 엔티티를 하나 이상 참조할 수 있으므로 자바 컬렉션 사용
||| 일대다 단방향 [1:N]
일대다 관계에서 외래 키는 항상 다(N)쪽 테이블에 있음
--> 반대편 테이블의 외래 키를 관리
> 팀 엔티티
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | @Entity public class Team { @Id @GeneratedValue @Column(name = "TEAM_ID") private Long id; private String name; @OneToMany @JoinColumn(name = "TEAM_ID") // MEMBER 테이블의 TEAM_ID (FK) private List<Member> members = new ArrayList<Member>(); // Getter, Setter ... } | cs |
> 회원 엔티티
1 2 3 4 5 6 7 8 9 10 11 12 | @Entity public class Member { @Id @GeneratedValue @colum(name = "MEMBER_ID") private Long id; private String username; // Getter, Setter .. } | cs |
* 일대다 단방향 관계 매핑 시 @JoinColumn을 명시
* 일대다 단방향 매핑의 단점은 매핑한 객체가 관리하는 외래 키가 다른 테이블에 있다는 점
--> Member 엔티티는 Team 엔티티를 모르므로 Member의 team 업데이트가 추가적으로 필요
* 일대다 단방향 매핑보다는 "다대일 양방향 매핑을 사용"
||| 일대다 양방향 [1:N, N:1]
일대다 양방향 매핑은 존재하지 않음.
대신 다대일 양방향 매핑을 사용
|| 일대일
- 일대일 관계는 양쪽이 서로 하나의 관계만 가짐
- 테이블 관계에서 항상 다(N)쪽이 외래 키를 가졌지만,
일대일 관계는 주 테이블이나 대상 테이블 둘 중 어느 곳이나 외래 키를 가질 수 있음
- 일대일 관계는 주 테이블이나 대상 테이블 중 누가 외래 키로 가질지 선택해야 함
ㅇ 주 테이블에 외래 키
- 주 테이블에 외래 키를 두고 대상 테이블을 참조
- 주 테이블만 확인해도 대상 테이블과 연관관계 확인 가능
ㅇ 대상 테이블의 외래 키
- 테이블 관계를 일대다로 변경할 때 테이블 구조 유지 가능
||| 주 테이블에 외래 키
JPA는 주 테이블에 외래 키가 있으면 더 편리하게 매핑
> 단방향
- 다대일 단방향(@ManyToOne)과 유사
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 29 | @Entity public class Member { @Id @GeneratedValue @colum(name = "MEMBER_ID") private Long id; private String username; @OneToOne @JoinColumn(name = "LOCKER_ID") private Locker locker; // Getter, Setter .. } @Entity public class Locker { @Id @GeneratedValue @colum(name = "LOCKER_ID") private Long id; private String name; // ... } | cs |
> 양방향
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 29 30 31 32 | @Entity public class Member { @Id @GeneratedValue @colum(name = "MEMBER_ID") private Long id; private String username; @OneToOne @JoinColumn(name = "LOCKER_ID") private Locker locker; // Getter, Setter .. } @Entity public class Locker { @Id @GeneratedValue @colum(name = "LOCKER_ID") private Long id; private String name; @OneToOne(mappedBy = "locker") private Member member; // ... } | cs |
||| 대상 테이블에 외래 키
> 단방향
- 일대일 관계 중 대상 테이블에 외래 키가 있는 단방향 관계는 JPA에서 지원하지 않음
- 단방향 관계를 Locker에서 Member 방향으로 수정하거나,
양방향 관계로 만든 후 Locker를 연관관계의 주인으로 설정해야 함
> 양방향
- 일대일 매핑에서 대상 테이블에 외래 키를 두고 싶을 경우
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 29 30 31 32 | @Entity public class Member { @Id @GeneratedValue @colum(name = "MEMBER_ID") private Long id; private String username; @OneToOne(mappedBy = "member") private Locker locker; // ... } @Entity public class Locker { @Id @GeneratedValue @colum(name = "LOCKER_ID") private Long id; private String name; @OneToOne @JoinColumn(name = "MEMBER_ID") private Member member; // ... } | cs |
|| 다대다
- "관계형 데이터베이스"는 정규화 된 테이블 2개로 다대다 관계를 표현할 수 없음
ㄴ 보통 다대다 관계를 일대다, 다대일 관계로 풀어냄
- "객체"는 테이블과 다르게 객체 2개로 다대다 관계 표현 가능
||| 단방향
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 29 30 | @Entity public class Member { @Id @colum(name = "MEMBER_ID") private String id; private String username; @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; // ... } | cs |
||| 양방향
- 역방향도 @ManyToMany 추가 후 원하는 곳에 mappedBy로 연관관계의 주인 지정
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | @Entity public class Product { @Id @Column(name ="PRODUCT_ID") private String id; private String name; @ManyToMany(mappedBy = "products") // 역방향 private List<Member> members; // ... } | cs |
||| 연결 엔티티 사용
실무에서 "주문 수량"이나 "주문 날짜"와 같은 필요한 컬럼이 추가되므로
@ManyToMany 매핑은 실무에서 사용하기에 한계가 있음
엔티티 간의 관계도 테이블 관계처럼 다대다 -> 일대다 or 다대다 -> 다대일
관계로 풀어야 함
식별 관계 : 기본 키 + 외래 키
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 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 | @Entity public class Member { @Id @colum(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 = "MEMBER_ID") private Member member; // MemberProductId.member와 연결 @Id @ManyToOne @JoinColumn(name = "PRODUCT_ID") private Product product; // MemberProductId.product와 연결 pricate int orderAmount; // ... } public class MemberProductId implements Serializable { private String member; // MemberProduct.member와 연결 private String product; // MemberProduct.product와 연결 public MemberProductId() {} public MemberProductId(String member, String product) { this.member = member; this.product = product; } @Override public boolean equals(Object o) { .. } @Override public int hashCode() { .. } } | cs |
* JPA에서 복합 키를 사용하려면 별도의 식별자 클래스를 만들어야 함.
그리고, @IdClass를 사용해서 복합키(식별자 필드가 2개 이상)를 위한 식별자 클래스를 지정.
ㄴ 식별자 클래스에 equals와 hashCode를 구현 (식별자 구분을 위함)
* 복합 키를 위한 식별자 클래스의 특징
- 복합 키는 별도의 식별자 클래스로 만들어야 함
- 식별자 클래스의 속성명과 엔티티에서 사용하는 식별자의 속성명이 같아야 함
- Serializable을 구현
- equals와 hashCode 메소드 구현
- 기본 생성자 필요
- 식별자 클래스는 public
* 복합 키를 사용하는 방법은 복잡하여
복합 키를 사용하지 않고 새로운 기본 키를 사용
||| 새로운 기본 키(대리 키) 사용
- 데이터베이스에서 자동으로 생성해주는 대리 키를 사용하는 방법
ORM 매핑 시 복합 키를 만들지 않아도 되므로 간단히 매핑을 수행
비식별 관계
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 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | @Entity public class Member { @Id @colum(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 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; // ... } | cs |
* 비식별 관계를 사용하는 것이 복합 키를 위한 식별자 클래스를 만들지 않아도 되므로,
단순하고 편리하게 ORM 매핑이 가능
출처 : 자바 ORM 표준 JPA 프로그래밍
'Books' 카테고리의 다른 글
[JPA] JPQL Query 정리 (0) | 2020.12.22 |
---|---|
[JPA] 고급 매핑(상속관계, 복합키, 식별/비식별, 조인 테이블) (0) | 2020.12.21 |
[JPA] 연관관계 매핑이란.? (0) | 2020.12.19 |
[JPA] 엔티티와 매핑. @Entity, @Table, @Id, @Column.. (0) | 2020.12.18 |
[JPA] 영속성(persistence)이란? (0) | 2020.12.18 |