JPA에서 가장 중요한 것을 생각해 보았는데, "객체"와 관계형 데이터베이스 테이블이 어떻게 매핑되는지를 이해하는것" 이 라고 생각합니다.
왜냐하면 JPA의 목적인 "객체 지향 프로그래밍과 데이터베이스 사이의 패러다임 불일치를 해결" 이라는 것과 가장 직접적으로 연관되어 있기 때문입니다.
객체와 테이블 매핑에 대한 내용을 더 구체적으로 나누면 칼럼, 타입, 테이블 등에 대한 1차원적인 매핑과 테이블 간의 연관 관계 매핑으로 나눌 수 있습니다.
1차원적인 매핑의 경우에는 @Entity
,@Column
,@Id
,@GeneratedValue
, @Enumerated
등의 말 그대로 객체와 데이터베이스 사이의 일대일로 대응되는 것으로써 기본적인 어노테이션을 숙지하고 필요한 경우에 찾아보는게 효율적입니다.
연관 관계 매핑은 필요할 때 찾아보기 보다는 비즈니스 로직, 비즈니스 요구사항에 따라 개발자가 더 적절한 관계 설정 방법을 선택해야 하는 주제이기 때문에 공부해 보았습니다.
데이터베이스 테이블은 외래 키(FK) 하나로 양 쪽 테이블 조인이 가능합니다.
따라서 데이터베이스는 단방향이니 양방향이니 나눌 필요가 없습니다.
그러나 객체는 참조용 필드가 있는 객체만 다른 객체를 참조하는 것이 가능합니다.
그렇기 때문에 두 객체 사이에 하나의 객체만 참조용 필드를 갖고 참조하면 단방향 관계, 두 객체 모두가 각각 참조용 필드를 갖고 참조하면 양방향 관계라고 합니다.
엄밀하게는 양방향 관계라는 것은 없고 두 객체가 단방향 참조를 각각 가져서 양방향 관계처럼 사용하는 것입니다.
JPA를 사용하여 데이터베이스와 패러다임을 맞추기 위해서 객체는 단방향 연관 관계를 가질지, 양방향 연관 관계를 가질지 선택합니다.
선택은 비즈니스 로직에서 두 객체가 참조가 필요한지 여부를 고민해보면 됩니다.
이렇게 비지니스 로직에 맞게 선택했는데 두 객체가 서로 단방향 참조를 했다면 양방향 연관 관계가 되는 것입니다.
두 객체 (A,B)가 양방향 관계, 다시 말해 단방향 관계 2개(A->B,B->A)를 맺을 때, 연관 관계의 주인을 지정해 주어야 합니다.
연관 관계의 주인을 지정하는 것은 두 단방향 관계 중에서 제어의 권한(외래 키를 비롯한 테이블 레코드를 저장,수정,삭제 처리)를 갖는 실질적인 관계가 어떤 것인지 JPA에게 알려준다고 생각하면 됩니다.
연관 관계의 주인은 연관 관계를 갖는 두 객체 사이에서 조회,저장,수정,삭제를 할 수 있지만, 연관 관계의 주인이 아니면 조회만 가능합니다.
연관 관계의 주인이 아닌 객체에서 mappedBy 속성을 사용해서 주인을 지정해줘야 합니다.
외래 키가 있는 곳을 연관관계의 주인으로 정하면 됩니다!!!!!!!중요x100
게시판(Board)와 게시글(Post)의 관계로 예를 들어봅니다.
요구사항
데이터베이스를 기준으로 다중성(게시글N : 게시판1)을 결정했습니다.
즉, 외래 키를 게시글(N)이 관리하는 일반적인 형태입니다.
(데이터베이스는 무조건 다(N)쪽이 외래 키를 갖습니다.)
@Entity
public class Post{
@Id
@GeneratedValue
@Column(name = "POST_ID")
private Long id;
@Column(name = "TITLE")
private String title;
@ManyToOne
@JoinColumn(name = "BOARD_ID")
private Board board
//getter,setter..
}
@Entity
public class Board{
@Id
@GeneratedValue
private Long id;
private String title;
//getter,setter...
}
@ManyToOne
를 추가해준것을 확인할 수 있습니다.@Entity
public class Post{
@Id
@GeneratedValue
@Column(name = "POST_ID")
private Long id;
@Column(name = "TITLE")
private String title;
@ManyToOne
@JoinColumn(name = "BOARD_ID")
private Board board
//getter,setter..
}
@Entity
public class Board{
@Id
@GeneratedValue
private Long id;
private String title;
@OneToMany(mappedBy = "board") //<-추가
List<Post> posts = new ArrayList();
//getter,setter...
}
@OneToMany
를 추가하고 양방향을 추가하고 양방향 매핑을 사용하였으니 연간 관계의 주인을 mappedBy
로 지정해줍니다.mappedBy
로 지정할 때 값은 대상이 되는 변수명을 따라 지정하면 됩니다. 전과 다르게 연관관계의 주인을 일(1)쪽에 둘 수 있습니다.
참고로 실무에서는 일대다(1:N)단방향은 거의 쓰지 않습니다.
데이터베이스 입장에서는 무조건 다(N)쪽에서 외래키를 쪽에서 관리합니다.
하지만 일(1)쪽 객체에서 다(N)쪽 객체를 조작(생성,수정,삭제)하는 방법입니다.
@Entity
public class Post{
@Id
@GeneratedValue
@Column(name = "POST_ID")
private Long id;
@Column(name = "TITLE")
private String title;
//getter,setter..
}
@Entity
public class Board{
@Id
@GeneratedValue
private Long id;
private String title;
@OneToMany
@JoinColumn(name = "POST_ID")
List<Post>posts = new ArrayList<>();
//getter,setter...
}
@OneToMany
에서 mappedBy
가 없습니다.당연히 양방향이 아니기 때문입니다.
대신 @JoinColumn
을 이용하여 조인을 합니다.
실제 사용은 아래와 같이 할 수 있습니다.
Post post = new Post();
post.setTitle("가입인사");
entityManager.persist(post);//post저장
Board board = new Board();
board.setTitle("자유게시판");
board.getPosts().add(post);
entityManager.persist(board);//board저장
board.getPosts().add(post);
때문입니다.@Entity
public class Post{
@Id
@GeneratedValue
@Column(name = "POST_ID")
private Long id;
@Column(name = "TITLE")
private String title;
@OneToOne
@JoinColumn(name = "ATTACH_ID")
private Attach attach;
//getter,setter...
}
@Entity
public class Attach{
@Id
@GeneratedValue
@Column(name = "ATTACH_ID")
private Long id;
private String name;
//getter,setter...
@OneToOne
로 설정하고 mappedBy
설정만 하여 읽기 전용으로 만들어주면 양방향도 간단하게 됩니다.@Entity
public class Attach{
@Id
@GeneratedValue
@Column(name = "ATTACH_ID")
private Long id;
private String name;
@OneToOne(mappedBy ="attach")
private Post post;
//getter,setter...