시그마 삽질==six 시그마

JPA -다양한 연관관계 매핑 본문

프로그래밍/JPA

JPA -다양한 연관관계 매핑

Ethan Matthew Hunt 2020. 4. 9. 18:05
우아한 형제들의 김영한 팀장님의  '자바 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
Comments