쌩로그

Jpa기본 05. 연관관계 매핑 기초(인프런 + 자바 ORM 표준 JPA 프로그래밍) 본문

Spring/JPA

Jpa기본 05. 연관관계 매핑 기초(인프런 + 자바 ORM 표준 JPA 프로그래밍)

.쌩수. 2023. 9. 1. 11:56
반응형

목록

  1. 포스팅 개요
  2. 본론
        2-1. 단방향 연관관계
        2-2. 연관관계 사용
        2-3. 양방향 연관관계
        2-4. 연관관계의 주인
        2-5. 양방향 연관관계 저장
        2-6. 양방향 연관관계의 주의점
  3. 요약

1. 포스팅 개요

해당 포스팅은 인프런에서 영한님의 JPA기본 강의에서 엔티티 매핑 기초 파트와 해당 파트에 맞는 책의 챕터를 보고 학습한 내용을 요약 및 정리하는 포스팅입니다.

2. 본론

먼저 객체와 RDB의 차이를 생각해 볼 필요가 있겠습니다.
객체는 참조(주소)를 사용해서 관계를 맺지만,
테이블은 외래 키를 사용해서 관계를 맺습니다.
객체의 참조와 테이블의 외래 키를 매핑하는 것이 이번 챕터의 목표입니다.

들어가기 앞서서 세 가지의 키워드를 알아놓으시면 좋을 거 같습니다.

방향
방향은 객체 관계에만 존재하고, 테이블 관계를 항상 양방향입니다.

  • 단방향 관계 : 둘 중 한 쪽만 참조하는 것을 단방향 관계라고 합니다.
  • 양방향 관계 : 양쪽 모두 서로 참조하는 것을 양방향 관계라고 합니다.

다중성
다대일(N:1), 일대다(1:N), 일대일(1:1), 다대다(N:M) 다중성이 있습니다.
예를 들어,
여러 회원(N)은 한 팀(1)에 속하므로 회원과 팀은 다대일(N:1) 관계입니다.
반대로,
한 팀(1)에 여러 회원(N)이 소속될 수 있으므로, 팀과 회원은 일대다(1:N) 관계입니다.

연관관계의 주인
객체를 양방향 연관관계로 만들면 연관관계의 주인을 정해야 합니다.

2-1. 단방향 연관관계

다대일(N:1) 단방향 관계

해당 그림을 예시로 들겠습니다.
다대일 단방향 관계는 다음과 같이 예시를 볼 수 있습니다.

  • 회원과 팀이 있습니다.
  • 회원은 하나의 팀에만 소속될 수 있다.
  • 회원과 팀은 다대일(N:1) 관계입니다.

이 예로 객체의 연관관계테이블의 연관관계를 살펴보겠습니다.

객체 연관관계

  • 회원 객체는 Member.team 필드(멤버변수)로 팀 객체와 연관관계를 맺습니다.
  • 회원 객체와 팀 객체는 단방향 관계입니다.
  • 회원은 Member.team 필드를 통해서 팀을 알 수 있지만, 반대로 팀은 회원을 알 수 없습니다.
    • member.getTeam() 은 가능하지만, team.getMember()은 불가능합니다.

테이블 연관관계

  • 회원 테이블은 TEAM_ID 외래 키로 팀 테이블과 연관관계를 맺습니다.
  • 회원 테이블과 팀 테이블은 양방향 관계입니다.
    • TEAM_ID 외래 키를 통해서 회원과 팀을 조인할 수 있고, 반대로 팀과 회원을 조인할 수도 있습니다.

객체 연관관계와 테이블 연관관계의 가장 큰 차이는 다음과 같습니다.
참조를 통한 연관관계는 언제나 단방향입니다!
객체 간 연관관계를 양방향으로 만들고 싶으면 반대쪽에도 필드를 추가해서 참조를 하도록 해야 합니다.
양쪽에서 서로 참조하는 것을 양방향 연관관계라고 하는데, 정확히 말하자면, 사실은 양방향 관계가 아니라 서로 다른 단방향 관계 2개입니다.
하지만, 테이블은 외래 키 하나로 양방향으로 서로 조인할 수 있습니다.

정리하자면,

  • 핵심은 객체는 참조(주소)로 연관관계를 맺고, 테이블은 외래 키로 연관관계를 맺습니다.

여기까진 방향에 대한 개념입니다만, 조금 더 디테일하게 각각의 입장에서 살펴봐야됩니다.

