JPA 기초 - 엔티티 1 - N 단방향 연관관계

2024. 1. 22. 18:04·JPA
본 내용은 유트브 최범균님의 강의 내용을 정리한 내용입니다.
JPA 기초 16 엔티티 간 1-N 단방향 연관 매핑

1 - N 단방향 연관 매핑

  • Set
  • List
  • Map

1. 1-N 단방향 Set 연관 매핑 설정

  • @OneToMany 어노테이션은 엔티티 간의 일대다 관계를 매핑할 때 사용합니다.
  • 밑의 예제는 Role 엔티티와 Permission 엔티티 간의 일대다 매핑을 하는 예제 코드입니다.
package com.example.jpa.entity;

...

@Data
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = "role")
public class Role {
    @Id
    private String id;
    private String name;

    @OneToMany // 1:N 연관 관계 명시
    @JoinColumn(name = "role_id") // 조인 시 참조할 컬럼 지정
    private Set<Permission> permissions = new HashSet<>();
    
    public void addPerm(Permission perm) { // 추가
        permissions.add(perm);
    }
    public void removePerm(Permission perm) { // 삭제
        permissions.remove(perm);
    }
    public void removeAllPerm() { // 모두 삭제
        permissions.clear();
    }
}

 

Set 컬렉션 저장

// Step 1: Permission 엔티티 저장
Permission perm1 = new Permission("P1", "G1");
Permission perm2 = new Permission("P2", "G2");
entityManager.persist(perm1);
entityManager.persist(perm2);

// Step 2: Role 엔티티 생성 및 저장
Set<Permission> permissions = new HashSet<>();
permissions.add(perm1);
permissions.add(perm2);
Role role = new Role("R1", "ROLE1", permissions);
entityManager.persist(role);
  • JPA 생성 쿼리
// Permission 엔티티 저장
Hibernate: 
    insert into role_perm (perm, id) values (?, ?)
Hibernate: 
    insert into role_perm (perm, id) values (?, ?)

// Role 엔티티 저장
Hibernate: 
    insert into role (name, id) values (?, ?)
Hibernate: 
    update role_perm set role_id=? where id=?
Hibernate: 
    update role_perm set role_id=? where id=?

 

  • Role 엔티티 저장 시 permissions에 담긴 엔티티의 role_id를 업데이트 합니다.

Set 컬렉션 추가, 삭제

Permission foundPerm1 = entityManager.find(Permission.class, "P1");
Permission foundPerm3 = entityManager.find(Permission.class, "P3");
Role foundRole = entityManager.find(Role.class, "R1");
foundRole.removePerm(foundPerm1); // Set 컬렉션에서 삭제
foundRole.addPerm(foundPerm3); // Set 컬렉션에 추가

 

// Set 컬렉션 clear()
Role foundRole = entityManager.find(Role.class, "R1");
foundRole.removeAllPerm();
  • JPA 생성 쿼리
Hibernate: 
    select
        p1_0.role_id,
        p1_0.id,
        p1_0.perm 
    from role_perm p1_0 
    where p1_0.role_id=?
Hibernate: 
    update role_perm set role_id=null where role_id=? and id=?
Hibernate: 
    update role_perm set role_id=? where id=?
  • Set 컬렉션의 엔티티를 삭제하는 경우 참조 컬럼(role_id)을 null로 업데이트 합니다.
  • Set 컬렉션에 엔티티를 추가하는 경우 참조 컬럼(role_id)를 Role 엔티티의 id값으로 업데이트 합니다.
Hibernate: 
    select
        p1_0.role_id,
        p1_0.id,
        p1_0.perm 
    from role_perm p1_0 
    where p1_0.role_id=?
Hibernate: 
    update role_perm set role_id=null where role_id=?
  • Set 컬렉션에 clear 메서드를 사용하면 현재 Role 엔티티와 연관된 모든 Permission 엔티티의 참조 컬럼(role_id)을 null로 업데이트 합니다.

