서로 다른 두 객체가 연관성을 가지고 관계를 맺는 것
데이터베이스 환경에서는 join이라는 구문을 사용하지만 객체 환경에서는 해당 어노테이션을 사용해서 매핑한다.
@joniColumn
은 외래키를 매핑할 때 사용한다.
@joniColumn 속성
name : 매핑할 외래키의 이름
referencesColumnName : 외래키가 참조하는 대상 테이블의 컬럼명
foreignKey : 외래키 제약 조건을 직접 지정할 수 있으며 테이블 생성 시 사용된다.
unique, nullable, insertable, update, columnDefinition, table : @Column의 속성과 동일하다.
@Entity(name="many_to_one_menu_and_category")
@Table(name="TBL_MENU")
public class MenuAndCategory {
@Id
@Column(name="MENU_CODE")
private int menuCode;
@Column(name="MENU_NAME")
private String menuName;
@Column(name="MENU_PRICE")
private int menuPrice;
@JoinColumn(name="CATEGORY_CODE")
private Category category;
... 생략
@ManyToOne
은 N:1 관계에서 사용한다.
@ManyToOne 속성
optional : false로 설정하면 연관된 엔터티가 있어야한다.
cascade : 영속성 전이 기능을 사용한다.(연관된 엔터티를 함께 영속성으로 관리한다는 의미)
orphanRemoval : true로 설정하면 고아 객체 제거
N:1 연관관계 객체 삽입 상황에서
insert 구문 commit을 할 경우 flush하며 컨텍스트 내의 영속성 객체를 insert하는 쿼리를 동작시키는데 부모 테이블(TBL_CATEGORY)에 값이 먼저 들어있어야 자식 테이블(TBL_MENU)에 데이터를 넣을 수 있다.
@ManyToOne 어노테이션에 영속성 전이 설정을 해주어야한다.
영속성 전이
란?
특정 엔터티를 영속화할 때 연관된 엔터티도 함께 영속화 한다는 의미이다.
cascade=CascadeType.PERSIST를 설정하면 Menu를 저장하기 전에 Category부터 저장하게된다.
영속성 전이가 필요한 필드 위에 적어준다.
@Entity(name="many_to_one_menu_and_category")
@Table(name="TBL_MENU")
public class MenuAndCategory {
@Id
@Column(name="MENU_CODE")
private int menuCode;
@Column(name="MENU_NAME")
private String menuName;
@Column(name="MENU_PRICE")
private int menuPrice;
@JoinColumn(name="CATEGORY_CODE")
@ManyToOne(cascade=CascadeType.PERSIST)
private Category category;
... 생략
@OneToMany
1:N 관계에서 사용한다.
해당 참조할 필드 위에 적어준다.
@Entity(name="one_to_many_category_and_menu")
@Table(name="TBL_CATEGORY")
public class CategoryAndMenu {
@Id
@Column(name="CATEGORY_CODE")
private int categoryCode;
@Column(name="CATEGORY_NAME")
private String categoryName;
@Column(name="REF_CATEGORY_CODE")
private Integer refCategoryCode;
@JoinColumn(name="CATEGORY_CODE")
@OneToMany(cascade=CascadeType.PERSIST)
private List<Menu> menuList;
CategoryAndMenu categoryAndMenu = entityManager.find(CategoryAndMenu.class, categoryCode);
//해당 테이블만 조회된 상태
System.out.println(categoryAndMenu);
//출력구문 실행 시 조회가 필요하기 때문에 연관관계 테이블 조회까지 실행된다.
주인
을 정하고, 주인이 아닌 연관관계를 하나 더 추가하는 방식으로 작성하게 된다.주인
을 정하는 기준mappedBy
: 연관관계의 주인을 정하기 위해서 연관관계의 주인이 아닌 객체에 mappedBy를 써서 연관관계의 주인 객체의 '필드명'을 매핑 시켜 놓으면 로직으로 양방향 관계를 적용할 수 있다.
@Entity(name="bidirection_category")
@Table(name="TBL_CATEGORY")
public class Category {
@Id
@Column(name="CATEGORY_CODE")
private int categoryCode;
@Column(name="CATEGORY_NAME")
private String categoryName;
@Column(name="REF_CATEGORY_CODE")
private Integer refCategoryCode;
@OneToMany(mappedBy="category")
private List<Menu> menuList;
...생략
@JoinColumn(name="CATEGORY_CODE")
@ManyToOne
을 사용@Entity(name="bidirection_menu")
@Table(name="TBL_MENU")
public class Menu {
@Id
@Column(name="MENU_CODE")
private int menuCode;
@Column(name="MENU_NAME")
private String menuName;
@Column(name="MENU_PRICE")
private int menuPrice;
@JoinColumn(name="CATEGORY_CODE")
@ManyToOne
private Category category;
@Column(name="ORDERABLE_STATUS")
private String orderableStatus;
...생략
주의 사항!
toString() 오버라이딩 시 양방향 연관관계는 재귀호출이 일어나기 때문에 stackOverFlowError가 발생하게된다.
따라서 재귀가 일어나지 않게 하기 위해서는 엔터티의 주인이 아닌 쪽의 toString을 연관객체 부분이 출력되지 않도록 toString에서 삭제해야한다.