먼저
순수한 객체 연관관계에 대해 생각해보면, 객체는 참조를 사용해서 연관관계를 탐색할 수 있어야 합니다. 이를 객체 그래프 탐색이라고 합니다.

그리고, 데이터베이스는 외래 키를 사용해서 연관관계를 탐색할 수 있는데 이것을 조인 이라고 합니다.

연관 관계는 JPA 표준 API에서 제공하는 애너테이션을 통해서 연관된 객체를 매핑할 수 있습니다.

@JoinColumn

외래 키를 매핑할 때 사용합니다.

속성 기능 기본값
name 매핑할 외래 키 이름 필드명 + '-' + 참조하는 테이블의 키본 키 컬럼명
referencedColumnName 외래 키가 참조하는 대상 테이블의 컬럼명 참조하는 테이블의 기본 키 컬럼명
foreignKey(DDL) 외래 키 제약조건을 직접 지정할 수 있습니다.
이 속성은 테이블을 생성할 때만 사용합니다.
unique
nullable
insertable
updatable
columnDefinition
table
@Column의 속성과 같습니다.

@ManyToOne

다대일(N:1) 관계에서 사용합니다.

속성 기능 기본 값
optional false로 설정하면 연관된 엔티티가 항상 있어야 합니다. true
fetch 글로벌 페치 전략을 설정합니다. @ManyToOne=FetchType.EAGER
@OneToMany=FetchType.LAZY
cascade 영속성 전이 기능을 사용합니다.
targetEntity 연관된 엔티티의 타입 정보를 설정합니다. 이 기능은 컬렉션 프레임워크를 사용하더라도 제너릭으로 타입 정보를 충분히 알 수 있습니다.
그래서 거의 사용하지 않습니다 ^^

위의 표처럼 보시다시피 targetEntity 속성은 잘 사용하지 않습니다.
코드를 보여드릴건데, 왜 잘 사용하지 않는지 바로 확인하실 수 있으실겁니다.
다음은 예시코드입니다!

@OneToMany
private List<Member> members;    // 제너릭으로 타입 정보를 알 수 있습니다.

@OneToMany(targetEntity=Member.class)
private List members;            // 제너릭이 없으면 타입 정보를 알 수 없습니다.

그냥 위에꺼 씁시다..

2-2. 연관관계 사용

// 팀1 저장  
Team team1 = new Team();  
team1.setName("team1");  
em.persist(team1);  

// 회원1 저장  
Member member1 = new Member();  
member1.setUsername("member1");  
member1.setTeam(team1); // 연관관계 설정 member1 -> team1
em.persist(member1);  

// 회원2 저장  
Member member2 = new Member();  
member2.setUsername("member2");  
member2.setTeam(team1); // 연관관계 설정 member2 -> team2
em.persist(member2);

이와 같은 코드가 있습니다.

참고로 아시겠지만, JPA에서 엔티티를 저장할 때 연관된 모든 엔티티는 영속 상태여야 합니다.

위의 코드를 보시면, 회원 엔티티는 팀 엔티티를 참조하고 저장했습니다.
실행되는 insert 쿼리를 보면 다음과 같습니다.

insert into Team (name, TEAM_ID) values (?, ?)
insert into Member (TEAM_ID, USERNAME, MEMBER_ID) values (?, ?, ?)
insert into Member (TEAM_ID, USERNAME, MEMBER_ID) values (?, ?, ?)

위의 insert 쿼리는 JPA가 만든 SQL입니다.
JPA는 참조한 팀의 식별자를 외래 키로 사용해서 적절한 등록 쿼리를 생성합니다.

그리고 결과를 다음 쿼리로 조회할 수 있습니다.

SELECT M.MEMBER_ID, M.USERNAME, M.TEAM_ID, T.NAME AS TEAM_NAME
FROM MEMBER M
 JOIN TEAM T ON M.TEAM_ID = T.TEAM_ID;

결과는 다음과 같습니다.

방금은 연관관계를 맺은 엔티티들의 등록에 대한 내용이었고,
이번엔 조회에 대해 알아보겠습니다.

연관관게가 있는 엔티티를 조회하는 방법은 크게 2가지가 있습니다.

  • 객체 그래프 탐색(객체의 연관관계를 사용한 조회)
  • 객체지향 쿼리 사용(JPQL)

위의 두 가지가 있습니다.

