객체연관관계와 테이블 연관관계를 매핑할 때 고려해야할 3가지
1. 방향(Direction)
- 단방향, 양방향
- 게시글, 게시판 관계가 있을 때
- 게시글 -> 게시판 또는 게시판 -> 게시글 둘 중 한 쪽만 참조한다면 단방향 관계
- 게시글 -> 게시판, 게시판 -> 게시글 양쪽 모두 서로 참조하는 것은 양방향 관계
- 방향은 객체 관계에만 존재하고, 테이블은 항상 양바향
2. 다중성(Multiplicity)
- 다대일(N:1), 일대다(1:N), 일대일(1:1), 다대다(N:M)
- 게시글, 게시판 관계가 있을 때
- 여러 게시글은 한 게시판에 속하므로 게시글:게시판 = N:1
- 한 게시판에 여러 게시글에 속하믄로 게시판:게시글 = 1:N
3. 연관관계의 주인(owner)
- 객체를 양방향 연관관계로 만들면 연관관계의 주인을 정해야한다.
객체 연관관계와 테이블 연관관계의 가장 큰 차이
참조를 통한 연관관계는 언제나 단방향. 객체간에 연관관계를 양방향으로 만들고 싶으면 반대쪽에도 필드를 추가 해서 참조를 보관해야한다. 결국 연관관계를 하나 더 만들어야한다. 하지만 이것은 엄밀히 말하면 양방향 관계가 아니라 서로 다른 단방향 관계 2개이다. 반면에 테이블은 외래키 하나로 양방향으로 조인할 수 있다.
단방향 관계(A -> B)
class A {
B b;
}
class B{}
양방향 관계(A <-> B)
class A {
B b;
}
class B {
A a;
}
객체 연관관계 VS 테이블 연관관계 정리
테이블 구조가 위와 같을 때, JPA를 사용해서 둘의 관계를 매핑해보자.
게시글 엔티티
@Entity
@Getter
@Setter
public class Post {
@ID
@Conumn(name = "POST_ID")
private Long id;
private Strin username;
// 연관 관계 매핑
@ManyToOne
@JoinColumn(name = "BOARD_ID")
}
게시판 엔티티
@Entity
@Getter
@Setter
public class Board {
@Id
@Column(name ="BOARD_ID")
private Long id;
private String name;
}
게시글 엔티티는 게시판 엔티티에 N:1(단방향 관계를 갖는다.)
@JoinColumn은 외래키를 매핑할 때 사용한다.
속성 | 기능 | 기본값 |
---|---|---|
name | 매핑할 외래키 이름 | "필드명" + _ + 참조하는 테이블의 "기본키 컬럼명" |
referencedColumnName | 외래키가 참조하는 대상 테이블의 컬럼명 | 참조하는 테이블의 "기본키 컬럼명" |
@ManyToOne
private Board board;
만약 위과 같이 @JoinColunn을 생략한다면 외래키를 찾을 때 기본전략을 사용한다.
다대일 관계에서 사용한다.
속성 | 기능 | 기본값 |
---|---|---|
optional | flase로 설정하면 연된 엔티티가 항상 있어야한다. | true |
fetch | 글로벌 페치 전략 | @ManyToOne=FetchType.EAGER, @OneToMany=FethchType.LAZY |
cascade | 연속성 전이 기능 |
게시글에서 게시판으로만 접근하는 단방향 매핑을 알아보았다. 이번엔 게시판에서 게시글로 접근하는 관계를 추가하여 게시글 -> 게시판, 게시판 -> 게시글로 접근할 수 있도록 양방향 연관관계 매핑을 알아보자.
게시판 엔티티
@Entity
@Getter
@Setter
public class Board {
@Id
@Column(name ="BOARD_ID")
private Long id;
private String name;
// 연관관계 추가
@OneToMany(mappedBy = "board")
private List<post> postList = new ArrayList<>();
}
mappedBy 속성은 양방향 매핑일 때만 사용하는데, 반대쪽 매핑의 필드값을 주면된다.(Post 클래스의 Board 매핑 필드값인 board)
@OneToMany의 mappedBy는 왜 필요한가?
객체에는 양방향 연관관계라는 것이 없다. 서로 다른 단방향 연관관계 2개를 묶어 양방향인 것처럼 보이게 하는 것이다.(데이터베이스는 외래키 하나로 양방향 연관관계를 맺음)
객체 연관관계
테이블 연관관계
엔티티를 단방향으로 매핑하면 참조를 하나만 사용하므로 이 참조로 외래키를 관리하면된다. 엔티티를 양방향으로 매핑하면 게시글 -> 게시판, 게시판 -> 게시글 두곳에서 서로를 참조한다. 따라서 객체의 연관관계를 관리하는 포인트가 2곳으로 늘어난다. 엔티티를 양방향 연관관계로 설정하면 객체의 참조는 둘인데 외래키는 하나다. 따라서 둘 사이에 차이가 발생한다.(어디서 외래키를 관리해야 하는가?) 이런 차이로 인해 JPA에서는 두 객체 연관관계 중 하나를 정해서 테이블의 외래키를 관리해야하는데 이것을 연관관계의 주인(owner)라고 한다.
양방향 매핑 시에는 두 연관관계 중 하나를 연관관계의 주인으로 정해야한다. 연관관계 주인만이 데이터베이스 연관관계와 매핑되고 외리키를 관리(등록, 수정, 삭제)할 수 있다. 주인이 아닌 쪽은 읽기만 할 수 있다.
연관관계의 주인은
외래키가 있는곳
으로 설정해야한다. 즉 위의 예에서 외래키 board_id를 갖고있는 post테이블 즉, Post엔티티를 주인으로 설정해야한다.
// Board Class
...
public void addPost(Post post) {
post.setBoard(this);
postList.add(post);
}
...
참조