일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- java
- vue.js
- 백명석님
- intellij 즐겨찾기
- ksql
- IntelliJ
- findTopBy
- aws
- 자바 ORM 표준 JPA 프로그래밍 정리
- 리눅스
- Linux
- 마이크로 서비스
- ksqldb
- javascript case
- Stream
- 리팩토링 2판
- CompletableFuture
- HandlerMethodArgumentResolver
- #docker compose
- intellij favorites
- 친절한 SQL 튜닝
- 원격 브랜 삭제
- Spring Cloud Netflix
- git
- multipart테스트
- 자바 ORM 표준 JPA 프로그래밍
- intellij 핵심 단축키
- JPA
- @TransactionalEventListener
- @Transactional Propagation
- Today
- Total
시그마 삽질==six 시그마
JPA -다양한 연관관계 매핑 본문
우아한 형제들의 김영한 팀장님의 '자바 ORM 표준 JPA 프로그래밍'을
구입하시길 강력 추천드립니다.
책 구입을 원하시는분은 요기를 클릭하시면 됩니다.
저자 직강 인프런 강의도 있습니다 궁금하신분은 요기를 클릭
하단의 내용은 제가 예전에 읽었던 내용을 요약 정리한 것입니다.
왼쪽을 연관관계 주인으로 할 경우임!
다대일 : 단방향,양방향 <--권장
일대다 : 단방향,양방향 <---비추
일대일 : 주테이블 단방향, 양방향<---권장
일대일: 대상테이블 단방향(비추), 양방향
다대다(연관 엔티티 x): 단방향, 양방향 <--비추 (연관테이블에 추가 컬럼없을시 가능)
다대다(연관 엔티티 o): 양방향만
1)식별관계: 받아온 식별자를 기본키+외래키로 사용 <---비추
2)비식별 관계: 받아온 식별자는 외래키로만 사용하고 새로운 식별자 생성 <---권장
1. 다대일
자세한건 요기를 참조
1)단방향<---권장
@Entity
public class Reply{
@Id
@Column(name=REPLY_ID)
private Long id;
//연관관계 매핑
@ManyToOne
@JoinColumn(name="BOARD_ID")
private Board board;
.....
}
@Entity
public class Board{
@Id
@Column(name=BOARD_ID)
private Long id;
.....
}
2)양방향 <---권장
@Entity
public class Reply{
@Id
@Column(name=REPLY_ID)
private Long id;
//연관관계 매핑
@ManyToOne
@JoinColumn(name="board_id")
private Board board;
.....
}
@Entity
public class Board{
@Id
@Column(name=BOARD_ID)
private Long id;
@OneToMany(mappedBy="board")
private List<Reply> replies= new ArrayList<Reply>();
.....
}
2. 일대다
1)단방향 <---비권장!!
@Entity
public class Board{
@Id
@Column(name=Board_ID)
private Long id;
@ManyToOne
@JoinColumn(name="REPLY_ID") //Reply테이블의 REPLY_ID (FK)
private List<Reply> replies= new ArrayList<Reply>();
.....
}
단점이 매핑한 객체가 관리하는 외래키가 다른 테이블에 있어서 연관관계를 처리하기 위한 update sql을 추가로 실행해야함.
Reply 엔티티 저장시 Board에 대해 모르기에 BOARD_ID 외래키에 아무것도 저장안됨. 대신 Board엔티티 저장시 Board.replies 참조값을 확인해서 Reply테이블의 BOARD_ID 업데이트함.
Reply reply1= new Reply("s1","리플제목1");
Reply reply2= new Reply("s2","리플제목2");
Board board1 = new Board("t1", "보드제목");
board1.getStudent().add(reply1);
board1.getStudent().add(reply2);
em.persist(reply1); //insert reply1
em.persist(reply2);//insert reply2
em.persist(board1 );// insert board1, update-reply1.fk ,update-reply2.fk
2)양방향 <---비권장
일대다 양방향 매핑은 존재하지 않음. 대신 다대일 양방향 매핑을 사용해야함. 그게 논리상 맞음('다'가 항상 주인임)
but 억지로 일대다 단방향 매핑 반대편에 같은 외래키를 사용하는 다대일 단방향 매핑을 읽기전용으로 추가하면되긴함
@Entity
public class Board{
@Id
@Column(name=Board_ID)
private Long id;
@ManyToOne
@JoinColumn(name="REPLY_ID") //Reply테이블의 REPLY_ID (FK)
private List<Reply> replies= new ArrayList<Reply>();
.....
}
@Entity
public class Reply{
@Id
@Column(name=REPLY_ID)
private Long id;
//연관관계 매핑
@ManyToOne
@JoinColumn(name="board_id" ,insertable=false, updatable=false)
private Board board;
.....
}
3.일대일(주테이블에 외래키)
1:1 매핑시에는 DB마인드 보다는 객체지향적 사고가 필요함!!!!
주테이블에 외래키 : 주 객체가 대상 객체 참조하듯 주테이블에 외래키두고 대상 테이블 참조. 객체지향 개발자들이 선호
1) 단방향 <--권장
@Entity
public class Member {
@Id @GeneratedValue
@Column(name = "MEMBER_ID")
private Long id;
private String username;
@OneToOne
@JoinColumn(name = "LOCKER_ID")
private Locker locker;
//...
}
@Entity
public class Locker {
@Id @GeneratedValue
@Column(name = "LOCKER_ID")
private Long id;
private String name;
//...
}
2) 양방향<--권장
@Entity
public class Member {
@Id @GeneratedValue
@Column(name = "MEMBER_ID")
private Long id;
private String username;
@OneToOne
@JoinColumn(name = "LOCKER_ID")
private Locker locker;
//...
}
@Entity
public class Locker {
@Id @GeneratedValue
@Column(name = "LOCKER_ID")
private Long id;
private String name;
@OneToOne(mappedBy = "locker")
private Member member;
//...
}
4.일대일(대상 테이블에 외래키)
대상 테이블에 외래키: DB개발자 선호. 1:1->1:다 확장시 테이블 구조 그대로 유지가능
1)단방향 <--no,no
JPA에서 지원안함
DB는 대상테이블에 외래키 둠/ 엔티티는 주객체가 대상객체 참조(가짐) 어긋남
2)양방향
주테이블에 외래키 경우의 반대로 해주면됨
@Entity
public class Member {
@Id @GeneratedValue
@Column(name = "MEMBER_ID")
private Long id;
private String username;
@OneToOne
@JoinColumn(name = "LOCKER_ID")
private Locker locker;
//...
}
@Entity
public class Locker {
@Id @GeneratedValue
@Column(name = "LOCKER_ID")
private Long id;
private String name;
@OneToOne(mappedBy = "locker")
private Member member;
//...
}
5.다대다(연결 엔티티 미사용)
MEMBER <--MEMBER_ITEM-->ITEM
테이블은 연결테이블이 필요하지만 객체는 객체2개로 다대다 생성 가능
1)단방향
@Entity
public class Member{
@Id
@Column(name=MEMBER_ID)
private String id;
@ManyToMany
@JoinTable(name="MEMBER_ITEM", joinColumns=@JoinColumn(name="MEMBER_ID"),
inverseJoinColumns= @JoinColumn(name="ITEM_ID"))
private List<Item> items=new ArrayList<Item>();
.....
}
@JoinTable.joinColumns: 현재방향 회원과 매핑할 조인컬럼정보 넣음
@JoinTable.jinverseJoinColumns 반대 방향인 상품과 매핑할 조인 컬럼정보 넣음
@Entity
public class Item{
@Id
@Column(name=ITEM_ID)
private String id;
...
}
2)양방향
다대다 양방향 매핑은 단방향과 유사함.
양쪽 중 원하는곳을 선택해서 연관 소유한쪽에 @JoinTable 설정해주면됨. 반대쪽은 MappedBy 설정
@Entity
public class Member{
@Id
@Column(name=MEMBER_ID)
private String id;
@ManyToMany
@JoinTable(name="MEMBER_ITEM", joinColumns=@JoinColumn(name="MEMBER_ID"),
inverseJoinColumns= @JoinColumn(name="ITEM_ID"))
private List<Item> items=new ArrayList<Item>();
.....
}
@Entity
public class Item{
@Id
@Column(name=ITEM_ID)
private String id;
@ManyToMany(mappedBy ="items")//역방향 추기
private List<Member> members;
}
6.다대다(연결 엔티티 사용)
MEMBER ----------MEMBER_ITEM-------------ITEM
기본키-------------> +외래키(FK)
+외래키(FK) <-----------------기본키
-------
=기본키(PK)
위 테이블에서 MEMBER_ITEM가 MEMBER와 ITEM의 기본키외에 별도의 컬럼을 둔다면(ORDER_QUANTITY,ORDER_DATE)
@ManyToMany는 추가된 컬럼 매핑할수 없기에 사용못함
그럴경우 회원상품 엔티티 추가해야함(MemberItem)
1) 방법1: 식별관계 사용하여 복합키 생성<---비추
회원과 상품의 기본키를 각각 받아 회원상품의 기본키이자 외래키로 사용하는것(받아온 식별자를 기본키+외래키로 사용)
복합키를 위한 식별자 클래스 조건(@IdClass 사용)
(1) 별도의 식별자 클래스 만들어야함
(2)Serializable 구현
(3) equals와 hashCode 메소드 구현
(4) 기본생성자
(5)식별자 클래스는 pulbic
@Entity
public class Member{
@Id
@Column(name=MEMBER_ID)
private String id;
@OneToMany(mappedBy ="member")
private List<MemberItem> memberItems;
.....
}
@Entity
public class Item{
@Id
@Column(name=ITEM_ID)
private String id;
@OneToMany(mappedBy ="item")
private List<MemberItem> memberItems;
}
@Entity
@IdClass(MemberItemtId.class)
public class MemberItem{
@Id
@ManyToOne
@JoinColumn(name="MEMBER_ID")
private Member member; //MemberItemId.member와 연결
@Id
@ManyToOne
@JoinColumn(name="ITEM_ID")
private Item item; //MemberItemId.item과 연결
private int orderQuantity;
.....
}
public class MemberItemId{
private String member; //MemberItemId.member와 연결
private String item; //MemberItemId.item과 연결
.....
}
2) 방법2: 비식별관계 (신규 기본키 생성) <----강추
id 기본키 하나 생성
DB에서 자동생성해주는 대리키 Long값으로 사용하는걸 추천
받아온 식별자는 외래키로만 사용 ,새로운 식별자를 추가함
MEMBER ----------MEMBER_ITEM-------------ITEM
기본키(PK)(id)==대리키
기본키-------------> 외래키(FK)
외래키 (FK)<-----------------기본키
@Entity
public class Member{
@Id
@Column(name=MEMBER_ID)
private String id;
@OneToMany(mappedBy ="member")
private List<MemberItem> memberItems;
.....
}
@Entity
public class Item{
@Id
@Column(name=ITEM_ID)
private String id;
@OneToMany(mappedBy ="item")
private List<MemberItem> memberItems;
}
@Entity
public class MemberItem{
@Id @GeneratedValue
@Column(name="ID")
private Long id;
@ManyToOne
@JoinColumn(name="MEMBER_ID")
private Member member; //MemberItemId.member와 연결
@ManyToOne
@JoinColumn(name="ITEM_ID")
private Item item; //MemberItemId.item과 연결
private int orderQuantity;
.....
}
private JPQLQuery<MemberItem> getQuery() {
return from(qMemberItem)
.join(qMemberItem.member).fetchJoin()
.join(qMemberItem.item).fetchJoin()
;
}
'프로그래밍 > JPA' 카테고리의 다른 글
JPA -프록시와 연관관계 관리 (0) | 2020.04.09 |
---|---|
JPA -고급 매핑 (0) | 2020.04.09 |
JPA -연관관계 매핑 (1) | 2020.04.08 |
JPA -Entity Mapping (0) | 2020.04.08 |
JPA -Persistence Management (0) | 2020.04.08 |