객체 그래프 탐색은 순수 객체 연관관계에서 본 것처럼 참조를 통해서 엔티티를 조회하는 것입니다.

객체지향 쿼리(JPQL)은 테이블을 대상으로 조회하는 SQL과 달리 객체를 대상으로 조회하는 추상화된 쿼리입니다.

위의 예시에서 "team1"에 소속된 회원들을 JPQL을 통해서 조회하는 코드는 다음과 같습니다.

String jpql = "select m from Member m join m.team t where " +  
        "t.name=:teamName";  

List<Member> members = em.createQuery(jpql)  
        .setParameter("teamName", "team1")  
        .getResultList();  


for(Member member : members) {  
    System.out.println("member.getUsername() = " + member.getUsername());  
}

// member.getUsername() = member1
// member.getUsername() = member2

회원이 팀과 관계를 가지고 있는 필드(m.team)를 통해서 Member와 Team을 조인한 것을 볼 수 있습니다.

참고로 "t.name=:teamName" 이 문법 중 콜론(:)으로 시작하는 것은 파라미터를 바인딩하는 문법입니다.

수정은 앞에서 살펴본 챕터처럼 변경감지에 의해서 자동으로 update쿼리가 나갑니다.

삭제에 대한 부분입니다.
연관된 엔티티를 삭제하려면, 기존에 있던 연관관계를 먼저 제거하고 삭제해야 합니다.

연관관계를 먼저 제거하지 않고 삭제하는 경우, 외래 키 제약조건으로 인해서 데이터베이스에 오류가 발생합니다.

다음 코드를 실행해보겠습니다.

Team team = em.find(Team.class, 1L);  
em.remove(team);

결과를 봅시다.

쿼리는 적절히 실행되는 것 같습니다만,
이후 로그를 보면 다음과 같습니다.

ERROR 로그 중, Referential integrity constraint violation이라고 나오는데, 참조 무결성 제약 위반이라는 뜻입니다.

따라서 반드시 연관된 엔티티와의 연관관계를 먼저 제거한 다음에 삭제해야 합니다.

2-3. 양방향 연관관계

이제 양방향 연관관계에 대해 간략히 보겠습니다.

양방향 객체 관게를 그림으로 나타내면 위와 같습니다.

참고로 JPA는 List를 포함해서 Collection, Set, Map 과 같은 다양한 컬렉션을 지원합니다.

테이블 연관관계는 언제나 동일합니다.

데이터베이스 테이블은 외래 키 하나로 양방향으로 조회할 수 있습니다.
테이블은 외래 키가 존재하는 순간부터 양방향 관계입니다. ^^

이전 예제에서는 회원과 팀은 다대일(N:1) 관계였고,
회원에서만 팀을 참조하는 방향만 있는 단방향 연관관계였습니다
그리고, 회원 엔티티 클래스인 Member 클래스에서 다대일(N:1) 관계를 설정하기 위해 @ManyToOne 애너테이션을 사용했습니다.

이번엔 회원에서 팀을 참조하는 단방향 연관관계의 코드를 똑같이 하되,
팀에서 회원으로의 연관관계만 맺어주면 됩니다.

팀 엔티티 클래스에서 다음 코드를 추가해주면 됩니다.

@OneToMany(mappedBy = "team")
private List<Member> members = new ArrayList<>();

@OneToMany(mappedBy = "team")
이 애너테이션은 일대다(1:N) 관계를 매핑합니다.
mappedBy는 양방향 매핑일 때 해당 엔티티 클래스에서 연관된 엔티티 클래스와 매핑하는 필드의 이름을 값으로 주면됩니다.

즉, Member테이블에 다음과 같은 코드가 있을 것입니다.

@ManyToOne
@joinColumn(name = "TEAM_ID")
"private Team team"

Member에 Team과 연관된 필드의 이름이 team이기 때문에,
Team 클래스에서는 "반대 방향에 있는 Member의 tem필드와 매핑 되겠다"는 의미로 mappedBy의 name 속성에 "team" 이라는 값을 줍니다.

2-4. 연관관계의 주인

사실 객체에는 양방향 연관관계라는 것은 없습니다.
서로 다른 단방향 연관관계 2개를 애플리케이션 로직에서 묶어서 마치 양방향인 것처럼 보이게 할 뿐입니다.

반면에 테이블은 (앞서 말했다시피) 외래 키 하나만으로 양방향 연관관계를 맺습니다.
엔티티를 단방향으로 매핑하면 참조를 하나만 사용하므로 이 참조로 테이블의 외래 키를 관리하면 됩니다.

