양방향 연관관계 매핑
데이터베이스의 테이블은 외래키 하나로 양방향 조회가 가능하지만
객체는 서로 다른 두 단방향 참조를 합쳐서 양방향이라고 한다.
따라서 두 개의 연관 관계 중 연관 관계의 주인을 정하고,
주인이 아닌 연관 관계를 하나 더 추가하는 방식으로 작성하게 된다.
반대 방향으로도 access하여 객체 그래프 탐색을 할 일이 많은 경우 양방향 연관관계 매핑을 사용한다.
(항상 사용하는 것이 아님)
연관 관계의 주인을 정하는 기준
양방향 연관 관계시 연관관계의 주인(Owner)라는 이름으로 인해 오해가 있을 수 있다.
비즈니스 로직 상 더 중요하다고 연관 관계의 주인으로 선택하면 안되며,
비즈니스 중요도를 배제하고 단순히 외래키 관리자의 의미를 부여해야 한다.
연관 관계의 주인은 외래키를 가지고 있는 엔티티이다.
진짜 연관 관계는 처음 조회 시부터 조인한 결과를 인출해 온다. 가자 연관관계는 해당 엔티티를 조회하고 필요 시 연관 관계 엔티티를 조회하는 쿼리를 다시 실행한다.
양방향 연관관계 매핑은 두 개의 객체 간에 서로를 참조할 수 있도록 하는 것을 의미한다.
예를 들어, 학생과 과목 간의 관계를 생각해보면, 하나의 학생이 여러 과목을 수강할 수 있고, 하나의 과목에는 여러 학생이 수강할 수 있다. 이러한 관계를 양방향 연관관계로 표현하면, 학생 객체와 과목 객체가 서로를 참조할 수 있게 된다.
이때 이러한 양방향 연관관계를 구현하기 위해서는, 두 객체 간의 참조를 맺어주는 코드를 작성해야 한다.
이를 위해 일반적으로 객체 지향 프로그래밍에서는 객체 간의 연관관계를 매핑하는 기술인 ORM(Object-Relational Mapping)을 사용하는데
ORM을 사용하면, 객체 간의 관계를 데이터베이스에 저장할 수 있다.
이때, 양방향 연관관계를 매핑하기 위해서는, 한 객체에서 다른 객체를 참조하는 코드를 작성하는 것 외에, 반대로 다른 객체에서도 해당 객체를 참조할 수 있는 코드를 작성해주어야 한다. 이렇게 양쪽으로 참조할 수 있는 코드를 작성하면, 두 객체 간의 관계를 양방향으로 설정할 수 있다.
즉, 양방향 연관관계 매핑을 구현하기 위해서는, 한 객체에서 다른 객체를 참조하는 코드와, 반대로 다른 객체에서도 해당 객체를 참조할 수 있는 코드를 모두 작성해주어야 한다. 이렇게 함으로써, 두 객체 간의 관계를 양방향으로 설정할 수 있으며, 이를 통해 객체 간의 관계를 보다 쉽게 처리할 수 있다.
stackOverFlowError
toString() 오버라이딩 시 양방향 연관 관계는 재귀호출이 일어나기 때문에 stackOverFlowError가 발생하게 된다.
따라서 재귀가 일어나지 않게 하기 위해서는 엔티티의 주인이 아닌 쪽의 toString을 연관 객체 부분이 출력 되지 않도록 해야 한다.
특히 자동 완성 및 롬복 라이브러리를 이용하는 경우 해당 문제 발생 가능성이 매우 높아진다.
양방향 연관관계 주인 객체를 이용할때 insert 하는 법
//when
menu.setCategory(entityManager.find(Category.class, 4));
//then
Menu foundMenu = entityManager.find(Menu.class, menu.getMenuCode());
양방향 연관관계를 설정하고 흔히 하는 실수는 연관관계의 주인에는 값을 입력하고,
주인이 아닌 곳에는 값을 입력하지 않는 경우 외래키 컬럼이 not null 제약조건이 설정되어 있는 경우이다.
null 값이 외래키 컬럼에 삽입 되지 않으므로 에러가 발생한다. 따라서 카테고리 정보를 추가한다.
양방향 연관관계 주인 객체를 이용할때 insert 할 때, 주인일 때와 주인이 아닐 때의 차이는 not null 제약조건이다.
아래 코드를 봐보자!
public void 양방향_연관관계_주인_객체를_이용한_삽입_테스트() {
//given
Menu menu = new Menu();
menu.setMenuCode(125);
menu.setMenuName("연관관계주인메뉴");
menu.setMenuPrice(10000);
menu.setOrderableStatus("Y");
}
public void 양방향_연관관계_주인이_아닌_객체를_이용한_삽입_테스트() {
//given
Category category = new Category();
category.setCategoryCode(1004);
category.setCategoryName("양방향카테고리");
category.setRefCategoryCode(null);
}
연관 관계의 주인의 경우 전과 똑같은 방식으로 연관 관계 매핑을 처리하면 된다.
@JoinColumn(name="CATEGORY_CODE")
@ManyToOne
private Category category;
mappedBy
연관 관계의 주인을 정하기 위해서 연관 관계의 주인이 아닌 객체에 mappedBy를 써서
연관 관계 주인 객체의 필드명을 매핑 시켜 놓으면 로직으로 양방향 관계를 적용할 수 있다.
@OneToMany(mappedBy="category")
private List<Menu> menuList;
'java > JPA' 카테고리의 다른 글
JPA 프로젝트 DTO 만드는 과정 , 디자인 패턴 (0) | 2023.05.05 |
---|---|
JPA- JPQL(Java Persistence Query Language) (0) | 2023.04.11 |
JPA 객체 관계 맵핑과 다양한 연관 관계 (0) | 2023.04.10 |
JPA EntityMapping 테이블 만들어보기 (0) | 2023.04.07 |
JPA PersistenceContext, EntityManagerFactory, EntityManager (0) | 2023.04.07 |