JPA @OneToMany
참조 : http://www.oracle.com/technology/products/ias/toplink/jpa/resources/toplink-jpa-annotations.html#OneToMany
위와 같은 관계에 있을 때 Category도 자신에 속해있는 Post를 참조할 수 있고 Post도 자신이 속한 Category를 참조할 수 있다면 Java 코드는 다음과 같이 작성할 수 있습니다.
private Long categoryId;
private String categoryName;
private Set<Post> posts;
...
}
public class Post {
private Long postId;
private Category category;
...
}
Category 입장에서 Post를 보면 "Category 하나는 여러 Post와 연관을 맺습니다." 따라서 OneToMany 관계 입니다.
@OneToMany 애노테이션을 getter위에 붙여 줍니다.
설정 할 수 있는 속성은 위에 보이는 것과 같이 네 개가 있습니다.
cascade의 사전적인 의미는 "작은 폭포" "계단식 정보 전달" 이라는 뜻이 있습니다. 이것으로 추축할 때 어느쪽 Entity에 영향을 주면 다른 쪽 Entity에도 어떤 영향을 줄 수 있는 설정이라는 것으로 생각할 수 있습니다.
fetch의 사전적인 의미는 "가지고 오다" "자아내다" 라는 뜻이 있습니다. 즉 해당 Entity를 불러올 때 연관을 맺고 있는 상대방(OneToMany이기 때문에 상대방은 Many쪽이 되겠죠.)들을 가져오는 것과 관련된 속성이라고 생각할 수 있습니다.
mappedBy는 "누군가에 의해 관계를 맺고 있다." 즉, 누군가 한테 종속되어 있다. 라는 설정으로 생각할 수 있겠습니다.
targetEntity는 연관을 맺고 있는 타겟을 지칭하는 듯해 보입니다.
속성 |
설명 |
기본값 |
cascade |
관계를 맺고 있는 타겟 쪽에 어떠한 persistence operation들을 연쇄적으로 적용하고 싶을 때 설정합니다. ALL, MERGE, PERSIST, REFRESH, REMOVE 등의 값을 사용하여 여러 개의 cascade 속성을 설정할 수 있습니다. 참조무결성을 위한 설정으로 보이며, Hibernate의 @Cascade 를 사용하여 보다 다양한 cascade 옵션을 사용할 수 있습니다. |
비어있는 CascadeType 배열 |
fetch |
연관을 맺고 있는 Entity들을 요청하는 순간 가져오는 설정이 LAZY 며, 해당 Entity를 가져올 때 미리 연관을 맺고 있는 Entity들까지 모두 가져오는 것이 EAGER 입니다. |
FetchType.LAZY |
mappedBy |
관계가 양방향 일 때는 mappedBy 속성에 관계의 주인이 되는 쪽에서 어떤 속성으로 접근을 하는지 설정해 줍니다. |
if the relationship is unidirectional, the persistence provider determines the field that owns the relationship. |
targetEntity |
만약 Generic을 사용하지 않은 Collection일 때는 이 속성을 관계의 주인이 되는 쪽 클래스로 설정해 주어야 합니다. |
타입을 명시한 Collection을 사용했을 때는 해당 타입으로 사용합니다. |
다시 Category와 Post의 관계로 돌아가서...
Category와 Post 관계 중에 어느 쪽이 관계의 주인이 되는지 생각해 보겠습니다. "관계의 주인" 영어 문서에는 owner side, owning entity등으로 표햔을 하고 있는데, 아무래도 직관적으로 생각해 봤을 때 DB 테이블 간의 관계를 설정할 때 상대방의 주키를 자신의 외례키로 가지는 쪽을 말하는 것 같습니다.
위의 관계라면 Post 에서 Catergory를 외례키로 가지고 있을 것이기 때문에, Post를 owning entity로 볼 수 있습니다.
그리고 Category 엔티티를 읽어 올 때 거기에 딸려 있는 모든 Post를 미리 읽어오게 하고 싶지 않습니다. 그러면 Category 목록만 보고 있는데도 그 안에 딸려 있는 모든 Post들을 DB에서 가져오게 될 텐데 그러면 엄청나게 많은 부하가 생길 것 같기 때문입니다. 그래서 fetch의 기본값인 LAZY를 사용하겠습니다.
cascade 속성은 owning entity에서 설정해주면 될 것 같고, targetEntity는 사용할 필요가 없습니다. 저는 Generic을 사용했기 때문에 별도로 명시해줄 필요가 없습니다.
위의 상황을 종합하여 다음과 같이 설정할 수 있습니다.
@OneToMany(fetch=FetchType.LAZY, mappedBy="category")
public Set<Post> getPosts() {
if(posts == null) posts = new HashSet<Post>();
return posts;
}
지금 예제는 양방향 관계이기 때문에 Owning Entity쪽 즉 Post 클래스의 getCategory()에 @ManyTonOne 설정을 하도록 하겠습니다. 너무 길어서 다음글로 이어집니다.