그런데 엔티티를 양방향 연관관계로 설정하면, 객체의 참조는 둘인데, 외래 키는 하나입니다.

그렇다면 연관된 두 개의 엔티티 중 어떤 엔티티를 통해서 외래 키를 관리해야할까요?

두 객체 연관관계 중 하나를 정해서 테이블의 외래 키를 관리해야하는데, 이것을 연관관계의 주인(Owner)이라고 합니다.

양방향 연관관계 매핑시 지켜야할 규칙이 있습니다.
두 연관관계 중 하나만 연관관계의 주인으로 정해주어야 합니다.
연관관계의 주인만데이터베이스 연관관계와 매핑되고 외래 키를 관리할 수 있습니다.
반면에, 주인이 아닌 쪽은 읽기"만" 할 수 있습니다.
연관관계의 주인을 정한다는 것은 사실 외래 키 관리자를 선택하는 것입니다.

어떤 객체를 연관관계의 주인으로 정할지는 mappedBy 속성을 사용하면 됩니다.
연관관계의 주인은 mappedBy 사용하지 않습니다.
주인이 아닌 곳에서 mappedBy 속성을 사용해서 속성의 값으로 연관관계의 주인을 지정해주어야 합니다.

그리고, 연관관계의 주인은 테이블에 외래 키가 있는 곳으로 정해야 합니다.
왜냐하면,
예를 들어보겠습니다.

회원테이블에는 외래 키로 팀의 ID가 있습니다.
그런데 객체에서 만약에, (정말 만약에) 연관관계의 주인을 Team으로 설정했다고 가정했을 때,

어떤 회원이 1팀에 있다가, 2팀으로 가게되었습니다.

그러면 회원 테이블에서 해당 회원의 row에서 팀 테이블과 관계되어있는 외래 키의 값이 2팀에 해당되는 ID값으로 바뀔 것입니다.

그렇다면, 객체에서는 어떻게 해야될까 생각해보면,

Team 은 List 형식으로 Member를 담고있으니 로직은 다음과 같이 되겠네요..

// em.find 로 팀1을 찾는다.
// em.find 로 회원을 찾는다.
// 팀1의 list에서 회원을 remove한다.
// em.find 로 팀2를 찾는다.
// 팀2의 list에 회원을 add한다.

흠.. 복잡합니다.

그리고, 테이블은 회원에서 팀의 외래 키를 변경해주었는데,
객체에서는 팀에서 일일이 회원을 찾아서 list에 넣는 것도 복잡해보입니다.

그런데, 만약 회원 테이블에 외래 키가 있듯이,
객체에 Member(회원)를 연관관계의 주인으로 설정하면 어떻게 될까요?

로직은 다음과 같이 생각할 수 있을 거 같습니다.

// em.find로 회원을 찾는다.
// em.find로 팀2를 찾는다.

// member.setTeam(팀2);

훨씬 간단하고, 간결해졌습니다.

따라서 연관관계의 주인은 테이블에 외래 키가 있는 곳으로 정해야 합니다.

※ 참고로 다대일, 일대다 관계에서는 항상 쪽이 외래 키를 가집니다.
@ManyToOne를 사용하는 엔티티는 항상 연관관계의 주인이 되기때문에 mappedBy 속성이 없습니다.

ㄹㅇ입니다..

2-5. 양방향 연관관계 저장

회원과 팀의 양방향 연관관계의 저장을 살펴보겠습니다.
앞의 단방향 연관관계에서는 회원에 Setter를 통해서 팀을 저장 해주었습니다.

// 팀 저장  
Team team1 = new Team();  
team1.setName("팀1");  
em.persist(team1);  

// 회원 저장  
Member member1 = new Member();  
member1.setUsername("회원1");  
member1.setTeam(team1);  
em.persist(member1);  

// 회원 저장  
Member member2 = new Member();  
member2.setUsername("회원2");  
member2.setTeam(team1);  
em.persist(member2);
select * from member;

결과는 다음과 같습니다.

TEAM_ID 컬럼에 팀의 기본 키 값이 저장되어있습니다.
양방향 연관관계는 연관관계의 주인이 외래 키를 관리하는데요.

말하고자 하는 바연관관계의 주인이 아닌 곳에 입력된 값은 외래 키에 영향을 주지 않는다는 것입니다.