2. 1-N 단방향 List 연관 매핑 설정

  • List 컬렉션 필드와 연관 매핑하는 경우에는 @OrderColumn 어노테이션을 사용하여 INDEX 값을 저장할 컬럼을 명시해야 합니다.
package com.example.jpa.entity;

...

@Data
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = "question")
public class Question {
    @Id
    private String id;
    private String text;

    @OneToMany
    @JoinColumn(name = "question_id")
    @OrderColumn(name = "idx") // 인덱스 값 컬럼 지정
    private List<Choice> choices;
    
    public void removeChoice(Choice choice) { // 삭제
        choices.remove(choice);
    }
    public void addChoice(Choice choice) { // 추가
        choices.add(choice);
    }
}

 

List 컬렉션 저장

// Choice 엔티티 저장
Choice c1 = new Choice("C1", "TEXT1");
Choice c2 = new Choice("C2", "TEXT2");
Choice c3 = new Choice("C3", "TEXT3");
entityManager.persist(c1);
entityManager.persist(c2);
entityManager.persist(c3);

// Question 엔티티 저장
List<Choice> choices = new ArrayList<>();
choices.add(c1);
choices.add(c2);
choices.add(c3);
entityManager.persist(new Question("Q1", "질문", choices));
  • JPA 생성 쿼리
Hibernate: 
    insert into question (text, id) values (?, ?)
Hibernate: 
    update question_choice set question_id=?, idx=? where id=?
Hibernate: 
    update question_choice set question_id=?, idx=? where id=?
Hibernate: 
    update question_choice set question_id=?, idx=? where id=?
  • Question 엔티티를 저장한 후 연관된 Choice 엔티티의 참조 컬럼(question_id)를 모두 업데이트 해줍니다.

List 컬렉션에 엔티티 추가, 삭제

Choice foundChoice1 = entityManager.find(Choice.class, "C1");
Choice foundChoice4 = entityManager.find(Choice.class, "C4");
Question foundQuestion = entityManager.find(Question.class, "Q1");
foundQuestion.removeChoice(foundChoice1); // Choice 엔티티 삭제
foundQuestion.addChoice(foundChoice4); // Choice 엔티티 추가
  • List 컬렉션에 엔티티 추가, 삭제의 경우 Set 컬렉션과 유사하게 참조 컬럼(question_id)을 업데이트 합니다.
  • 그리고 INDEX 값을 저장하는 컬럼(idx)도 업데이트 합니다.

QUESTION_CHOICE 테이블 결과

 

3. 1-N 단방향 Map 연관 매핑 설정

  • Map 컬렉션 필드와 연관 매핑하는 경우에는 @MapKeyColumn 어노테이션을 사용하여 Map의 Key 값이 될 컬럼을 명시해줍니다.
package com.example.jpa.entity;

...

@Data
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = "doc")
public class Document {
    @Id
    private String id;
    private String title;
    private String content;

    @OneToMany
    @JoinColumn(name = "doc_id")
    @MapKeyColumn(name = "doc_title") // Map의 키가 될 컬럼 지정
    private Map<String, PropValue> props = new HashMap<>();
}

 

Map 컬렉션 저장

// PropValue 엔티티 저장
PropValue prop1 = new PropValue("P1", "Value1");
PropValue prop2 = new PropValue("P2", "Value2");
PropValue prop3 = new PropValue("P3", "Value3");
entityManager.persist(prop1);
entityManager.persist(prop2);
entityManager.persist(prop3);

// Document 엔티티 저장
Map<String, PropValue> props = new HashMap<>();
props.put("Key1", prop1);
props.put("Key2", prop2);
props.put("Key3", prop3);
Document document = new Document("D1", "제목1", "내용1", props);
entityManager.persist(document);
  • JPA 생성 쿼리
Hibernate: 
    insert into doc (content, title, id) values (?, ?, ?)
Hibernate: 
    update doc_prop set doc_id=?, doc_title=? where id=?
