자바 ORM 표준 JPA 프로그래밍(김영한) 참고
member1.setTeam(team1);
Team findTeam = member1.getTeam();
SELECT *
FROM member
JOIN team ON member.TEAM_ID = team.ID
WHERE member.ID = 'member1'
@JoinColumn: 외래키를 매핑할 때 사용.(생략 가능)
- name: 매핑할 외래키 이름
- 생략하면, name은 필드명(team)+_+참조하는 테이블의 기본키 컬럼명(TEAM_ID)으로 됨. = team_TEAM_ID
@ManyToOne: 다대일(N:1) 관계에서 사용(필수)
조회
- 객체 그래프 탐색(객체를 통해 조회: member.getTeam();)
- 객체지향 쿼리 사용(JPQL)
- sql 조인과 jpql 조인은 문법이 다르다.
- jpql에서는
:변수명
로 써서 파라미터를 바인딩 한다.
수정
entity 값 변경
연관관계 삭제
연관관계를 삭제하고, 엔티티를 삭제해야 한다.
member1.setTeam(null); // 연관관계 삭제
em.remove(team); // 엔티티 삭제
양방향 연관관계 만들기
DB에서는 외래키를 사용해서 양방향 연관관계를 가지고 있으므로, 현재 구조에서 객체쪽 연관관계를 수정한다.
현재는, 회원->팀(member.team)인 단방향 관계이다.
팀->회원(team.members)인 단방향 관계도 추가한다. 여기서 팀->회원은 일대다 관계이다.
@OneToMany(mappedBy = "team")
에서 mappedby 속성에는 반대쪽 매핑의 필드 이름이다.
두 객체의 연관관계는 양방향이 아닌 두 개의 단방향이다. DB는 외래키를 사용한 한 개의 양방향 연관관계이다.
DB 쪽은 연관관계가 1개, 객체 쪽은 연관관계가 2개이기 때문에 객체의 연관관계 중 하나를 선택해 외래키를 관리해야 하고, 이것을 연관관계의 주인
이라 한다.
연관관계의 주인만이 DB와 매핑되어 외래키를 관리(등록, 수정, 삭제)할 수 있고, 주인이 아닌 쪽은 읽기만 할 수 있다.
주인은 mappedby 속성을 사용하지 않고, 주인이 아닌쪽은 mappedby 속성을 통해 주인을 선택한다.
연관관게의 주인은 테이블에 외래키가 있는 곳으로 정해야 한다. 여기서는 MEMBER 테이블 안에 TEAM_ID가 FK로 들어가있으므로, member.team이 주인이 된다.
양방향 연관관계 저장은 주인쪽에서 해야 DB에도 저장이 된다.
하지만, 객체 입장에서는 한쪽에서만(Member.team) 관계를 연결하면 다른쪽(Team.member)에서 참조할 수 없다.
-> 객체의 양방향 연관관계는 양쪽 모두 관계를 맺어주어야 한다.
양쪽 모두 연관관계를 사용하려면 자세히 살펴야 한다. member에 team을 넣어줄때, team에도 잊지않고 member를 넣어줘야 하며, 이때 기존 team과의 연관관계도 제거해줘야 한다.
따라서 객체에서 양방향 연관관계(단방향 2개)를 사용하려면 로직을 잘 관리해야 한다.
일대다(1:N), 다대일(N:1) 관계에서 외래키는 항상 다(N)쪽에 있고, 외래키가 있는 쪽이 주인이다.
양방향 연관관계는 서로를 참조해야 하며, 편의 메소드(한 메소드를 호출해서 양방향 연관관계를 만들수 있게 하는 메소드)를 만드는 게 좋다.
Member(회원)와 Locker(사물함)은 1대1관계
다대다(N:N)
관계형 데이터베이스에서는 테이블 2개로 다대다 관계를 표현할 수 없다. 그래서 중간 연견 테이블을 추가해서 일대다, 다대일 관계로 풀어낸다.
객체는 다대다 관계를 만들 수 있다.
다대다 단방향
MEMBER(회원)과 상품(Product)은 다대다. 중간을 연결해 줄 테이블 MEMBER_PRODUCT
@JoinTable.name : 연결 테이블 지정(MEMBER_PRODUCT)
@JoinTable.joinColumns: 현재 방향인 회원과 매핑할 조인 컬럼 정보 지정(MEMBER_ID)
@JoinTable.inverseJoinColumns: 반대 방향인 상품과 매핑할 조인 컬럼 정보 지정(PRODUCT_ID)
다대다 양방향
mappedby 사용, 편의 메소드 (addProduct) 추가
다대다 매핑의 한계
@ManyToMany를 사용하면, 연결테이블을 자동으로 처리해서줫 편리하나 추가 컬럼이 생기면 사용할 수 없다. 예를 들어, 주문 수량 컬럼이나 주문 시간 같은 컬럼. 왜냐하면 추가한 컬럼은 기존 테이블과 연결시킬 수 없기 때문이다.
그래서 얘네도 다대다에서 일대다, 다대일로 매핑해줘야한다.
컬럼이 2개 이상 복합 기본키를 만들려면, @IdClass를 사용해서 별도로 식별자 클래스를 만들어야 한다.
복합키를 위한 식별자 클래스는 다음과 같은 특징이 있다.
- 복합키는 별도의 식별자 클래스(public)로 만들어야 한다.
- Serializable을 구현해야 한다.
- 기본생성자, equals, hashCode 메소드를 구현해야 한다.
복합키를 사용하지 않고 하기.
- 대리키 생성(Long): 간편(복합키 안 만들어도 됨)하고, 비즈니스에 의존하지 않음
원래는 MEMBER_PRODUCT 테이블에 MEMBER_ID, PRODUCT_ID 2개의 복합키를 사용했으나 ORDERS 테이블에 ORDER_ID를 기본키로 하는 테이블로 수정. MEMBER_ID, PRODUCT_ID는 외래키로 사용