즉, 생각해보면, 다음과 같은 코드가 있어야 될 것입니다.

team1.getMembers().add(member1);
team1.getMembers().add(member2);

하지만, Team은 연관관계의 주인이 아니기 때문에, 여기에 입력된 값은 외래 키에 영향을 주지 않습니다.
따라서 해당 코드는 데이터베이스에 저장될 때 무시됩니다.

연관관계의 주인은 Member 클래스의 Team타입 team필드이기 때문에,
EntityManager는 이곳에 입력된 값을 사용해서 외래 키를 관리합니다.

(저 코드가 데이터베이스에 저장될 때 무시된다고 하여 필요없는 것은 아닙니다. 후에 다룹니다.)

2-6. 양방향 연관관계의 주의점

처음의 흔한 실수
양방향 연관관계를 설정하고 가장 흔히 하는 실수가 연관관계의 주인에는 값을 입력하지 않고, 주인이 아닌 곳에만 값을 입력하는 것이라고 합니다.

Member member1 = new Member();  
member1.setUsername("member1");  
em.persist(member1);  

Member member2 = new Member();  
member2.setUsername("member2");  
em.persist(member2);  

Team team1 = new Team();  
team1.setName("팀1");  
team1.getMembers().add(member1);  
team1.getMembers().add(member2);  

em.persist(team1);
select * from member;

이 결과는 어떻게 될까요..?
예상은 이렇게 되어있지 않을까요..?

MEMBER_ID USERNAME TEAM_ID
1 member1 3
2 member2 3

하지만, 결과는 다음과 같습니다.

허허허...그렇네요..
왜냐하면 연관관계의 주인인 member로 team을 설정한 것이 아니라,
연관관계의 주인이 아닌 곳인 team에서 member를 설정했기 때문입니다.
코드를 수정하여 예상한 결과를 얻을 수 있도록 바꿔보겠습니다!

다음과 같이 바꾸면 될 거 같네요

Member member1 = new Member();  
member1.setUsername("member1");  
em.persist(member1);  

Member member2 = new Member();  
member2.setUsername("member2");  
em.persist(member2);  

Team team1 = new Team();  
team1.setName("팀1");  
em.persist(team1);  

member1.setTeam(team1);  
member2.setTeam(team1);

결과는 다음과 같습니다.

이처럼 연관관계의 주인만이 외래 키 값을 변경할 수 있습니다.

그런데 객체관점에서 다음과 같은 코드도 있어야할 것 같다고 했습니다..

team1.getMembers().add(member1);
team1.getMembers().add(member2);

사실 객체 관점에서는 양쪽 방향에 모두 값을 입력해주는 것이 가장 안전합니다.
영한님은 책을 통해 설명하시기를 "양쪽 방향 모두 값을 입력하지 않으면 JPA를 사용하지 않는 순수한 객체 상태에서 심각한 문제가 발생할 수 있다." 라고 말씀하십니다.

덧붙이시기를
ORM은 객체와 관계형 데이터베이스 둘 다 중요하다고 말씀하십니다..
따라서 데이터 베이스뿐만 아니라, 객체도 함께 고려해야 합니다.

따라서 살펴본 것처럼 회원에 팀을 지정해주는 것 뿐만 아니라, 팀에서도 회원을 입력해주어야 합니다.
결론은 외래 키에 대한 연관관계 매핑도 중요하지만, 뿐 아니라, 객체까지 고려해서 연관관계의 주인이 아닌 곳에도 값을 입력해주어야 합니다.

그래서 나온 것이 연관관계 편의 메서드입니다.
양방향 연관관계에서는 결국 양쪽 다 신경써야 합니다.

회원과 팀을 예로 들면, 다음과 같은 코드를 같이 써야합니다.

member.setTeam(team);
team.getMembers().add(member);

간혹 사람이기 때문에 실수로 둘 중 하나만 입력하여 양방향 관계가 깨질 수 도 있습니다.
따라서 연관관계 편의 메서드라는 것을 이용해서 양방향 관계에서 두 코드가 하나인 것처럼 사용하는 것이 안전합니다.

예를들어서 Member 클래스에는 다음과 같이 사용할 수 있겠습니다.

setTeam(Team team) {
    this.team = team;
    team.getMembers().add(this);
}

이렇게 하나의 메서드로 양방향 관계를 모두 설정하도록 하였습니다.
이처럼 한 번에 양방향 관계를 설정하는 메서드를 연관관계 편의 메서드라고 합니다.