Hibernate: 
    update doc_prop set doc_id=?, doc_title=? where id=?
Hibernate: 
    update doc_prop set doc_id=?, doc_title=? where id=?
  • Document 엔티티 저장 후 연관 된 PropValue 엔티티의 참조 컬럼(doc_id)와 Map의 Key 컬럼(doc_title)을 업데이트 합니다.

Map 컬렉션에 추가, 삭제

Document foundDoc = entityManager.find(Document.class, "D1");
PropValue foundProp4 = entityManager.find(PropValue.class, "P4");
PropValue foundProp5 = entityManager.find(PropValue.class, "P5");
foundDoc.addProp("Key1", foundProp4); // Key1 매핑 값을 prop1 -> foundProp4로 변경
foundDoc.addProp("Key5", foundProp5); // 키 값 Key5 추가
foundDoc.removeProp("Key2"); // 키 값 Key2 삭제
  • JPA 생성 쿼리
// Key1과 Key2 와 매핑된 데이터 null로 변경
Hibernate: 
    update doc_prop set doc_id=null, doc_title=null where doc_id=? and id=?
Hibernate: 
    update doc_prop set doc_id=null, doc_title=null where doc_id=? and id=?

// Key1과 Key5 업데이트
Hibernate: 
    update doc_prop set doc_id=?, doc_title=? where id=?
Hibernate: 
    update doc_prop set doc_id=?, doc_title=? where id=?
  • Map 컬렉션의 키(Key2)에 매핑된 값(prop1)을 변경하는 경우 이전에 매핑된 엔티티의 참조 컬럼과 키 컬럼의 값을 null로 변경합니다.
  • 그리고 새로 추가한 값(foundProp4)의 참조 컬럼과 키 컬럼의 값을 업데이트 합니다.
  • Map 컬렉션에 새로운 키(Key5)와 값(foundProp5)을 추가한 경우에는 해당 엔티티의 참조 컬럼과 키 컬럼 값을 업데이트 합니다.
  • Map 컬렉션에 엔티티를 삭제하는 경우 해당 엔티티의 참조 컬럼과 키 컬럼 값을 null로 업데이트 합니다.

DOC_PROP 테이블 결과

'JPA' 카테고리의 다른 글

MemberService 테스트 중 LazyInitializationException  (0) 2024.01.26
Spring JPA - 회원 엔티티, 서비스, 레포지토리 구현  (1) 2024.01.23
JPA 기초 1 - 1 단방향 연관 관계  (0) 2024.01.19
JPA 기초 - 값 컬렉션 Map 매핑  (0) 2024.01.18
JPA 기초 - 값 컬렉션 List 매핑  (0) 2024.01.18
'JPA' 카테고리의 다른 글
  • MemberService 테스트 중 LazyInitializationException
  • Spring JPA - 회원 엔티티, 서비스, 레포지토리 구현
  • JPA 기초 1 - 1 단방향 연관 관계
  • JPA 기초 - 값 컬렉션 Map 매핑
PortLee
PortLee
  • PortLee
    프로그래밍 공부
    PortLee
  • 전체
    오늘
    어제
    • 분류 전체보기
      • C++
      • JAVA
      • JPA
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    persistence.xml
    MemberRepository
    @Embeddable
    JoinColumn
    @Table
    @Basic
    @AttributeOverride
    MemberService
    @CollectionTable
    SQL Mapping
    Translent
    Table 기본키 생성 전략
    Entity 연관관계
    다른 테이블 매핑
    list
    Entity
    MemberEntity
    @Access
    entity mapping
    map
    컬렉션 매핑
    식별자공유
    1-1연관관계
    allocationSize
    JPA
    set
    필드와 컬럼 매핑
    기본키 매핑
    1-N
    컬랙션 매핑
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.0
PortLee
JPA 기초 - 엔티티 1 - N 단방향 연관관계
상단으로

티스토리툴바