연관관계 편의 메서드 작성 시 주의사항
연관관계 편의 메서드를 작성할 때도 주의사항이 있습니다.

member1.setTeam(teamA); // 1 
member1.setTeam(teamB); // 2 
Member findMember = teamA.getMember().get(0);

무슨 문제가 있을까요?
member1은 teamA에서 teamB로 팀을 변경했습니다..
teamB에서 member1이 조회될 것입니다.

여기까진 정상입니다.
그런데 ,,
teamA에도 member1이 조회됩니다..;;
원래는 되면 안됩니다.

그림으로 하면 다음과 같이 될 것 같습니다.

먼저 setTeam(teamA); 메서드 호출에 대한 그림이 나올 것입니다.

이후 setTeam(teamB); 호출 시 그림입니다.

이러한 문제로 인해서 기존 팀과 회원의 연관관계를 삭제하는 코드도 다음 예와 같이 추가해주어야 합니다.

void setTeam(Team team) {
    // 기존 팀과 관계를 제거
    if(this.team != null) {
        this.team.getMembers().remove(this);
    }
    this.team = team;
    team.getMembers().add(this);
}

이처럼 객체에서 양방향 연관관계를 사용하려면 로직을 견고하게 해주어야 합니다!

참고 + 주의사항

영한님께서 말씀해주시는 참고 부분입니다. 알아두면 좋을 거 같아서 끄적입니다..

teamA -> memberl 관계가 제거되지 않아도 데이터베이스 외래 키를 변경하는 데는 문제가 없다. 
왜냐하면 teamA -> memberl 관계를 설정한 Team.members는 연관관계의 주인이 아니기 때문이다. 
연관관계의 주인인 Member.team의 참조를 memberl -> teamB로 변경했으므로 데이터베이스에 외래 키는 teamB를 참조하도록 정상 반영 된다. 
그리고 이후에 새로운 영속성 컨텍스트에서 teamA를 조회해서 teamA.getMembers()를 호출하면 데이터베이스 외래 키에는 관계가 끊어져 있으므로 아무것도 조회되지 않는다. 
여기까지만 보면 특별한 문제가 없는 것 같다. 

문제는 관계를 변경하고 영속성 컨텍스트가 아직 살아있는 상태에서 teamA의 getMembers()를 호출하면 memberl이 반환된다는 점이다. 따라서 변경된 연관관계는 앞서 설명한 것처럼 관계를 제거하는 것이 안전하다.

연관관계의 주인을 정하는 기준

단뱡향은 항상 외래 키가 있는 곳을 기준으로 매핑하면 됩니다.
비즈니스 로직상 더 중요하다고 하여 연관관계의 주인으로 선택하면 안 됩니다.
비즈니스 중요도를 배제하고, 단순히 외래 키 관리자 정도의 의미만 부여해야 합니다.

자동차와 바퀴를 생각하면, 바퀴가 외래키가 있는 다(N) 쪽입니다.
따라서 자동차 바퀴가 연관관계의 주인이 됩니다.
차체가 더 중요한 것 같아 보이지만, 연관관계의 주인은 단순히 외래 키를 매핑한 바퀴를 선택하면 됩니다.

연관관계의 주인은 외래 키의 위치와 관련하여 정해야하며, 비즈니스 중요도로 접근하면 안 됩니다.

3. 요약

정리하자면,

  • 연관관계가 하나인 단방향 매핑은 언제나 연관관계의 주인이라는 점입니다.
  • 양방향은 여기(=단방향 매핑)에 주인이 아닌 연관관계를 하나 추가했을 뿐입니다.
  • 양방향의 장점은 반대방향으로 객체 그래프 탐색 기능이 추가된 것뿐입니다.
  • 주인의 반대편은 mappedBy로 주인을 지정해야 합니다.
  • 양방향 연관관계를 매핑하려면 객체에서 양쪽 방향을 모두 관리해야 합니다.
  • 처음은 우선 단방향 매핑을 설정하고 반대방향으로 객체 그래프 탐색 기능(JPQL 쿼리 탐색 포함)이 필요할 때 양방향을 사용하도록 코드를 추가해도 됩니다.

다음은 다양한 연관관계 매핑으로 찾아뵙겠습니다.

이번 년도 안에 QueryDSL까지 한 번 정리 쫘악 해보겠습니다.
-끝-

728x90
Comments